|
|
Hi,
Here's a generic raymarcher in POV-Ray. It consists of a camera looking at a
plane, and a pattern applied to said plane. Only diffuse shading has been
implemented (no shadows, reflections, etc.) The pattern loops through x and y
gradients, and uses various inputs which define the scene.
I would have liked to do this using pure functions (and not pigment_map loops)
but... solutions based on nothing but functions are hard to figure out :P
Sam
/*
BasicRaymarching.pov
2023 Sam Benge
Warning! It takes a long time to parse. For faster parsing, lower the values for
Res and NSteps.
*/
#version 3.7;
global_settings{assumed_gamma 2.2}
#default{ finish{emission 1} }
camera{
orthographic
right x up y
location -z
look_at 0
}
// a displacement pattern for the plane
#declare FPattern = function{pattern{crackle}}
// Distance Estimate for sphere and plane (This is the scene's geometry.
DE=signed distance function)
#declare DE =
function{
min(
// sphere
sqrt(x*x+y*y+z*z)-2,
// plane
y+1.9
// displacement for plane
- .4*FPattern(x, y, z)
)
}
//~~~ Raymarching Variables ~~~//
// x & y resolution (later versions of POV-Ray [or maybe just UberPOV] allow
for more than 256 pigment_map entries)
#declare Res = <256, 256>;
// number of raymarching steps
#declare NSteps = 64;
// camera position
#declare RayBeg = <0, 0, -10>;
// light position
#declare LPos = vnormalize(<1, .5, -.3>);
// raymarching bailout threshold
#declare Threshold = 0.001;
// normal accuracy
#declare NAcc = .001;
//~~~ Rendering ~~~//
// we are just looking at a plane
plane{
z, 0
// image is mapped using two gradients: x & y
pigment{
// image uv y gradient
function{min(1, max(0, y))}
pigment_map{
#for(Y, 0, Res.y-1)
[1/Res.y*Y
// image uv x gradient
function{min(1, max(0, x))}
pigment_map{
#for(X, 0, Res.x-1)
[1/Res.x*X
// initialize Ray
#local Ray = RayBeg;
// ray direction
#local RayDir = vnormalize(<X/Res.x-.5, Y/Res.y-.5, 1>);
// did the ray hit something?
// -1 = no, it did not
// >=0 = yeah, it hit something
#local FDist = -1;
// march the ray through DE
#for(I, 0, NSteps-1)
// functions require all axes to be reduced to single values
#local RX = Ray.x;
#local RY = Ray.y;
#local RZ = Ray.z;
// value for DE at Ray position
#local Dist = DE(RX, RY, RZ);
// if DE at Ray position is below threshold
#if(Dist<Threshold)
// the ray hit something, so we give FDist a value
#local FDist = Dist;
// and then we get surface normal
#local Norm =
vnormalize(
<
DE(RX-NAcc, RY, RZ)-DE(RX+NAcc, RY, RZ),
DE(RX, RY-NAcc, RZ)-DE(RX, RY+NAcc, RZ),
DE(RX, RY, RZ-NAcc)-DE(RX, RY, RZ+NAcc)
>
);
#break
#end
// advance the ray
#local Ray = Ray + Dist * RayDir;
#end
// return color/value based on whether or not the ray hit something
#if(FDist>=0)
// diffuse shading
rgb .875 * max(0, pow(vdot(Norm, -LPos), .75))
#else
// background
rgb .5
#end
]
#end
}
]
#end
}
// center pattern on screen
translate -.5*(x+y-1/Res)
}
}
Post a reply to this message
Attachments:
Download 'basicraymarching.jpg' (68 KB)
Preview of image 'basicraymarching.jpg'
|
|