lygia
/lighting
/raymarch
/glass
)Raymarching for glass render. For more info, see the video link: Tutorial 1: https://youtu.be/NCpaaLkmXI8 Tutorial 2: https://youtu.be/0RWaR7zApEo
Dependencies:
Use:
<vec3> raymarchGlass( in <vec3> ray, in <vec3> pos, in <float> ior, in <float> roughness )
#ifndef RAYMARCH_GLASS_DENSITY
#define RAYMARCH_GLASS_DENSITY 0.
#endif
#ifndef RAYMARCH_GLASS_COLOR
#define RAYMARCH_GLASS_COLOR vec3(1.,1.,1.)
#endif
#if !defined(RAYMARCH_GLASS_REFLECTION_EFFECT) && defined(RAYMARCH_GLASS_ENABLE_REFLECTION)
#define RAYMARCH_GLASS_REFLECTION_EFFECT 5.
#endif
#ifdef RAYMARCH_GLASS_MAP_FNC
#define RAYMARCH_GLASS_WAVELENGTH_MAP_FNC(res, rdIn, rdOut, pEnter, pExit, nEnter, nExit, ior, roughness) RAYMARCH_GLASS_MAP_FNC(res, rdIn, rdOut, pEnter, pExit, nEnter, nExit, ior, roughness)
#endif
#ifndef RAYMARCH_GLASS_FNC
#define RAYMARCH_GLASS_FNC(RAY, POSITION, IOR, ROUGHNESS) raymarchDefaultGlass(RAY, POSITION, IOR, ROUGHNESS)
#endif
#ifndef RAYMARCH_GLASS_CHROMATIC_ABBERATION
#define RAYMARCH_GLASS_CHROMATIC_ABBERATION .01
#endif
#ifndef RAYMARCH_GLASS_SAMPLES
#define RAYMARCH_GLASS_SAMPLES 50
#endif
#ifndef RAYMARCH_GLASS_MIN_DIST
#define RAYMARCH_GLASS_MIN_DIST 0.
#endif
#ifndef RAYMARCH_GLASS_MAX_DIST
#define RAYMARCH_GLASS_MAX_DIST 100.
#endif
#ifndef RAYMARCH_GLASS_MIN_HIT_DIST
#define RAYMARCH_GLASS_MIN_HIT_DIST .0001
#endif
#ifndef RAYMARCH_MAP_DISTANCE
#define RAYMARCH_MAP_DISTANCE a
#endif
#ifndef RAYMARCH_MAP_FNC
#define RAYMARCH_MAP_FNC(POS) raymarchMap(POS)
#endif
#ifndef RAYMARCH_MAP_TYPE
#define RAYMARCH_MAP_TYPE vec4
#endif
#ifndef RAYMARCH_MAP_MATERIAL_TYPE
#define RAYMARCH_MAP_MATERIAL_TYPE vec3
#endif
#ifndef RAYMARCH_GLASS_MAP_MATERIAL
#define RAYMARCH_GLASS_MAP_MATERIAL rgb
#endif
#ifndef FNC_RAYMARCH_GLASS
#define FNC_RAYMARCH_GLASS
RAYMARCH_MAP_TYPE raymarchGlassMarching(in vec3 ro, in vec3 rd) {
float tmin = RAYMARCH_GLASS_MIN_DIST;
float tmax = RAYMARCH_GLASS_MAX_DIST;
float t = tmin;
RAYMARCH_MAP_MATERIAL_TYPE m;
// Because when the ray is inside the surface,the distance becomes negative.
float side = sign(RAYMARCH_MAP_FNC(ro).RAYMARCH_MAP_DISTANCE);
for (int i = 0; i < RAYMARCH_GLASS_SAMPLES; i++) {
vec3 pos = ro + rd * t;
RAYMARCH_MAP_TYPE sideDirection = RAYMARCH_MAP_FNC(pos);
t += sideDirection.RAYMARCH_MAP_DISTANCE * side;
m = sideDirection.RAYMARCH_GLASS_MAP_MATERIAL;
if(t > tmax || abs(t) < RAYMARCH_GLASS_MIN_HIT_DIST)
break;
}
return RAYMARCH_MAP_TYPE(m, t);
}
#endif
#ifndef FNC_RAYMARCH_DEFAULT_GLASS
#define FNC_RAYMARCH_DEFAULT_GLASS
// For overwriting the parameters rendering that can be set manually
#ifdef RAYMARCH_GLASS_FNC_MANUAL
vec3 raymarchDefaultGlass(in vec3 ray, in vec3 pos, in float ior, in float roughness, in float glassSharpness, in float chromatic, in float density, in bool enableReflection, in float reflection, in vec3 colorGlass) {
vec3 color = vec3(0.);
RAYMARCH_MAP_TYPE marchOutside = raymarchGlassMarching(pos,ray); // Outside of the object
if(marchOutside.RAYMARCH_MAP_DISTANCE < RAYMARCH_MAX_DIST) {
vec3 newPos = pos + ray * marchOutside.RAYMARCH_MAP_DISTANCE;
vec3 nEnter, nExit;
nEnter = raymarchNormal(newPos, glassSharpness);
vec3 newReflect = reflect(ray, nEnter);
color = envMap(newReflect, roughness).rgb;
vec3 rdIn = refract(ray, nEnter, 1./ior);
vec3 pEnter = newPos - nEnter * RAYMARCH_GLASS_MIN_HIT_DIST * 3.;
RAYMARCH_MAP_TYPE marchInside = raymarchGlassMarching(pEnter, rdIn); // Inside the object
vec3 pExit = pEnter + rdIn * marchInside.RAYMARCH_MAP_DISTANCE;
nExit = -raymarchNormal(pExit, glassSharpness);
vec3 rdOut, res;
if(chromatic != 0.) {
#ifdef RAYMARCH_GLASS_WAVELENGTH_MAP_FNC
RAYMARCH_GLASS_WAVELENGTH_MAP_FNC(res, rdIn, rdOut, pEnter, pExit, nEnter, nExit, ior, roughness);
#else
// Red
rdOut = refract(rdIn, nExit, ior - chromatic);
if(dot(rdOut, rdOut) == 0.)
rdOut = reflect(rdIn, nExit);
res.r = envMap(rdOut, roughness).r;
// Green
rdOut = refract(rdIn, nExit, ior);
if(dot(rdOut, rdOut) == 0.)
rdOut = reflect(rdIn, nExit);
res.g = envMap(rdOut, roughness).g;
// Blue
rdOut = refract(rdIn, nExit, ior + chromatic);
if(dot(rdOut, rdOut) == 0.)
rdOut = reflect(rdIn, nExit);
res.b = envMap(rdOut, roughness).b;
#endif
float optDist = exp(-marchInside.RAYMARCH_MAP_DISTANCE * density);
res *= optDist * colorGlass;
if (enableReflection) {
float fresnelVal = pow(1.+dot(ray, nEnter), reflection);
return vec4(mix(res, color, saturate(fresnelVal)), 1.0);
} else {
return vec4(res, 1.0);
}
} else {
rdOut = refract(rdIn, nExit, ior);
if(dot(rdOut, rdOut) == 0.)
rdOut = reflect(rdIn, nExit);
float optDist = exp(-marchInside.RAYMARCH_MAP_DISTANCE * density);
res = envMap(rdOut, roughness).rgb;
res *= optDist * colorGlass;
if (enableReflection) {
float fresnelVal = pow(1.+dot(ray, nEnter), reflection);
return vec4(mix(res, color, saturate(fresnelVal)), 1.0);
} else {
return vec4(res, 1.0);
}
}
} else {
return vec4(envMap(ray, 0.).rgb, 1.0);
}
}
#endif
vec4 raymarchDefaultGlass(in vec3 ray, in vec3 pos, in float ior, in float roughness) {
vec3 color = vec3(0.);
RAYMARCH_MAP_TYPE marchOutside = raymarchGlassMarching(pos,ray); // Outside of the object
if(marchOutside.RAYMARCH_MAP_DISTANCE < RAYMARCH_MAX_DIST) {
vec3 newPos = pos + ray * marchOutside.RAYMARCH_MAP_DISTANCE;
vec3 nEnter, nExit;
#ifdef RAYMARCH_GLASS_EDGE_SHARPNESS
nEnter = raymarchNormal(newPos, RAYMARCH_GLASS_EDGE_SHARPNESS);
#else
nEnter = raymarchNormal(newPos);
#endif
vec3 newReflect = reflect(ray, nEnter);
color = envMap(newReflect, roughness).rgb;
vec3 rdIn = refract(ray, nEnter, 1./ior);
vec3 pEnter = newPos - nEnter * RAYMARCH_GLASS_MIN_HIT_DIST * 3.;
RAYMARCH_MAP_TYPE marchInside = raymarchGlassMarching(pEnter, rdIn); // Inside the object
vec3 pExit = pEnter + rdIn * marchInside.RAYMARCH_MAP_DISTANCE;
#ifdef RAYMARCH_GLASS_EDGE_SHARPNESS
nExit = -raymarchNormal(pExit, RAYMARCH_GLASS_EDGE_SHARPNESS);
#else
nExit = -raymarchNormal(pExit);
#endif
vec3 rdOut, res;
#ifdef RAYMARCH_GLASS_WAVELENGTH
#ifdef RAYMARCH_GLASS_WAVELENGTH_MAP_FNC
RAYMARCH_GLASS_WAVELENGTH_MAP_FNC(res, rdIn, rdOut, pEnter, pExit, nEnter, nExit, ior, roughness);
#else
// Red
rdOut = refract(rdIn, nExit, ior - RAYMARCH_GLASS_CHROMATIC_ABBERATION);
if(dot(rdOut, rdOut) == 0.)
rdOut = reflect(rdIn, nExit);
res.r = envMap(rdOut, roughness).r;
// Green
rdOut = refract(rdIn, nExit, ior);
if(dot(rdOut, rdOut) == 0.)
rdOut = reflect(rdIn, nExit);
res.g = envMap(rdOut, roughness).g;
// Blue
rdOut = refract(rdIn, nExit, ior + RAYMARCH_GLASS_CHROMATIC_ABBERATION);
if(dot(rdOut, rdOut) == 0.)
rdOut = reflect(rdIn, nExit);
res.b = envMap(rdOut, roughness).b;
#endif
float optDist = exp(-marchInside.RAYMARCH_MAP_DISTANCE * RAYMARCH_GLASS_DENSITY);
res *= optDist * RAYMARCH_GLASS_COLOR;
#ifdef RAYMARCH_GLASS_ENABLE_REFLECTION
float fresnelVal = pow(1.+dot(ray, nEnter), RAYMARCH_GLASS_REFLECTION_EFFECT);
return vec4(mix(res, color, saturate(fresnelVal)), 1.);
#else
return vec4(res, 1.0);
#endif
#else
rdOut = refract(rdIn, nExit, ior);
if(dot(rdOut, rdOut) == 0.)
rdOut = reflect(rdIn, nExit);
float optDist = exp(-marchInside.RAYMARCH_MAP_DISTANCE * RAYMARCH_GLASS_DENSITY);
res = envMap(rdOut, roughness).rgb;
res *= optDist * RAYMARCH_GLASS_COLOR;
#ifdef RAYMARCH_GLASS_ENABLE_REFLECTION
float fresnelVal = pow(1.+dot(ray, nEnter), RAYMARCH_GLASS_REFLECTION_EFFECT);
return vec4(mix(res, color, saturate(fresnelVal)), 1.0);
#else
return vec4(res, 1.0);
#endif
#endif
} else {
return vec4(envMap(ray, 0.).rgb, 1.0);
}
}
vec4 raymarchGlass(in vec3 ray, in vec3 pos, in float ior, in float roughness) {
return RAYMARCH_GLASS_FNC(ray, pos, ior, roughness);
}
#endif
Dependencies:
Use:
<float3> raymarchGlass( in <float3> ray, in <float3> pos, in <float> ior, in <float> roughness )
#ifndef RAYMARCH_GLASS_DENSITY
#define RAYMARCH_GLASS_DENSITY 0.
#endif
#ifndef RAYMARCH_GLASS_COLOR
#define RAYMARCH_GLASS_COLOR float3(1.,1.,1.)
#endif
#if !defined(RAYMARCH_GLASS_REFLECTION_EFFECT) && defined(RAYMARCH_GLASS_ENABLE_REFLECTION)
#define RAYMARCH_GLASS_REFLECTION_EFFECT 5.
#endif
#ifdef RAYMARCH_GLASS_MAP_FNC
#define RAYMARCH_GLASS_WAVELENGTH_MAP_FNC(res, rdIn, rdOut, pEnter, pExit, nEnter, nExit, ior, roughness) RAYMARCH_GLASS_MAP_FNC(res, rdIn, rdOut, pEnter, pExit, nEnter, nExit, ior, roughness)
#endif
#ifndef RAYMARCH_GLASS_FNC
#define RAYMARCH_GLASS_FNC(RAY, POSITION, IOR, ROUGHNESS) raymarchDefaultGlass(RAY, POSITION, IOR, ROUGHNESS)
#endif
#ifndef RAYMARCH_GLASS_CHROMATIC_ABBERATION
#define RAYMARCH_GLASS_CHROMATIC_ABBERATION .01
#endif
#ifndef RAYMARCH_GLASS_SAMPLES
#define RAYMARCH_GLASS_SAMPLES 50
#endif
#ifndef RAYMARCH_GLASS_MIN_DIST
#define RAYMARCH_GLASS_MIN_DIST 0.
#endif
#ifndef RAYMARCH_GLASS_MAX_DIST
#define RAYMARCH_GLASS_MAX_DIST 100.
#endif
#ifndef RAYMARCH_GLASS_MIN_HIT_DIST
#define RAYMARCH_GLASS_MIN_HIT_DIST .0001
#endif
#ifndef RAYMARCH_MAP_DISTANCE
#define RAYMARCH_MAP_DISTANCE a
#endif
#ifndef RAYMARCH_MAP_FNC
#define RAYMARCH_MAP_FNC(POS) raymarchMap(POS)
#endif
#ifndef RAYMARCH_MAP_TYPE
#define RAYMARCH_MAP_TYPE float4
#endif
#ifndef RAYMARCH_MAP_MATERIAL_TYPE
#define RAYMARCH_MAP_MATERIAL_TYPE float3
#endif
#ifndef RAYMARCH_GLASS_MAP_MATERIAL
#define RAYMARCH_GLASS_MAP_MATERIAL rgb
#endif
#ifndef FNC_RAYMARCH_GLASS
#define FNC_RAYMARCH_GLASS
RAYMARCH_MAP_TYPE raymarchGlassMarching(in float3 ro, in float3 rd) {
float tmin = RAYMARCH_GLASS_MIN_DIST;
float tmax = RAYMARCH_GLASS_MAX_DIST;
float t = tmin;
RAYMARCH_MAP_MATERIAL_TYPE m;
// Because when the ray is inside the surface,the distance becomes negative.
float side = sign(RAYMARCH_MAP_FNC(ro).RAYMARCH_MAP_DISTANCE);
for (int i = 0; i < RAYMARCH_GLASS_SAMPLES; i++) {
float3 pos = ro + rd * t;
RAYMARCH_MAP_TYPE sideDirection = RAYMARCH_MAP_FNC(pos);
t += sideDirection.RAYMARCH_MAP_DISTANCE * side;
m = sideDirection.RAYMARCH_GLASS_MAP_MATERIAL;
if(t > tmax || abs(t) < RAYMARCH_GLASS_MIN_HIT_DIST)
break;
}
return RAYMARCH_MAP_TYPE(m, t);
}
#endif
#ifndef FNC_RAYMARCH_DEFAULT_GLASS
#define FNC_RAYMARCH_DEFAULT_GLASS
// For overwriting the parameters rendering that can be set manually
#ifdef RAYMARCH_GLASS_FNC_MANUAL
float3 raymarchDefaultGlass(in float3 ray, in float3 pos, in float ior, in float roughness, in float glassSharpness, in float chromatic, in float density, in bool enableReflection, in float reflection, in float3 colorGlass) {
float3 color = float3(0.);
RAYMARCH_MAP_TYPE marchOutside = raymarchGlassMarching(pos,ray); // Outside of the object
if(marchOutside.RAYMARCH_MAP_DISTANCE < RAYMARCH_MAX_DIST) {
float3 newPos = pos + ray * marchOutside.RAYMARCH_MAP_DISTANCE;
float3 nEnter, nExit;
nEnter = raymarchNormal(newPos, glassSharpness);
float3 newReflect = reflect(ray, nEnter);
color = envMap(newReflect, roughness).rgb;
float3 rdIn = refract(ray, nEnter, 1./ior);
float3 pEnter = newPos - nEnter * RAYMARCH_GLASS_MIN_HIT_DIST * 3.;
RAYMARCH_MAP_TYPE marchInside = raymarchGlassMarching(pEnter, rdIn); // Inside the object
float3 pExit = pEnter + rdIn * marchInside.RAYMARCH_MAP_DISTANCE;
nExit = -raymarchNormal(pExit, glassSharpness);
float3 rdOut, res;
if(chromatic != 0.) {
#ifdef RAYMARCH_GLASS_WAVELENGTH_MAP_FNC
RAYMARCH_GLASS_WAVELENGTH_MAP_FNC(res, rdIn, rdOut, pEnter, pExit, nEnter, nExit, ior, roughness);
#else
// Red
rdOut = refract(rdIn, nExit, ior - chromatic);
if(dot(rdOut, rdOut) == 0.)
rdOut = reflect(rdIn, nExit);
res.r = envMap(rdOut, roughness).r;
// Green
rdOut = refract(rdIn, nExit, ior);
if(dot(rdOut, rdOut) == 0.)
rdOut = reflect(rdIn, nExit);
res.g = envMap(rdOut, roughness).g;
// Blue
rdOut = refract(rdIn, nExit, ior + chromatic);
if(dot(rdOut, rdOut) == 0.)
rdOut = reflect(rdIn, nExit);
res.b = envMap(rdOut, roughness).b;
#endif
float optDist = exp(-marchInside.RAYMARCH_MAP_DISTANCE * density);
res *= optDist * colorGlass;
if (enableReflection) {
float fresnelVal = pow(1.+dot(ray, nEnter), reflection);
return lerp(res, color, saturate(fresnelVal));
} else {
return res;
}
} else {
rdOut = refract(rdIn, nExit, ior);
if(dot(rdOut, rdOut) == 0.)
rdOut = reflect(rdIn, nExit);
float optDist = exp(-marchInside.RAYMARCH_MAP_DISTANCE * density);
res = envMap(rdOut, roughness).rgb;
res *= optDist * colorGlass;
if (enableReflection) {
float fresnelVal = pow(1.+dot(ray, nEnter), reflection);
return lerp(res, color, saturate(fresnelVal));
} else {
return res;
}
}
} else {
return envMap(ray, 0.).rgb;
}
}
#endif
float3 raymarchDefaultGlass(in float3 ray, in float3 pos, in float ior, in float roughness) {
float3 color = float3(0.);
RAYMARCH_MAP_TYPE marchOutside = raymarchGlassMarching(pos,ray); // Outside of the object
if(marchOutside.RAYMARCH_MAP_DISTANCE < RAYMARCH_MAX_DIST) {
float3 newPos = pos + ray * marchOutside.RAYMARCH_MAP_DISTANCE;
float3 nEnter, nExit;
#ifdef RAYMARCH_GLASS_EDGE_SHARPNESS
nEnter = raymarchNormal(newPos, RAYMARCH_GLASS_EDGE_SHARPNESS);
#else
nEnter = raymarchNormal(newPos);
#endif
float3 newReflect = reflect(ray, nEnter);
color = envMap(newReflect, roughness).rgb
float3 rdIn = refract(ray, nEnter, 1./ior);
float3 pEnter = newPos - nEnter * RAYMARCH_GLASS_MIN_HIT_DIST * 3.;
RAYMARCH_MAP_TYPE marchInside = raymarchGlassMarching(pEnter, rdIn); // Inside the object
float3 pExit = pEnter + rdIn * marchInside.RAYMARCH_MAP_DISTANCE;
#ifdef RAYMARCH_GLASS_EDGE_SHARPNESS
nExit = -raymarchNormal(pExit, RAYMARCH_GLASS_EDGE_SHARPNESS);
#else
nExit = -raymarchNormal(pExit);
#endif
float3 rdOut, res;
#ifdef RAYMARCH_GLASS_WAVELENGTH
float NoV = dot(ray, nEnter);
#ifdef RAYMARCH_GLASS_WAVELENGTH_MAP_FNC
RAYMARCH_GLASS_WAVELENGTH_MAP_FNC(res, rdIn, rdOut, pEnter, pExit, nEnter, nExit, ior, roughness);
#else
// Red
rdOut = refract(rdIn, nExit, ior - RAYMARCH_GLASS_CHROMATIC_ABBERATION);
if(dot(rdOut, rdOut) == 0.)
rdOut = reflect(rdIn, nExit);
res.r = envMap(rdOut, roughness).r;
// Green
rdOut = refract(rdIn, nExit, ior);
if(dot(rdOut, rdOut) == 0.)
rdOut = reflect(rdIn, nExit);
res.g = envMap(rdOut, roughness).g;
// Blue
rdOut = refract(rdIn, nExit, ior + RAYMARCH_GLASS_CHROMATIC_ABBERATION);
if(dot(rdOut, rdOut) == 0.)
rdOut = reflect(rdIn, nExit);
res.b = envMap(rdOut, roughness).b;
#endif
float optDist = exp(-marchInside.RAYMARCH_MAP_DISTANCE * RAYMARCH_GLASS_DENSITY);
res *= optDist * RAYMARCH_GLASS_COLOR;
#ifdef RAYMARCH_GLASS_ENABLE_REFLECTION
float fresnelVal = pow(1.+dot(ray, nEnter), RAYMARCH_GLASS_REFLECTION_EFFECT);
return lerp(res, color, saturate(fresnelVal));
#else
return res;
#endif
#else
rdOut = refract(rdIn, nExit, ior);
if(dot(rdOut, rdOut) == 0.)
rdOut = reflect(rdIn, nExit);
float optDist = exp(-marchInside.RAYMARCH_MAP_DISTANCE * RAYMARCH_GLASS_DENSITY);
res = envMap(rdOut, roughness).rgb;
res *= optDist * RAYMARCH_GLASS_COLOR;
#ifdef RAYMARCH_GLASS_ENABLE_REFLECTION
float fresnelVal = pow(1.+dot(ray, nEnter), RAYMARCH_GLASS_REFLECTION_EFFECT);
return lerp(res, color, saturate(fresnelVal));
#else
return res;
#endif
#endif
} else {
return envMap(ray, 0.).rgb;
}
}
float3 raymarchGlass(in float3 ray, in float3 pos, in float ior, in float roughness) {
return RAYMARCH_GLASS_FNC(ray, pos, ior, roughness);
}
#endif
LYGIA is dual-licensed under the Prosperity License and the Patron License for sponsors and contributors.
Sponsors and contributors are automatically added to the Patron License and they can ignore the any non-commercial rule of the Prosperity Licensed software (please take a look to the exception).
It's also possible to get a permanent comercial license hook to a single and specific version of LYGIA.
Sign up for the news letter bellow, joing the LYGIA's channel on Discord or follow the Github repository