Tried to recreate in OSL this GLSL ray-marching tutorial from You Tube: https://www.youtube.com/watch?v=Ff0jJyyiVyw
And it works pretty fast for a CPU but require some additional setup by user in order for it to show anything.
3 Likes
float sdCapsule(vector p, vector a, vector b, float r) {
vector ab = b-a;
vector ap = p-a;
float t = dot(ab, ap) / dot(ab, ab);
t = clamp(t, 0., 1.);
vector c = a + t*ab;
return length(p-c) - r;
}
float sdCylinder(vector p, vector a, vector b, float r) {
vector ab = b-a;
vector ap = p-a;
float t = dot(ab, ap) / dot(ab, ab);
//t = clamp(t, 0., 1.);
vector c = a + t*ab;
float x = length(p-c)-r;
float y = (abs(t-.5)-.5)*length(ab);
float e = length(max(vector(x, y, 0.), 0.));
float i = min(max(x, y), 0.);
return e + i;
}
float sdTorus(vector p, vector r) {
float x = length(vector(p[0], p[2], 0.) )-r[0];
return length(vector(x, p[1], 0.))-r[1];
}
float dBox(vector p, vector s) {
return length(max(abs(p)-s, 0.));
}
float GetDist(vector p) {
vector s = vector(.0, .1, .6);
float sphereDist = length(p-s)-1;
float planeDist = p[1];
float cd = sdCapsule(p, vector(3, .5, 6), vector(3, 2.5, 6), .5);
float td = sdTorus(p-vector(0, .5, 6), vector(1.5, .4, 0.));
float bd = dBox(p-vector(-3.5, 1, 6), vector(1, .75, 1));
float cyld = sdCylinder(p, vector(0, .3, 3), vector(3, .3, 5), .3);
float d = min(cd, planeDist);
d = min(d, td);
d = min(d, bd);
d = min(d, cyld);
return d;
}
float RayMarch(vector viewOrigin, vector rd, int MAX_STEPS, int MAX_DIST) {
float dO=0.;
for(int i=0; i<MAX_STEPS; i++) {
vector p = viewOrigin + rd*dO;
float dS = GetDist(p);
dO += dS;
if(dO>MAX_DIST || dS<0.001) break;
}
return dO;
}
vector GetNormal(vector p) {
float d = GetDist(p);
vector e = vector(.001, .0, 0.);
vector n = d - vector(
GetDist(p-vector(e[0], e[1], e[1])),
GetDist(p-vector(e[1], e[0], e[1])),
GetDist(p-vector(e[1], e[1], e[0])));
return normalize(n);
}
float GetLight(vector p, vector LightPos, float SURF_DIST, int MAX_STEPS, int MAX_DIST) {
vector l = normalize(LightPos-p);
vector n = GetNormal(p);
float dif = clamp(dot(n, l), 0., 1.);
float d = RayMarch(p+n*SURF_DIST*2., l, MAX_STEPS, MAX_DIST);
if(d<length(LightPos-p)) dif *= .1;
return dif;
}
shader mainImage(vector viewOrigin = 0, vector viewDirection = 0, vector LightPos = 0, int MAX_STEPS = 100, int MAX_DIST = 100, float SURF_DIST = 0.001, output color fragColor = 0 )
{
vector rd = normalize(viewDirection);
float d = RayMarch(viewOrigin, rd, MAX_STEPS, MAX_DIST);
vector p = viewOrigin + rd * d;
float dif = GetLight(p, LightPos, SURF_DIST, MAX_STEPS, MAX_DIST);
fragColor = color(dif, dif, dif);
}
4 Likes
There version with soft shadows and with controlling view direction by just rotating 3D viewport around:
float sdCapsule(vector p, vector a, vector b, float r) {
vector ab = b-a;
vector ap = p-a;
float t = dot(ab, ap) / dot(ab, ab);
t = clamp(t, 0., 1.);
vector c = a + t*ab;
return length(p-c) - r;
}
float sdCylinder(vector p, vector a, vector b, float r) {
vector ab = b-a;
vector ap = p-a;
float t = dot(ab, ap) / dot(ab, ab);
//t = clamp(t, 0., 1.);
vector c = a + t*ab;
float x = length(p-c)-r;
float y = (abs(t-.5)-.5)*length(ab);
float e = length(max(vector(x, y, 0.), 0.));
float i = min(max(x, y), 0.);
return e + i;
}
float sdTorus(vector p, vector r) {
float x = length(vector(p[0], p[2], 0.) )-r[0];
return length(vector(x, p[1], 0.))-r[1];
}
float dBox(vector p, vector s) {
return length(max(abs(p)-s, 0.));
}
float GetDist(vector p) {
vector s = vector(.0, .1, .6);
float sphereDist = length(p-s)-1;
float planeDist = p[1];
float cd = sdCapsule(p, vector(3, .5, 6), vector(3, 2.5, 6), .5);
float td = sdTorus(p-vector(0, .5, 6), vector(1.5, .4, 0.));
float bd = dBox(p-vector(-3.5, 1, 6), vector(1, .75, 1));
float cyld = sdCylinder(p, vector(0, .3, 3), vector(3, .3, 5), .3);
float d = min(cd, planeDist);
d = min(d, td);
d = min(d, bd);
d = min(d, cyld);
return d;
}
float RayMarch(vector viewOrigin, vector rd, int MAX_STEPS, float MAX_DIST, float SURF_DIST) {
float dO=0.;
for(int i=0; i<MAX_STEPS; i++) {
vector p = viewOrigin + rd*dO;
float dS = GetDist(p);
dO += dS;
if(dO>MAX_DIST || dS<SURF_DIST) break;
}
return dO;
}
shader mainImage(vector viewOrigin = vector(0,5,0), vector LightPos = vector(0,10,0), int MAX_STEPS = 100,
float MAX_DIST = 100, float SURF_DIST = 0.001, float shaddist = 0.001,
float shadhardness = 5.0, float shadintensity = 10.0,
// outputs
output color fragColor = 0, output vector surfPosition = 0, output vector surfNormal = 0)
{
vector rd = -vector(I[1],I[2],I[0]);
float d = RayMarch(viewOrigin, rd, MAX_STEPS, MAX_DIST, SURF_DIST);
vector p = viewOrigin + rd * d;
vector l = normalize(LightPos-p);
float dsurpo = GetDist(p);
// surface normals
vector e = vector(.001, .0, .0);
vector n = dsurpo - vector(
GetDist(p-vector(e[0], e[1], e[1])),
GetDist(p-vector(e[1], e[0], e[1])),
GetDist(p-vector(e[1], e[1], e[0])));
vector snor = normalize(n);
// light
float dif = clamp(dot(snor, l), 0., 1.);
// Softshadow
float k = shadhardness;
float res = 1.0;
float t = shaddist;
for( int i=0; i<50; i++ )
{
float h = GetDist( p + l*t );
res = min( res, k*h/t );
t += clamp( h, 0.02, 0.20 );
if( res<0.005 || t>MAX_DIST ) break;
}
float Softshadow = clamp( res, 0.0, 1.0);
dif *= max(0.0, pow(Softshadow*0.5+0.5, shadintensity));
// outputs
fragColor = color(dif, dif, dif);
surfPosition = p;
surfNormal = snor;
}
1 Like