300 lines
No EOL
9.9 KiB
HLSL
300 lines
No EOL
9.9 KiB
HLSL
#include "../envMap.hlsl"
|
|
|
|
/*
|
|
contributors: The Art Of Code
|
|
description: |
|
|
Raymarching for glass render. For more info, see the video below link:
|
|
Tutorial 1: https://youtu.be/NCpaaLkmXI8
|
|
Tutorial 2: https://youtu.be/0RWaR7zApEo
|
|
use: <float3> raymarchGlass( in <float3> ray, in <float3> pos, in <float> ior, in <float> roughness )
|
|
options:
|
|
- RAYMARCH_GLASS_DENSITY: 0. [Density of the ray going through the glass]
|
|
- RAYMARCH_GLASS_COLOR: float3(1.0, 1.0, 1.0) [Color of the glass]
|
|
- RAYMARCH_GLASS_WAVELENGTH [Define this option to enable chromatic abberation effects]
|
|
- RAYMARCH_GLASS_ENABLE_REFLECTION [Define this option to enable reflection]
|
|
- RAYMARCH_GLASS_REFLECTION_EFFECT 5. [The higher the value, the less reflections area from surface view]
|
|
- RAYMARCH_GLASS_CHROMATIC_ABBERATION .01 [Chromatic Abberation Effects on environment map]
|
|
- RAYMARCH_GLASS_EDGE_SHARPNESS [Optional, to determine the edge sharpness]
|
|
- RAYMARCH_GLASS_FNC_MANUAL [Optional, enable this to set glass params manually without using defines]
|
|
- RAYMARCH_GLASS_FNC(RAY,POSITION,IOR,ROUGHNESS)
|
|
- RAYMARCH_GLASS_MAP_FNC(res, rdIn, rdOut, pEnter, pExit, nEnter, nExit, ior, 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 |