UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

2 lines (1 loc) 7.12 kB
export default "/*\n * Code taken from this demo: https://n8python.github.io/goodGodRays/\n * By: https://github.com/n8python\n *\n * With cleanup and minor changes\n */\n\nvarying vec2 vUv;\n\nuniform sampler2D sceneDepth;\nuniform sampler2D blueNoise;\nuniform vec3 lightPos;\nuniform vec3 cameraPos;\nuniform vec2 resolution;\nuniform mat4 lightCameraProjectionMatrix;\nuniform mat4 lightCameraMatrixWorldInverse;\nuniform mat4 cameraProjectionMatrixInv;\nuniform mat4 cameraMatrixWorld;\nuniform sampler2D shadowMap;\nuniform vec2 noiseResolution;\nuniform float mapSize;\nuniform float lightCameraNear;\nuniform float lightCameraFar;\nuniform float density;\nuniform float maxDensity;\nuniform float distanceAttenuation;\nuniform vec3[6] fNormals;\nuniform float[6] fConstants;\n#include <packing>\n\nvec3 WorldPosFromDepth(float depth, vec2 coord) {\n float z = depth * 2.0 - 1.0;\n vec4 clipSpacePosition = vec4(coord * 2.0 - 1.0, z, 1.0);\n vec4 viewSpacePosition = cameraProjectionMatrixInv * clipSpacePosition;\n // Perspective division\n viewSpacePosition /= viewSpacePosition.w;\n vec4 worldSpacePosition = cameraMatrixWorld * viewSpacePosition;\n return worldSpacePosition.xyz;\n}\n\nfloat linearize_depth(float d,float zNear,float zFar) {\n return zNear * zFar / (zFar + d * (zNear - zFar));\n}\n\n/**\n * Converts angle between light and a world position to a coordinate\n * in a point light cube shadow map\n */\nvec2 cubeToUV( vec3 v, float texelSizeY ) {\n // Number of texels to avoid at the edge of each square\n vec3 absV = abs( v );\n // Intersect unit cube\n float scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n absV *= scaleToCube;\n // Apply scale to avoid seams\n // two texels less per square (one texel will do for NEAREST)\n v *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n // Unwrap\n // space: -1 ... 1 range for each square\n //\n // #X## dim := ( 4 , 2 )\n // # # center := ( 1 , 1 )\n vec2 planar = v.xy;\n float almostATexel = 1.5 * texelSizeY;\n float almostOne = 1.0 - almostATexel;\n if ( absV.z >= almostOne ) {\n if ( v.z > 0.0 )\n planar.x = 4.0 - v.x;\n } else if ( absV.x >= almostOne ) {\n float signX = sign( v.x );\n planar.x = v.z * signX + 2.0 * signX;\n } else if ( absV.y >= almostOne ) {\n float signY = sign( v.y );\n planar.x = v.x + 2.0 * signY + 2.0;\n planar.y = v.z * signY - 2.0;\n }\n // Transform to UV space\n // scale := 0.5 / dim\n // translate := ( center + 0.5 ) / dim\n return vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n}\n\n/**\n * Projects `worldPos` onto the shadow map of a directional light and returns\n * that position in UV space.\n */\nvec3 projectToShadowMap(vec3 worldPos) {\n vec4 lightSpacePos = lightCameraProjectionMatrix * lightCameraMatrixWorldInverse * vec4(worldPos, 1.0);\n lightSpacePos /= lightSpacePos.w;\n lightSpacePos = lightSpacePos * 0.5 + 0.5;\n return lightSpacePos.xyz;\n}\n\nvec2 inShadow(vec3 worldPos) {\n #if defined(IS_POINT_LIGHT)\n float texelSizeY = 1.0 / (mapSize * 2.0);\n vec2 shadowMapUV = cubeToUV(normalize(worldPos - lightPos), texelSizeY);\n #elif defined(IS_DIRECTIONAL_LIGHT)\n vec3 shadowMapUV = projectToShadowMap(worldPos);\n if (shadowMapUV.x < 0.0 || shadowMapUV.x > 1.0 || shadowMapUV.y < 0.0 || shadowMapUV.y > 1.0 || shadowMapUV.z < 0.0 || shadowMapUV.z > 1.0) {\n return vec2(1.0, 0.0);\n }\n #endif\n\n vec4 packedDepth = texture2D(shadowMap, shadowMapUV.xy);\n float depth = unpackRGBAToDepth(packedDepth);\n depth = lightCameraNear + (lightCameraFar - lightCameraNear) * depth;\n #if defined(IS_POINT_LIGHT)\n float lightDist = distance(worldPos, lightPos);\n #elif defined(IS_DIRECTIONAL_LIGHT)\n float lightDist = (lightCameraNear + (lightCameraFar - lightCameraNear) * shadowMapUV.z);\n #endif\n #if defined(IS_POINT_LIGHT)\n float difference = lightDist - depth;\n #elif defined(IS_DIRECTIONAL_LIGHT)\n float difference = lightDist - depth;\n #endif\n return vec2(float(difference > 0.0), lightDist);\n}\n\nfloat sdPlane( vec3 p, vec3 n, float h )\n{\n // n must be normalized\n return dot(p,n) + h;\n}\nvoid main() {\n float depth = texture2D(sceneDepth, vUv).x;\n\n vec3 worldPos = WorldPosFromDepth(depth, vUv);\n // vec2 tempUV = projectToShadowMap(worldPos);\n // if (tempUV.x < 0.0 || tempUV.x > 1.0 || tempUV.y < 0.0 || tempUV.y > 1.0) {\n // gl_FragColor = vec4(0.0);\n // return;\n // }\n // gl_FragColor = vec4(tempUV, 0.0, 1.0);\n // return;\n float inBoxDist = -10000.0;\n for(int i = 0; i < 6; i++) {\n inBoxDist = max(inBoxDist, sdPlane(cameraPos, fNormals[i], fConstants[i]));\n }\n bool inBox = false;\n if (inBoxDist < 0.0) {\n inBox = true;\n }\n vec3 startPos = cameraPos;\n if (inBox) {\n for(int i = 0; i < 6; i++) {\n if (sdPlane(worldPos, fNormals[i], fConstants[i]) > 0.0) {\n vec3 direction = normalize(worldPos - cameraPos);\n float denom = dot(fNormals[i], direction);\n float t = -(dot(cameraPos, fNormals[i]) + fConstants[i]) / denom;\n worldPos = cameraPos + t * direction;\n }\n }\n } else {\n vec3 direction = normalize(worldPos - cameraPos);\n float minT = 10000.0;\n for(int i = 0; i < 6; i++) {\n float denom = dot(fNormals[i], direction);\n float t = -(dot(cameraPos, fNormals[i]) + fConstants[i]) / denom;\n if (t < minT && t > 0.0) {\n minT = t;\n }\n }\n if (minT == 10000.0) {\n gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n return;\n } else {\n startPos = cameraPos + (minT + 0.001) * direction;\n }\n float endInBoxDist = -10000.0;\n for(int i = 0; i < 6; i++) {\n endInBoxDist = max(endInBoxDist, sdPlane(worldPos, fNormals[i], fConstants[i]));\n }\n bool endInBox = false;\n if (endInBoxDist < 0.0) {\n endInBox = true;\n }\n if (!endInBox) {\n float minT = 10000.0;\n for(int i = 0; i < 6; i++) {\n if (sdPlane(worldPos, fNormals[i], fConstants[i]) > 0.0) {\n float denom = dot(fNormals[i], direction);\n float t = -(dot(startPos, fNormals[i]) + fConstants[i]) / denom;\n if (t < minT && t > 0.0) {\n minT = t;\n }\n }\n }\n if (minT < distance(worldPos, startPos)) {\n worldPos = startPos + minT * direction;\n }\n }\n }\n float illum = 0.0;\n\n vec4 blueNoiseSample = texture2D(blueNoise, vUv * (resolution / noiseResolution));\n float samples = round(60.0 + 8.0 * blueNoiseSample.x);\n for (float i = 0.0; i < samples; i++) {\n vec3 samplePos = mix(startPos, worldPos, i / samples);\n vec2 shadowInfo = inShadow(samplePos);\n float shadowAmount = (1.0 - shadowInfo.x);\n illum += shadowAmount * (distance(startPos, worldPos) * density) * pow(1.0 - shadowInfo.y / lightCameraFar, distanceAttenuation);// * exp(-distanceAttenuation * shadowInfo.y);\n }\n illum /= samples;\n gl_FragColor = vec4(vec3(clamp((1.0 - exp(-illum)), 0.0, maxDensity)), depth);\n}\n";