New marcher calculates instead of approximating normals; fix artifacts in old marcher.

master
James T. Martin 2021-05-20 20:25:48 -07:00
parent 528b97bccb
commit ebe3bfdcff
Signed by: james
GPG Key ID: 4B7F3DA9351E577C
2 changed files with 202 additions and 10 deletions

View File

@ -216,15 +216,7 @@ float df_cube_minus_sphere(mat4 trans, float sphere_radius, vec3 pos) {
// we're inside the cube
vec3 sphere_pos = (trans * vec4(0., 0., 0., 1.)).xyz;
float sdsphere = sdf_sphere(sphere_pos, sphere_radius, pos);
if (sdsphere >= MIN_DISTANCE) {
// inside the cube but outside the sphere
return 0.;
}
// we're inside the sphere subtracted from the cube,
// so our distance is the distance to the sphere.
return abs(sdsphere);
return max(sdcube, -sdsphere);
}
float distance_to_objects(out int material, vec3 pos) {
@ -331,7 +323,7 @@ float ray_march(out int mat, vec3 ray_origin, vec3 ray_direction) {
vec3 normal(vec3 pos) {
// Magic number determined by tinkering with it until stuff worked.
vec2 delta = vec2(0.00025, 0.);
vec2 delta = vec2(0.0001, 0.);
int _mat = -1;
float dist = distance_to_objects(_mat, pos);
vec3 dq = (dist - vec3(

200
ray_march 2021-05-20.frag Normal file
View File

@ -0,0 +1,200 @@
// https://www.shadertoy.com/view/7ts3z8
// 4x supersampling antialiasing.
#define SUPERSAMPLE
// The minimum distance between two points before they are considered intersecting.
#define MIN_DISTANCE 0.001
// The maximum distance from the camera objects are visible.
#define MAX_DISTANCE 15.000
// The maximum number of steps we're allowed to take during ray marching.
#define MAX_STEPS 150
// The width of the field of view. (180 degrees / FOV)
// Larger numbers suffer from less distortion at the edges of the image,
// but make the scene appear more zoomed-in.
#define FOV 2.
#define CAMERA_ORIGIN vec3(0., 0., -2.)
// The minimum lighting intensity for objects which would otherwise
// be in total darkness.
#define MIN_LIGHT 0.01
#define INF 1./0.
#define NaN sqrt(-1.)
struct NearPoint {
vec3 point;
vec3 normal;
};
struct NearObject {
NearPoint near;
int material;
};
NearObject nearestNearObject(NearObject a, NearObject b, vec3 pos) {
if (distance(a.near.point, pos) < distance(b.near.point, pos)) {
return a;
}
return b;
}
NearPoint nearPoint(vec3 pPos, vec3 pos) {
vec3 normal = normalize(pos - pPos);
return NearPoint(pPos, normal);
}
NearPoint nearSegment(vec3 pPos, vec3 pVec, vec3 pos) {
float len = length(pVec);
float h = clamp(dot(normalize(pVec), pos - pPos), 0., len);
vec3 point = pPos + h * normalize(pVec);
return NearPoint(point, normalize(pos - point));
}
NearPoint nearPlane(float height, vec3 pos) {
vec3 normal = vec3(0., 1., 0.);
vec3 point = vec3(pos.x, height, pos.z);
return NearPoint(point, normal);
}
NearPoint inflate(float radius, NearPoint near) {
return NearPoint(near.normal * radius + near.point, near.normal);
}
NearPoint nearSphere(vec3 sPos, float sRadius, vec3 pos) {
return inflate(sRadius, nearPoint(sPos, pos));
}
NearPoint nearPill(vec3 pPos, vec3 pVec, float pRadius, vec3 pos) {
return inflate(pRadius, nearSegment(pPos, pVec, pos));
}
NearObject nearestObject(vec3 pos) {
NearObject ground = NearObject(nearPlane(-1., pos), 1);
NearObject sphere1 = NearObject(nearSphere(
5. * vec3(sin(iTime), 0., cos(iTime)),
1., pos
), 2);
NearObject pill1 = NearObject(nearPill(
vec3(-0.7, -0.8, 2.),
vec3(1.3, 0.1, -0.1),
0.1, pos
), 3);
return nearestNearObject(nearestNearObject(ground, sphere1, pos), pill1, pos);
}
vec3 srgb2linear(vec3 srgb) {
// approximation
return vec3(pow(srgb.x, 1./2.2), pow(srgb.y, 1./2.2), pow(srgb.z, 1./2.2));
}
vec3 materialColor(int material) {
if (material == 1) {
return vec3(1.);
}
if (material == 2) {
return srgb2linear(vec3(0., 0.19, 0.56));
}
if (material == 3) {
return srgb2linear(vec3(0.50, 1.00, 0.40));
}
if (material == 4) {
return srgb2linear(vec3(0.83, 0.69, 0.22));
}
// missing material placeholder color
return vec3(1., 0., 1.);
}
struct Ray {
vec3 origin;
vec3 direction;
};
NearObject raymarch(Ray ray) {
vec3 pos = ray.origin;
NearObject nanObject = NearObject(NearPoint(vec3(INF), vec3(NaN)), -1);
NearObject object = nanObject;
for (int i = 0; i < MAX_STEPS && distance(pos, ray.origin) < MAX_DISTANCE; i++) {
object = nearestObject(pos);
float delta = distance(pos, object.near.point);
if (delta < MIN_DISTANCE) {
return object;
}
pos += ray.direction * delta;
}
return nanObject;
}
Ray projectSphere(vec2 uv) {
vec3 direction = vec3(uv, sqrt(1. - uv.x*uv.x - uv.y*uv.y));
return Ray(CAMERA_ORIGIN + direction, direction);
}
float light(vec3 sPos, NearPoint near) {
vec3 sDirection = normalize(sPos - near.point);
float intensity = dot(sDirection, near.normal);
float marchDist = distance(raymarch(Ray(sPos, -sDirection)).near.point, sPos);
if (marchDist < distance(sPos, near.point) - 10. * MIN_DISTANCE) {
// The object is in the shadow.
intensity *= 0.1;
}
if (intensity < MIN_LIGHT && length(near.point) < INF) {
return MIN_LIGHT;
}
return intensity;
}
vec3 rayColor(Ray ray) {
NearObject object = raymarch(ray);
if (object.material == -1) {
return vec3(0.);
}
vec3 color = materialColor(object.material);
float lightIntensity = light(vec3(1.5, 1.5, 6.), object.near);
return color * lightIntensity;
}
vec3 linear2srgb(vec3 linear_rgb) {
// copied from somewhere on the internet
bvec3 cutoff = lessThan(linear_rgb, vec3(0.0031308));
vec3 higher = vec3(1.055)*pow(linear_rgb, vec3(1.0/2.4)) - vec3(0.055);
vec3 lower = linear_rgb * vec3(12.92);
return mix(higher, lower, cutoff);
}
vec3 uvColor(vec2 uv) {
return rayColor(projectSphere(uv));
}
vec3 uvSupersample(vec2 uv) {
vec2 off = vec2(0.5, -0.5) / (FOV * iResolution.x);
return ( uvColor(uv + off.xx)
+ uvColor(uv + off.xy)
+ uvColor(uv + off.yx)
+ uvColor(uv + off.yy)
) / 4.;
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = (fragCoord / iResolution.xy - 0.5) * 2.;
// Cut off the part of the scene which doesn't fit due to the aspect ratio.
if (iResolution.x > iResolution.y) {
uv = vec2(uv.x, uv.y * iResolution.y / iResolution.x);
} else {
uv = vec2(uv.x * iResolution.x / iResolution.y, uv.y);
}
uv /= FOV;
#ifndef SUPERSAMPLE
vec3 color = uvColor(uv);
#else
vec3 color = uvSupersample(uv);
#endif
//vec3 color = raymarch(projectSphere(uv)).near.normal / 2. + 0.5;
fragColor = vec4(linear2srgb(color), 0.);
}