@animech-public/playcanvas
Version:
PlayCanvas WebGL game engine
2 lines (1 loc) • 5.75 kB
JavaScript
import{random as e}from"../../core/math/random.js";import{Vec3 as t}from"../../core/math/vec3.js";import{TEXTUREPROJECTION_OCTAHEDRAL as r,TEXTUREPROJECTION_CUBE as s,FILTER_NEAREST as n}from"../../platform/graphics/constants.js";import{DeviceCache as o}from"../../platform/graphics/device-cache.js";import{GraphicsDevice as a}from"../../platform/graphics/graphics-device.js";import{RenderTarget as i}from"../../platform/graphics/render-target.js";import{drawQuadWithShader as l}from"./quad-render-utils.js";import{Texture as c}from"../../platform/graphics/texture.js";import{ChunkUtils as h}from"../shader-lib/chunk-utils.js";import{shaderChunks as p}from"../shader-lib/chunks/chunks.js";import{getProgramLibrary as m}from"../shader-lib/get-program-library.js";import{createShaderFromCode as u}from"../shader-lib/utils.js";import{BlendState as d}from"../../platform/graphics/blend-state.js";const f=e=>{switch(e){case s:return"Cubemap";case r:return"Octahedral";default:return"Equirect"}},g=(e,t,r)=>{if(e<=0)t[r+0]=0,t[r+1]=0,t[r+2]=0,t[r+3]=0;else if(e>=1)t[r+0]=255,t[r+1]=0,t[r+2]=0,t[r+3]=0;else{let s=1*e%1,n=255*e%1,o=65025*e%1;const a=16581375*e%1;s-=n/255,n-=o/255,o-=a/255,t[r+0]=Math.min(255,Math.floor(256*s)),t[r+1]=Math.min(255,Math.floor(256*n)),t[r+2]=Math.min(255,Math.floor(256*o)),t[r+3]=Math.min(255,Math.floor(256*a))}},M=(e,t,r,s)=>{const n=2*r*Math.PI,o=Math.pow(1-t,1/(s+1)),a=Math.sqrt(1-o*o);e.set(Math.cos(n)*a,Math.sin(n)*a,o).normalize()},v=(e,t,r)=>{const s=2*r*Math.PI,n=Math.sqrt(1-t),o=Math.sqrt(t);e.set(Math.cos(s)*o,Math.sin(s)*o,n).normalize()},w=(e,t,r,s)=>{const n=2*r*Math.PI,o=Math.sqrt((1-t)/(1+(s*s-1)*t)),a=Math.sqrt(1-o*o);e.set(Math.cos(n)*a,Math.sin(n)*a,o).normalize()},S=(e,t)=>{const r=e*t,s=t/(1-e*e+r*r);return s*s*(1/Math.PI)},$={16:{2:26,8:20,32:17,128:16,512:16},32:{2:53,8:40,32:34,128:32,512:32},128:{2:214,8:163,32:139,128:130,512:128},1024:{2:1722,8:1310,32:1114,128:1041,512:1025}},b=(r,s,n)=>{const o=n/r,a=1-Math.log2(s)/11,i=a*a,l=new t,c=new t,h=new t(0,0,1),p=[],m=((e,t)=>{const r=$[e];return r&&r[t]||e})(r,s);for(let t=0;t<m;++t){w(l,t/m,e.radicalInverse(t),i);const r=l.z;if(c.set(l.x,l.y,l.z).mulScalar(2*r).sub(h),c.z>0){const e=S(Math.min(1,r),i)/4+.001,t=.5*Math.log2(o/e);p.push(c.x,c.y,c.z,t)}}for(;p.length<4*r;)p.push(0,0,0,0);return p},x=(e,t,r)=>{const s=(e=>{const t=e.length,r=Math.min(t,512),s=Math.ceil(t/r),n=new Uint8Array(r*s*4);let o=0;for(let r=0;r<t;r+=4)g(.5*e[r+0]+.5,n,o+0),g(.5*e[r+1]+.5,n,o+4),g(.5*e[r+2]+.5,n,o+8),g(e[r+3]/8,n,o+12),o+=16;return{width:r,height:s,data:n}})(r);return new c(e,{name:t,width:s.width,height:s.height,mipmaps:!1,minFilter:n,magFilter:n,levels:[s.data]})};class P{constructor(e=!0){this.map=new Map,this.destroyContent=e}destroy(){this.destroyContent&&this.map.forEach(((e,t)=>{e.destroy()}))}get(e,t){if(!this.map.has(e)){const r=t();return this.map.set(e,r),r}return this.map.get(e)}}const _=new P(!1),j=new o,y=(e,t,r)=>j.get(e,(()=>new P)).get(t,(()=>x(e,t,_.get(t,r)))),C=(r,s,n)=>y(r,`lambert-samples-${s}-${n}`,(()=>((r,s)=>{const n=s/r,o=new t,a=[];for(let t=0;t<r;++t){v(o,t/r,e.radicalInverse(t));const s=o.z/Math.PI,i=.5*Math.log2(n/s);a.push(o.x,o.y,o.z,i)}return a})(s,n))),E=(r,s,n)=>y(r,`phong-samples-${s}-${n}`,(()=>((r,s)=>{const n=new t,o=[];for(let t=0;t<r;++t)M(n,t/r,e.radicalInverse(t),s),o.push(n.x,n.y,n.z,0);return o})(s,n)));function U(e,t,r={}){var s,n,o,c,g;e instanceof a&&(e=arguments[1],t=arguments[2],r={},void 0!==arguments[3]&&(r.specularPower=arguments[3]),void 0!==arguments[4]&&(r.numSamples=arguments[4]));const M=null!=(s=r.seamPixels)?s:0,v=(null!=(n=null==(o=r.rect)?void 0:o.z)?n:t.width)-2*M,w=(null!=(c=null==(g=r.rect)?void 0:g.w)?c:t.height)-2*M;if(v<1||w<1)return!1;const S=r.hasOwnProperty("specularPower")?r.specularPower:1,$=r.hasOwnProperty("face")?r.face:null,x=r.hasOwnProperty("distribution")?r.distribution:1===S?"none":"phong",P={none:"reproject",lambert:"prefilterSamplesUnweighted",phong:"prefilterSamplesUnweighted",ggx:"prefilterSamples"}[x]||"reproject",_=P.startsWith("prefilterSamples"),j=h.decodeFunc(e.encoding),U=h.encodeFunc(t.encoding),z=`sample${f(e.projection)}`,O=`getDirection${f(t.projection)}`,F=r.hasOwnProperty("numSamples")?r.numSamples:1024,I=`${P}_${j}_${U}_${z}_${O}_${F}`,N=e.device;let q=m(N).getCachedShader(I);if(!q){const t=`#define PROCESS_FUNC ${P}\n${_?"#define USE_SAMPLES_TEX\n":""}${e.cubemap?"#define CUBEMAP_SOURCE\n":""}#define DECODE_FUNC ${j}\n#define ENCODE_FUNC ${U}\n#define SOURCE_FUNC ${z}\n#define TARGET_FUNC ${O}\n#define NUM_SAMPLES ${F}\n#define NUM_SAMPLES_SQRT ${Math.round(Math.sqrt(F)).toFixed(1)}\n`;q=u(N,"\nattribute vec2 vertex_position;\n\nuniform vec4 uvMod;\n\nvarying vec2 vUv0;\n\nvoid main(void) {\n\t\tgl_Position = vec4(vertex_position, 0.5, 1.0);\n\t\tvUv0 = getImageEffectUV((vertex_position.xy * 0.5 + 0.5) * uvMod.xy + uvMod.zw);\n}\n",`${t}\n${p.reprojectPS}`,I)}N.setBlendState(d.NOBLEND);N.scope.resolve(e.cubemap?"sourceCube":"sourceTex").setValue(e);const T=N.scope.resolve("params");N.scope.resolve("params2");const V=N.scope.resolve("uvMod");M>0?V.setValue([(v+2*M)/v,(w+2*M)/w,-M/v,-M/w]):V.setValue([1,1,0,0]);const A=[0,e.fixCubemapSeams?1/e.width:0,t.fixCubemapSeams?1/t.width:0];if(_){const t=e.width*e.height*(e.cubemap?6:1),r="ggx"===x?((e,t,r,s)=>y(e,`ggx-samples-${t}-${r}-${s}`,(()=>b(t,r,s))))(N,F,S,t):"lambert"===x?C(N,F,t):E(N,F,S);N.scope.resolve("samplesTex").setValue(r),N.scope.resolve("samplesTexInverseSize").setValue([1/r.width,1/r.height])}for(let e=0;e<(t.cubemap?6:1);e++)if(null===$||e===$){var D;const s=new i({colorBuffer:t,face:e,depth:!1,flipY:N.isWebGPU});A[0]=e,T.setValue(A),l(N,s,q,null==(D=r)?void 0:D.rect),s.destroy()}return!0}export{U as reprojectTexture};