UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

4 lines (2 loc) 9.23 kB
var reprojectPS = '\n\nvarying vUv0: vec2f;\n\n#ifdef CUBEMAP_SOURCE\n var sourceCube: texture_cube<f32>;\n var sourceCubeSampler : sampler;\n#else\n var sourceTex: texture_2d<f32>;\n var sourceTexSampler : sampler;\n#endif\n\n#ifdef USE_SAMPLES_TEX\n // samples\n var samplesTex: texture_2d<f32>;\n var samplesTexSampler : sampler;\n uniform samplesTexInverseSize: vec2f;\n#endif\n\n// params:\n// x - target cubemap face 0..6\n// y - target image total pixels\n// z - source cubemap size\nuniform params: vec3f;\n\nfn targetFace() -> f32 { return uniform.params.x; }\nfn targetTotalPixels() -> f32 { return uniform.params.y; }\nfn sourceTotalPixels() -> f32 { return uniform.params.z; }\n\nconst PI: f32 = 3.141592653589793;\n\nfn saturate(x: f32) -> f32 {\n return clamp(x, 0.0, 1.0);\n}\n\n#include "decodePS"\n#include "encodePS"\n\n//-- supported projections\n\nfn modifySeams(dir: vec3f, scale: f32) -> vec3f {\n let adir = abs(dir);\n let M = max(max(adir.x, adir.y), adir.z);\n return dir / M * vec3f(\n select(scale, 1.0, adir.x == M),\n select(scale, 1.0, adir.y == M),\n select(scale, 1.0, adir.z == M)\n );\n}\n\nfn toSpherical(dir: vec3f) -> vec2f {\n let nonZeroXZ = any(dir.xz != vec2f(0.0, 0.0));\n return vec2f(select(0.0, atan2(dir.x, dir.z), nonZeroXZ), asin(dir.y));\n}\n\nfn fromSpherical(uv: vec2f) -> vec3f {\n return vec3f(cos(uv.y) * sin(uv.x),\n sin(uv.y),\n cos(uv.y) * cos(uv.x));\n}\n\nfn getDirectionEquirect(uv: vec2f) -> vec3f {\n return fromSpherical((vec2f(uv.x, 1.0 - uv.y) * 2.0 - 1.0) * vec2f(PI, PI * 0.5));\n}\n\n// octahedral code, based on https://jcgt.org/published/0003/02/01/\n// "Survey of Efficient Representations for Independent Unit Vectors" by Cigolle, Donow, Evangelakos, Mara, McGuire, Meyer\n\nfn signNotZero(k: f32) -> f32 {\n return select(-1.0, 1.0, k >= 0.0);\n}\n\nfn signNotZeroVec2(v: vec2f) -> vec2f {\n return vec2f(signNotZero(v.x), signNotZero(v.y));\n}\n\n// Returns a unit vector. Argument o is an octahedral vector packed via octEncode, on the [-1, +1] square\nfn octDecode(o: vec2f) -> vec3f {\n var v = vec3f(o.x, 1.0 - abs(o.x) - abs(o.y), o.y);\n if (v.y < 0.0) {\n var temp: vec2f = (1.0 - abs(v.zx)) * signNotZeroVec2(v.xz);\n v = vec3f(temp.x, v.y, temp.y);\n }\n return normalize(v);\n}\n\nfn getDirectionOctahedral(uv: vec2f) -> vec3f {\n return octDecode(vec2f(uv.x, 1.0 - uv.y) * 2.0 - 1.0);\n}\n\n// Assumes that v is a unit vector. The result is an octahedral vector on the [-1, +1] square\nfn octEncode(v: vec3f) -> vec2f {\n let l1norm = abs(v.x) + abs(v.y) + abs(v.z);\n var result = v.xz * (1.0 / l1norm);\n if (v.y < 0.0) {\n result = (1.0 - abs(result.yx)) * signNotZeroVec2(result.xy);\n }\n return result;\n}\n\n/////////////////////////////////////////////////////////////////////\n\n#ifdef CUBEMAP_SOURCE\n fn sampleCubemapDir(dir: vec3f) -> vec4f {\n return textureSample(sourceCube, sourceCubeSampler, modifySeams(dir, 1.0));\n }\n\n fn sampleCubemapSph(sph: vec2f) -> vec4f {\n return sampleCubemapDir(fromSpherical(sph));\n }\n\n fn sampleCubemapDirLod(dir: vec3f, mipLevel: f32) -> vec4f {\n return textureSampleLevel(sourceCube, sourceCubeSampler, modifySeams(dir, 1.0), mipLevel);\n }\n\n fn sampleCubemapSphLod(sph: vec2f, mipLevel: f32) -> vec4f {\n return sampleCubemapDirLod(fromSpherical(sph), mipLevel);\n }\n#else\n\n fn sampleEquirectSph(sph: vec2f) -> vec4f {\n let uv = sph / vec2f(PI * 2.0, PI) + 0.5;\n return textureSample(sourceTex, sourceTexSampler, vec2f(uv.x, 1.0 - uv.y));\n }\n\n fn sampleEquirectDir(dir: vec3f) -> vec4f {\n return sampleEquirectSph(toSpherical(dir));\n }\n\n fn sampleEquirectSphLod(sph: vec2f, mipLevel: f32) -> vec4f {\n let uv = sph / vec2f(PI * 2.0, PI) + 0.5;\n return textureSampleLevel(sourceTex, sourceTexSampler, vec2f(uv.x, 1.0 - uv.y), mipLevel);\n }\n\n fn sampleEquirectDirLod(dir: vec3f, mipLevel: f32) -> vec4f {\n return sampleEquirectSphLod(toSpherical(dir), mipLevel);\n }\n\n fn sampleOctahedralDir(dir: vec3f) -> vec4f {\n let uv = octEncode(dir) * 0.5 + 0.5;\n return textureSample(sourceTex, sourceTexSampler, vec2f(uv.x, 1.0 - uv.y));\n }\n\n fn sampleOctahedralSph(sph: vec2f) -> vec4f {\n return sampleOctahedralDir(fromSpherical(sph));\n }\n\n fn sampleOctahedralDirLod(dir: vec3f, mipLevel: f32) -> vec4f {\n let uv = octEncode(dir) * 0.5 + 0.5;\n return textureSampleLevel(sourceTex, sourceTexSampler, vec2f(uv.x, 1.0 - uv.y), mipLevel);\n }\n\n fn sampleOctahedralSphLod(sph: vec2f, mipLevel: f32) -> vec4f {\n return sampleOctahedralDirLod(fromSpherical(sph), mipLevel);\n }\n\n#endif\n\nfn getDirectionCubemap(uv: vec2f) -> vec3f {\n let st = uv * 2.0 - 1.0;\n let face = targetFace();\n\n var vec: vec3f;\n if (face == 0.0) {\n vec = vec3f(1, -st.y, -st.x);\n } else if (face == 1.0) {\n vec = vec3f(-1, -st.y, st.x);\n } else if (face == 2.0) {\n vec = vec3f(st.x, 1, st.y);\n } else if (face == 3.0) {\n vec = vec3f(st.x, -1, -st.y);\n } else if (face == 4.0) {\n vec = vec3f(st.x, -st.y, 1);\n } else {\n vec = vec3f(-st.x, -st.y, -1);\n }\n\n return normalize(modifySeams(vec, 1.0));\n}\n\nfn matrixFromVector(n: vec3f) -> mat3x3f {\n let a = 1.0 / (1.0 + n.z);\n let b = -n.x * n.y * a;\n let b1 = vec3f(1.0 - n.x * n.x * a, b, -n.x);\n let b2 = vec3f(b, 1.0 - n.y * n.y * a, -n.y);\n return mat3x3f(b1, b2, n);\n}\n\nfn matrixFromVectorSlow(n: vec3f) -> mat3x3f {\n let up = select(vec3f(0.0, 0.0, select(-1.0, 1.0, n.y > 0.0)), vec3f(0.0, 1.0, 0.0), abs(n.y) > 0.0000001);\n let x = normalize(cross(up, n));\n let y = cross(n, x);\n return mat3x3f(x, y, n);\n}\n\nfn reproject(uv: vec2f) -> vec4f {\n if ({NUM_SAMPLES} <= 1) {\n // single sample\n return {ENCODE_FUNC}({DECODE_FUNC}({SOURCE_FUNC}Dir({TARGET_FUNC}(uv))));\n } else {\n // multi sample\n let t = {TARGET_FUNC}(uv);\n let tu = dpdx(t);\n let tv = dpdy(t);\n\n var result = vec3f(0.0);\n for (var u = 0.0; u < {NUM_SAMPLES_SQRT}; u += 1.0) {\n for (var v = 0.0; v < {NUM_SAMPLES_SQRT}; v += 1.0) {\n result += {DECODE_FUNC}({SOURCE_FUNC}Dir(normalize(t +\n tu * (u / {NUM_SAMPLES_SQRT} - 0.5) +\n tv * (v / {NUM_SAMPLES_SQRT} - 0.5))));\n }\n }\n return {ENCODE_FUNC}(result / ({NUM_SAMPLES_SQRT} * {NUM_SAMPLES_SQRT}));\n }\n}\n\nconst unpackFloat: vec4f = vec4f(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0);\n\n#ifdef USE_SAMPLES_TEX\n fn unpackSample(i: i32, L: ptr<function, vec3f>, mipLevel: ptr<function, f32>) {\n var u = (f32(i * 4) + 0.5) * uniform.samplesTexInverseSize.x;\n var v = (floor(u) + 0.5) * uniform.samplesTexInverseSize.y;\n\n var raw: vec4f;\n raw.x = dot(textureSample(samplesTex, samplesTexSampler, vec2f(u, v)), unpackFloat); u += uniform.samplesTexInverseSize.x;\n raw.y = dot(textureSample(samplesTex, samplesTexSampler, vec2f(u, v)), unpackFloat); u += uniform.samplesTexInverseSize.x;\n raw.z = dot(textureSample(samplesTex, samplesTexSampler, vec2f(u, v)), unpackFloat); u += uniform.samplesTexInverseSize.x;\n raw.w = dot(textureSample(samplesTex, samplesTexSampler, vec2f(u, v)), unpackFloat);\n\n *L = raw.xyz * 2.0 - 1.0;\n *mipLevel = raw.w * 8.0;\n }\n\n // convolve an environment given pre-generated samples\n fn prefilterSamples(uv: vec2f) -> vec4f {\n // construct vector space given target direction\n let vecSpace = matrixFromVectorSlow({TARGET_FUNC}(uv));\n\n var L: vec3f;\n var mipLevel: f32;\n\n var result = vec3f(0.0);\n var totalWeight = 0.0;\n for (var i = 0; i < {NUM_SAMPLES}; i += 1) {\n unpackSample(i, &L, &mipLevel);\n result += {DECODE_FUNC}({SOURCE_FUNC}DirLod(vecSpace * L, mipLevel)) * L.z;\n totalWeight += L.z;\n }\n\n return {ENCODE_FUNC}(result / totalWeight);\n }\n\n // unweighted version of prefilterSamples\n fn prefilterSamplesUnweighted(uv: vec2f) -> vec4f {\n // construct vector space given target direction\n let vecSpace = matrixFromVectorSlow({TARGET_FUNC}(uv));\n\n var L: vec3f;\n var mipLevel: f32;\n\n var result = vec3f(0.0);\n for (var i = 0; i < {NUM_SAMPLES}; i += 1) {\n unpackSample(i, &L, &mipLevel);\n result += {DECODE_FUNC}({SOURCE_FUNC}DirLod(vecSpace * L, mipLevel));\n }\n\n return {ENCODE_FUNC}(result / f32({NUM_SAMPLES}));\n }\n#endif\n\n@fragment\nfn fragmentMain(input : FragmentInput) -> FragmentOutput {\n var output: FragmentOutput;\n output.color = {PROCESS_FUNC}(input.vUv0);\n return output;\n}\n'; export { reprojectPS as default };