|
|
"Samuel B." <stb### [at] hotmailcom> wrote:
> a generic raymarcher in POV-Ray.
Here's another version. I added a surface color, fog color, and shadows. It's
very slow. No antialiasing. A lot of artifacts typical of naive ray marching.
This image parsed very slowly but rendered quickly, finishing at a total of 3
minutes and 33 seconds, with a resolution of only 354x354.
(Why did I do this?)
This is far as I'll take it, because the whole exercise if kind of pointless,
other than to show how flexible POV-Ray's SDL can be.
Sam
/*
BasicRaymarchingB.pov
2023 Sam Benge
Warning! It takes a long time to parse... minutes, even. For faster parsing,
lower the values for Res (start with <32, 32> Also, lower or RaySteps and
LightSteps if needed.
*/
#version 3.7;
global_settings{assumed_gamma 2.2}
#default{ finish{emission 1} }
// linear interpolation function
#macro Mix(A, B, C) A*(1-C) + B*C #end
camera{
orthographic
right x up y
location -z
look_at 0
}
// distance estimate for sphere and plane (This is the scene's geometry.
DE=signed distance field/function)
#declare DE =
function{
min(
// sphere
sqrt(x*x+y*y+z*z)-2,
// plane
y+2
)
// displacement
+ .07*(cos(7*x)+cos(7*y)+cos(7*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 = <354, 354>;
// number of camera raymarching steps
#declare RaySteps = 256;
// adjust camera ray step amount (1 is ideal, but some distance estimates
require lower values)
#declare Adj = 0.5;
// number of light steps
#declare LightSteps = 32;
// camera position
#declare RayBeg = <0, 0, -10>;
// light position
#declare LPos = <1, .5, -.3>;
// raymarching bailout threshold
#declare Threshold = 0.001;
// normal accuracy
#declare NAcc = .001;
// object color
#declare ObjCol = <1, .8, .5>;
// fog color
#declare FogCol = <.2, .4, 1>;
// fog distance
#declare FogDist = 20;
//~~~ Rendering ~~~//
// we are only looking at a plane
plane{
z, 0
// image is mapped using x & y gradients
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?
// false = (default) no, it didn't hit anything
// true = yeah, it hit something
#local DidHit = false;
// march the ray through DE
#for(I, 0, RaySteps-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 = Adj*DE(RX, RY, RZ);
// if DE at Ray position is below threshold
#if(Dist<Threshold)
// the ray hit something, so we set DidHit to true
#local DidHit = true;
// escape the loop because we don't need to trace anything anymore
#break
#end
// advance the ray
#local Ray = Ray + Dist * RayDir;
#end
// did the ray hit something?
#if(DidHit) // the ray hit something, so we start shading the objects
// position where the ray hit
#local Hit = Ray;
#local HX = Hit.x;
#local HY = Hit.y;
#local HZ = Hit.z;
// initial color
#local Col = ObjCol;
// get the surface normal from DE() at hit position
#local Norm =
vnormalize(
<
DE(HX+NAcc, HY, HZ)-DE(HX-NAcc, HY, HZ),
DE(HX, HY+NAcc, HZ)-DE(HX, HY-NAcc, HZ),
DE(HX, HY, HZ+NAcc)-DE(HX, HY, HZ-NAcc)
>
);
// diffuse value
#local Diffuse = max(0, pow(vdot(Norm, LPos), .75));
// set initial color
#local Col = ObjCol;
// apply diffuse
#local Col = Col * Diffuse;
// calculate shadows
#if(true)
// light direction
#local LDir = vnormalize(LPos);
// initialize light ray (slightly offset from surface)
#local LRay = Hit + 2 * Threshold * Norm;
// Is the light shining here? default = true
#local IsLit = true;
// march the light ray through DE
// (not designed to stop after passing through light source)
#for(I, 0, LightSteps)
// light ray position is reduced to single values
#local LX = LRay.x;
#local LY = LRay.y;
#local LZ = LRay.z;
// value for DE at light ray position
#local LDist = DE(LX, LY, LZ);
// if light ray hits an object, then no light is shining on this
pixel
#if(LDist<Threshold)
// not lit
#local IsLit = false;
// escape the loop because we don't need to trace anything anymore
#break
#end
// advance the ray
#local LRay = LRay + LDist * LDir;
#end
// apply shadow
#local Col = Col * IsLit;
#end // ~if shadows
// apply fog (calculation provided from POV docs)
#local Col = Mix(FogCol, Col, exp(-vlength(RayBeg-Hit)/FogDist));
// final object color
rgb Col
#else // the ray didn't hit anything, so we use the background color
// background
rgb FogCol
#end
]
#end
}
]
#end
}
// center pattern on screen
translate -.5*(x+y-1/Res)
}
}
Post a reply to this message
Attachments:
Download 'basicraymarchingb3m_33s.jpg' (59 KB)
Preview of image 'basicraymarchingb3m_33s.jpg'
|
|