UNPKG

three

Version:

JavaScript 3D library

85 lines (63 loc) 3.17 kB
export default /* glsl */` #ifdef USE_TRANSMISSION // Transmission code is based on glTF-Sampler-Viewer // https://github.com/KhronosGroup/glTF-Sample-Viewer #ifdef USE_TRANSMISSIONMAP uniform sampler2D transmissionMap; #endif #ifdef USE_THICKNESSMAP uniform sampler2D thicknessMap; #endif uniform vec2 transmissionSamplerSize; uniform sampler2D transmissionSamplerMap; uniform mat4 modelMatrix; uniform mat4 projectionMatrix; varying vec4 vWorldPosition; vec3 getVolumeTransmissionRay(vec3 n, vec3 v, float thickness, float ior, mat4 modelMatrix) { // Direction of refracted light. vec3 refractionVector = refract(-v, normalize(n), 1.0 / ior); // Compute rotation-independant scaling of the model matrix. vec3 modelScale; modelScale.x = length(vec3(modelMatrix[0].xyz)); modelScale.y = length(vec3(modelMatrix[1].xyz)); modelScale.z = length(vec3(modelMatrix[2].xyz)); // The thickness is specified in local space. return normalize(refractionVector) * thickness * modelScale; } float applyIorToRoughness(float roughness, float ior) { // Scale roughness with IOR so that an IOR of 1.0 results in no microfacet refraction and // an IOR of 1.5 results in the default amount of microfacet refraction. return roughness * clamp(ior * 2.0 - 2.0, 0.0, 1.0); } vec3 getTransmissionSample(vec2 fragCoord, float roughness, float ior) { float framebufferLod = log2(transmissionSamplerSize.x) * applyIorToRoughness(roughness, ior); return texture2DLodEXT(transmissionSamplerMap, fragCoord.xy, framebufferLod).rgb; } vec3 applyVolumeAttenuation(vec3 radiance, float transmissionDistance, vec3 attenuationColor, float attenuationDistance) { if (attenuationDistance == 0.0) { // Attenuation distance is +∞ (which we indicate by zero), i.e. the transmitted color is not attenuated at all. return radiance; } else { // Compute light attenuation using Beer's law. vec3 attenuationCoefficient = -log(attenuationColor) / attenuationDistance; vec3 transmittance = exp(-attenuationCoefficient * transmissionDistance); // Beer's law return transmittance * radiance; } } vec3 getIBLVolumeRefraction(vec3 n, vec3 v, float perceptualRoughness, vec3 baseColor, vec3 specularColor, vec3 position, mat4 modelMatrix, mat4 viewMatrix, mat4 projMatrix, float ior, float thickness, vec3 attenuationColor, float attenuationDistance) { vec3 transmissionRay = getVolumeTransmissionRay(n, v, thickness, ior, modelMatrix); vec3 refractedRayExit = position + transmissionRay; // Project refracted vector on the framebuffer, while mapping to normalized device coordinates. vec4 ndcPos = projMatrix * viewMatrix * vec4(refractedRayExit, 1.0); vec2 refractionCoords = ndcPos.xy / ndcPos.w; refractionCoords += 1.0; refractionCoords /= 2.0; // Sample framebuffer to get pixel the refracted ray hits. vec3 transmittedLight = getTransmissionSample(refractionCoords, perceptualRoughness, ior); vec3 attenuatedColor = applyVolumeAttenuation(transmittedLight, length(transmissionRay), attenuationColor, attenuationDistance); return (1.0 - specularColor) * attenuatedColor * baseColor; } #endif `;