UNPKG

@animech-public/playcanvas

Version:
2 lines (1 loc) 7.89 kB
import{Color as e}from"../../core/math/color.js";import{Mat4 as t}from"../../core/math/mat4.js";import{Vec3 as s}from"../../core/math/vec3.js";import{Vec4 as r}from"../../core/math/vec4.js";import{UNIFORMTYPE_MAT4 as a,UNIFORM_BUFFER_DEFAULT_SLOT_NAME as i,SHADERSTAGE_VERTEX as o,SHADERSTAGE_FRAGMENT as h}from"../../platform/graphics/constants.js";import{drawQuadWithShader as n}from"../graphics/quad-render-utils.js";import{SHADOW_VSM8 as d,SHADOW_VSM32 as l,SHADOW_PCF5 as c,SHADOW_PCF1 as p,SHADOW_PCF3 as u,LIGHTTYPE_OMNI as m,LIGHTTYPE_DIRECTIONAL as f,SORTKEY_DEPTH as w,SHADOWUPDATE_NONE as S,SHADOWUPDATE_THISFRAME as g,BLUR_GAUSSIAN as V,SHADER_SHADOW as b}from"../constants.js";import{ShaderPass as v}from"../shader-pass.js";import{shaderChunks as C}from"../shader-lib/chunks/chunks.js";import{createShaderFromCode as y}from"../shader-lib/utils.js";import{LightCamera as _}from"./light-camera.js";import{UniformBufferFormat as B,UniformFormat as P}from"../../platform/graphics/uniform-buffer-format.js";import{BindGroupFormat as O,BindUniformBufferFormat as M}from"../../platform/graphics/bind-group-format.js";import{BlendState as F}from"../../platform/graphics/blend-state.js";function I(e,t){return Math.exp(-e*e/(2*t*t))}const U=new Set,x=new t,D=new t,R=new Float32Array(2),j=new r(1,1,0,0),T=new t;class L{constructor(e,t){this.shadowPassCache=[],this.device=e.device,this.renderer=e,this.lightTextureAtlas=t;const s=this.device.scope;this.polygonOffsetId=s.resolve("polygonOffset"),this.polygonOffset=new Float32Array(2),this.sourceId=s.resolve("source"),this.pixelOffsetId=s.resolve("pixelOffset"),this.weightId=s.resolve("weight[0]"),this.blurVsmShaderCode=[C.blurVSMPS,`#define GAUSS\n${C.blurVSMPS}`];const r="#define PACKED\n";this.blurPackedVsmShaderCode=[r+this.blurVsmShaderCode[0],r+this.blurVsmShaderCode[1]],this.blurVsmShader=[{},{}],this.blurPackedVsmShader=[{},{}],this.blurVsmWeights={},this.shadowMapLightRadiusId=s.resolve("light_radius"),this.viewUniformFormat=null,this.viewBindGroupFormat=null,this.blendStateWrite=new F,this.blendStateNoWrite=new F,this.blendStateNoWrite.setColorWrite(!1,!1,!1,!1)}static createShadowCamera(t,s,r,a){const i=_.create("ShadowCamera",r,a);return i.clearColor=s>=d&&s<=l?new e(0,0,0,0):new e(1,1,1,1),i.clearDepthBuffer=!0,i.clearStencilBuffer=!1,i}static setShadowCameraSettings(e,t,s,r,a){let i=s===c||(s===p||s===u)&&t.supportsDepthShadow;r!==m||a||(i=!1),e.clearColorBuffer=!i}_cullShadowCastersInternal(e,t,s){const r=e.length;for(let a=0;a<r;a++){const r=e[a];r.castShadow&&(r.cull&&!r._isVisible(s)||(r.visibleThisFrame=!0,t.push(r)))}}cullShadowCasters(e,t,s,r,a){if(s.length=0,a)this._cullShadowCastersInternal(a,s,r);else{const a=e.layerList,i=a.length;for(let e=0;e<i;e++){const i=a[e];i._lightsSet.has(t)&&(U.has(i)||(U.add(i),this._cullShadowCastersInternal(i.shadowCasters,s,r)))}U.clear()}s.sort(this.renderer.sortCompareDepth)}setupRenderState(e,t){e.isWebGL1&&e.extStandardDerivatives&&(t._type===m?(this.polygonOffset[0]=0,this.polygonOffset[1]=0,this.polygonOffsetId.setValue(this.polygonOffset)):(this.polygonOffset[0]=-1e3*t.shadowBias,this.polygonOffset[1]=-1e3*t.shadowBias,this.polygonOffsetId.setValue(this.polygonOffset)));const s=this.renderer.scene.clusteredLightingEnabled,r=e.isWebGL2||e.isWebGPU,a=s?t._isPcf&&r:t._isPcf&&r&&t._type!==m;e.setBlendState(a?this.blendStateNoWrite:this.blendStateWrite),e.setDepthState(t.shadowDepthState),e.setStencilState(null,null)}dispatchUniforms(e,t,r,a){const i=t._node;e._type!==f&&(this.renderer.dispatchViewPos(i.getPosition()),this.shadowMapLightRadiusId.setValue(e.attenuationEnd)),x.setTRS(i.getPosition(),i.getRotation(),s.ONE).invert(),D.mul2(t.projectionMatrix,x);const o=r.shadowViewport;t.rect=o,t.scissorRect=r.shadowScissor,T.setViewport(o.x,o.y,o.z,o.w),r.shadowMatrix.mul2(T,D),e._type===f&&e._shadowMatrixPalette.set(r.shadowMatrix.data,16*a)}getShadowPass(e){var t;const s=e._type,r=e._shadowType;let a=null==(t=this.shadowPassCache[s])?void 0:t[r];if(!a){const e=`ShadowPass_${s}_${r}`;a=v.get(this.device).allocate(e,{isShadow:!0,lightType:s,shadowType:r}),this.shadowPassCache[s]||(this.shadowPassCache[s]=[]),this.shadowPassCache[s][r]=a}return a.index}submitCasters(e,t){const s=this.device,r=this.renderer,a=r.scene,i=1<<b,o=this.getShadowPass(t),h=e.length;for(let t=0;t<h;t++){const h=e[t],n=h.mesh;h.ensureMaterial(s);const d=h.material;r.setBaseConstants(s,d),r.setSkinning(s,h),d.dirty&&(d.updateUniforms(s,a),d.dirty=!1),d.chunks&&(r.setupCullMode(!0,1,h),d.setParameters(s),h.setParameters(s,i));const l=h.getShaderInstance(o,0,a,this.viewUniformFormat,this.viewBindGroupFormat),c=l.shader;h._key[w]=c.id,s.setShader(c),r.setVertexBuffers(s,n),r.setMorphing(s,h.morphInstance),this.renderer.setupMeshUniformBuffers(l,h);const p=h.renderStyle;s.setIndexBuffer(n.indexBuffer[p]),r.drawInstance(s,h,n,p),r._shadowDrawCalls++}}needsShadowRendering(e){const t=e.enabled&&e.castShadows&&e.shadowUpdateMode!==S&&e.visibleThisFrame;return e.shadowUpdateMode===g&&(e.shadowUpdateMode=S),t&&(this.renderer._shadowMapUpdates+=e.numShadowFaces),t}getLightRenderData(e,t,s){return e.getRenderData(e._type===f?t:null,s)}setupRenderPass(e,t,s){const r=t.renderTarget;e.init(r),e.depthStencilOps.clearDepthValue=1,e.depthStencilOps.clearDepth=s,r.depthBuffer?e.depthStencilOps.storeDepth=!0:(e.colorOps.clearValue.copy(t.clearColor),e.colorOps.clear=s,e.depthStencilOps.storeDepth=!1),e.requiresCubemaps=!1}prepareFace(e,t,s){const r=e._type,a=e._shadowType,i=this.renderer.scene.clusteredLightingEnabled,o=this.getLightRenderData(e,t,s).shadowCamera;L.setShadowCameraSettings(o,this.device,a,r,i);const h=r===f?0:s;return o.renderTarget=e._shadowMap.renderTargets[h],o}renderFace(e,t,s,r,a=!0){const i=this.device,o=this.getLightRenderData(e,t,s),h=o.shadowCamera;this.dispatchUniforms(e,h,o,s);const n=h.renderTarget,d=this.renderer;d.setCameraUniforms(h,n),i.supportsUniformBuffers&&d.setupViewUniformBuffers(o.viewBindGroups,this.viewUniformFormat,this.viewBindGroupFormat,1),a?(d.setupViewport(h,n),r&&d.clear(h)):d.clearView(h,n,!0,!1),this.setupRenderState(i,e),this.submitCasters(o.visibleCasters,e)}render(e,t,s=!0){if(this.needsShadowRendering(e)){const r=e.numShadowFaces;for(let a=0;a<r;a++)this.prepareFace(e,t,a),this.renderFace(e,t,a,!0,s);this.renderVsm(e,t)}}renderVsm(e,t){if(e._isVsm&&e._vsmBlurSize>1){this.renderer.scene.clusteredLightingEnabled&&e._type!==f||this.applyVsmBlur(e,t)}}getVsmBlurShader(e,t,s){let r=(e?this.blurPackedVsmShader:this.blurVsmShader)[t][s];if(!r){this.blurVsmWeights[s]=function(e){const t=(e-1)/6,s=.5*(e-1),r=new Array(e);let a=0;for(let i=0;i<e;++i)r[i]=I(i-s,t),a+=r[i];for(let t=0;t<e;++t)r[t]/=a;return r}(s);const a=C.fullscreenQuadVS;let i=`#define SAMPLES ${s}\n`;i+=e?this.blurPackedVsmShaderCode[t]:this.blurVsmShaderCode[t];const o=`blurVsm${t}${s}${e}`;r=y(this.device,a,i,o),e?this.blurPackedVsmShader[t][s]=r:this.blurVsmShader[t][s]=r}return r}applyVsmBlur(e,t){const s=this.device;s.setBlendState(F.NOBLEND);const r=e.getRenderData(e._type===f?t:null,0).shadowCamera.renderTarget,a=this.renderer.shadowMapCache.get(s,e),i=a.renderTargets[0],o=e._shadowType===d,h=e.vsmBlurMode,l=e._vsmBlurSize,c=this.getVsmBlurShader(o,h,l);j.z=e._shadowResolution-2,j.w=j.z,this.sourceId.setValue(r.colorBuffer),R[0]=1/e._shadowResolution,R[1]=0,this.pixelOffsetId.setValue(R),h===V&&this.weightId.setValue(this.blurVsmWeights[l]),n(s,i,c,null,j),this.sourceId.setValue(i.colorBuffer),R[1]=R[0],R[0]=0,this.pixelOffsetId.setValue(R),n(s,r,c,null,j),this.renderer.shadowMapCache.add(e,a)}initViewBindGroupFormat(){this.device.supportsUniformBuffers&&!this.viewUniformFormat&&(this.viewUniformFormat=new B(this.device,[new P("matrix_viewProjection",a)]),this.viewBindGroupFormat=new O(this.device,[new M(i,o|h)]))}frameUpdate(){this.initViewBindGroupFormat()}}export{L as ShadowRenderer};