UNPKG

@animech-public/playcanvas

Version:
2 lines (1 loc) 16.4 kB
import{Vec3 as t}from"../../core/math/vec3.js";import{LIGHTSHAPE_PUNCTUAL as e,LIGHTTYPE_OMNI as s,LIGHTTYPE_SPOT as i,LIGHTTYPE_DIRECTIONAL as a,FOG_NONE as o,FOG_LINEAR as h,LAYERID_DEPTH as r}from"../constants.js";import{Renderer as l}from"./renderer.js";import{LightCamera as n}from"./light-camera.js";import{RenderPassForward as d}from"./render-pass-forward.js";import{RenderPassPostprocessing as g}from"./render-pass-postprocessing.js";const c=[[],[],[]],u={drawCalls:[],shaderInstances:[],isNewMaterial:[],lightMaskChanged:[],clear:function(){this.drawCalls.length=0,this.shaderInstances.length=0,this.isNewMaterial.length=0,this.lightMaskChanged.length=0}};class m extends l{constructor(t){super(t);const e=this.device;this._forwardDrawCalls=0,this._materialSwitches=0,this._depthMapTime=0,this._forwardTime=0,this._sortTime=0;const s=e.scope;this.fogColorId=s.resolve("fog_color"),this.fogStartId=s.resolve("fog_start"),this.fogEndId=s.resolve("fog_end"),this.fogDensityId=s.resolve("fog_density"),this.ambientId=s.resolve("light_globalAmbient"),this.skyboxIntensityId=s.resolve("skyboxIntensity"),this.cubeMapRotationMatrixId=s.resolve("cubeMapRotationMatrix"),this.pcssDiskSamplesId=s.resolve("pcssDiskSamples[0]"),this.pcssSphereSamplesId=s.resolve("pcssSphereSamples[0]"),this.lightColorId=[],this.lightDir=[],this.lightDirId=[],this.lightShadowMapId=[],this.lightShadowMatrixId=[],this.lightShadowParamsId=[],this.lightShadowIntensity=[],this.lightRadiusId=[],this.lightPos=[],this.lightPosId=[],this.lightWidth=[],this.lightWidthId=[],this.lightHeight=[],this.lightHeightId=[],this.lightInAngleId=[],this.lightOutAngleId=[],this.lightCookieId=[],this.lightCookieIntId=[],this.lightCookieMatrixId=[],this.lightCookieOffsetId=[],this.lightShadowSearchAreaId=[],this.lightCameraParamsId=[],this.shadowMatrixPaletteId=[],this.shadowCascadeDistancesId=[],this.shadowCascadeCountId=[],this.screenSizeId=s.resolve("uScreenSize"),this._screenSize=new Float32Array(4),this.fogColor=new Float32Array(3),this.ambientColor=new Float32Array(3),this.pcssDiskSamples=function(t){const e=[];for(let s=0;s<t;++s){const i=Math.sqrt(s+.5)/Math.sqrt(t);e.push(i)}return e}(16),this.pcssSphereSamples=function(t){const e=[];for(let s=0;s<t;s++){const i=s/t,a=Math.sqrt(1-i*i);e.push(a)}return e}(16)}destroy(){super.destroy()}dispatchGlobalLights(t){if(this.ambientColor[0]=t.ambientLight.r,this.ambientColor[1]=t.ambientLight.g,this.ambientColor[2]=t.ambientLight.b,t.gammaCorrection)for(let t=0;t<3;t++)this.ambientColor[t]=Math.pow(this.ambientColor[t],2.2);if(t.physicalUnits)for(let e=0;e<3;e++)this.ambientColor[e]*=t.ambientLuminance;this.ambientId.setValue(this.ambientColor),this.skyboxIntensityId.setValue(t.physicalUnits?t.skyboxLuminance:t.skyboxIntensity),this.cubeMapRotationMatrixId.setValue(t._skyboxRotationMat3.data)}_resolveLight(t,e){const s=`light${e}`;this.lightColorId[e]=t.resolve(`${s}_color`),this.lightDir[e]=new Float32Array(3),this.lightDirId[e]=t.resolve(`${s}_direction`),this.lightShadowMapId[e]=t.resolve(`${s}_shadowMap`),this.lightShadowMatrixId[e]=t.resolve(`${s}_shadowMatrix`),this.lightShadowParamsId[e]=t.resolve(`${s}_shadowParams`),this.lightShadowIntensity[e]=t.resolve(`${s}_shadowIntensity`),this.lightShadowSearchAreaId[e]=t.resolve(`${s}_shadowSearchArea`),this.lightRadiusId[e]=t.resolve(`${s}_radius`),this.lightPos[e]=new Float32Array(3),this.lightPosId[e]=t.resolve(`${s}_position`),this.lightWidth[e]=new Float32Array(3),this.lightWidthId[e]=t.resolve(`${s}_halfWidth`),this.lightHeight[e]=new Float32Array(3),this.lightHeightId[e]=t.resolve(`${s}_halfHeight`),this.lightInAngleId[e]=t.resolve(`${s}_innerConeAngle`),this.lightOutAngleId[e]=t.resolve(`${s}_outerConeAngle`),this.lightCookieId[e]=t.resolve(`${s}_cookie`),this.lightCookieIntId[e]=t.resolve(`${s}_cookieIntensity`),this.lightCookieMatrixId[e]=t.resolve(`${s}_cookieMatrix`),this.lightCookieOffsetId[e]=t.resolve(`${s}_cookieOffset`),this.lightCameraParamsId[e]=t.resolve(`${s}_cameraParams`),this.shadowMatrixPaletteId[e]=t.resolve(`${s}_shadowMatrixPalette[0]`),this.shadowCascadeDistancesId[e]=t.resolve(`${s}_shadowCascadeDistances[0]`),this.shadowCascadeCountId[e]=t.resolve(`${s}_shadowCascadeCount`)}setLTCDirectionalLight(e,s,i,a,o){this.lightPos[s][0]=a.x-i.x*o,this.lightPos[s][1]=a.y-i.y*o,this.lightPos[s][2]=a.z-i.z*o,this.lightPosId[s].setValue(this.lightPos[s]);const h=e.transformVector(new t(-.5,0,0));this.lightWidth[s][0]=h.x*o,this.lightWidth[s][1]=h.y*o,this.lightWidth[s][2]=h.z*o,this.lightWidthId[s].setValue(this.lightWidth[s]);const r=e.transformVector(new t(0,0,.5));this.lightHeight[s][0]=r.x*o,this.lightHeight[s][1]=r.y*o,this.lightHeight[s][2]=r.z*o,this.lightHeightId[s].setValue(this.lightHeight[s])}dispatchDirectLights(t,s,i,a){let o=0;const h=this.device.scope;for(let r=0;r<t.length;r++){if(!(t[r].mask&i))continue;const l=t[r],n=l._node.getWorldTransform();if(this.lightColorId[o]||this._resolveLight(h,o),this.lightColorId[o].setValue(s.gammaCorrection?l._linearFinalColor:l._finalColor),n.getY(l._direction).mulScalar(-1),l._direction.normalize(),this.lightDir[o][0]=l._direction.x,this.lightDir[o][1]=l._direction.y,this.lightDir[o][2]=l._direction.z,this.lightDirId[o].setValue(this.lightDir[o]),l.shape!==e&&this.setLTCDirectionalLight(n,o,l._direction,a._node.getPosition(),a.farClip),l.castShadows){const t=l.getRenderData(a,0),e=l._getUniformBiasValues(t);this.lightShadowMapId[o].setValue(t.shadowBuffer),this.lightShadowMatrixId[o].setValue(t.shadowMatrix.data),this.shadowMatrixPaletteId[o].setValue(l._shadowMatrixPalette),this.shadowCascadeDistancesId[o].setValue(l._shadowCascadeDistances),this.shadowCascadeCountId[o].setValue(l.numCascades),this.lightShadowIntensity[o].setValue(l.shadowIntensity);const s=50/t.projectionCompensation,i=t.shadowCamera.renderTarget;if(i){const t=l.penumbraSize/i.width;this.lightShadowSearchAreaId[o].setValue(t*s)}const h=l._shadowCameraParams;h.length=4,h[0]=t.depthRangeCompensation,h[1]=t.shadowCamera._farClip,h[2]=t.shadowCamera._nearClip,h[3]=1,this.lightCameraParamsId[o].setValue(h);const r=l._shadowRenderParams;r.length=4,r[0]=l._shadowResolution,r[1]=e.normalBias,r[2]=e.bias,r[3]=0,this.lightShadowParamsId[o].setValue(r)}o++}return o}setLTCPositionalLight(e,s){const i=e.transformVector(new t(-.5,0,0));this.lightWidth[s][0]=i.x,this.lightWidth[s][1]=i.y,this.lightWidth[s][2]=i.z,this.lightWidthId[s].setValue(this.lightWidth[s]);const a=e.transformVector(new t(0,0,.5));this.lightHeight[s][0]=a.x,this.lightHeight[s][1]=a.y,this.lightHeight[s][2]=a.z,this.lightHeightId[s].setValue(this.lightHeight[s])}dispatchOmniLight(t,s,i,a){const o=i._node.getWorldTransform();if(this.lightColorId[a]||this._resolveLight(s,a),this.lightRadiusId[a].setValue(i.attenuationEnd),this.lightColorId[a].setValue(t.gammaCorrection?i._linearFinalColor:i._finalColor),o.getTranslation(i._position),this.lightPos[a][0]=i._position.x,this.lightPos[a][1]=i._position.y,this.lightPos[a][2]=i._position.z,this.lightPosId[a].setValue(this.lightPos[a]),i.shape!==e&&this.setLTCPositionalLight(o,a),i.castShadows){const t=i.getRenderData(null,0);this.lightShadowMapId[a].setValue(t.shadowBuffer);const e=i._getUniformBiasValues(t),s=i._shadowRenderParams;s.length=4,s[0]=i._shadowResolution,s[1]=e.normalBias,s[2]=e.bias,s[3]=1/i.attenuationEnd,this.lightShadowParamsId[a].setValue(s),this.lightShadowIntensity[a].setValue(i.shadowIntensity);const o=i.penumbraSize/t.shadowCamera.renderTarget.width;this.lightShadowSearchAreaId[a].setValue(o);const h=i._shadowCameraParams;h.length=4,h[0]=t.depthRangeCompensation,h[1]=t.shadowCamera._farClip,h[2]=t.shadowCamera._nearClip,h[3]=0,this.lightCameraParamsId[a].setValue(h)}i._cookie&&(this.lightCookieId[a].setValue(i._cookie),this.lightShadowMatrixId[a].setValue(o.data),this.lightCookieIntId[a].setValue(i.cookieIntensity))}dispatchSpotLight(t,s,i,a){const o=i._node.getWorldTransform();if(this.lightColorId[a]||this._resolveLight(s,a),this.lightInAngleId[a].setValue(i._innerConeAngleCos),this.lightOutAngleId[a].setValue(i._outerConeAngleCos),this.lightRadiusId[a].setValue(i.attenuationEnd),this.lightColorId[a].setValue(t.gammaCorrection?i._linearFinalColor:i._finalColor),o.getTranslation(i._position),this.lightPos[a][0]=i._position.x,this.lightPos[a][1]=i._position.y,this.lightPos[a][2]=i._position.z,this.lightPosId[a].setValue(this.lightPos[a]),i.shape!==e&&this.setLTCPositionalLight(o,a),o.getY(i._direction).mulScalar(-1),i._direction.normalize(),this.lightDir[a][0]=i._direction.x,this.lightDir[a][1]=i._direction.y,this.lightDir[a][2]=i._direction.z,this.lightDirId[a].setValue(this.lightDir[a]),i.castShadows){const t=i.getRenderData(null,0);this.lightShadowMapId[a].setValue(t.shadowBuffer),this.lightShadowMatrixId[a].setValue(t.shadowMatrix.data);const e=i._getUniformBiasValues(t),s=i._shadowRenderParams;s.length=4,s[0]=i._shadowResolution,s[1]=e.normalBias,s[2]=e.bias,s[3]=1/i.attenuationEnd,this.lightShadowParamsId[a].setValue(s),this.lightShadowIntensity[a].setValue(i.shadowIntensity);const o=i.penumbraSize/t.shadowCamera.renderTarget.width,h=t.shadowCamera._fov*Math.PI/180,r=1/Math.tan(h/2);this.lightShadowSearchAreaId[a].setValue(o*r);const l=i._shadowCameraParams;l.length=4,l[0]=t.depthRangeCompensation,l[1]=t.shadowCamera._farClip,l[2]=t.shadowCamera._nearClip,l[3]=0,this.lightCameraParamsId[a].setValue(l)}if(i._cookie){if(!i.castShadows){const t=n.evalSpotCookieMatrix(i);this.lightShadowMatrixId[a].setValue(t.data)}this.lightCookieId[a].setValue(i._cookie),this.lightCookieIntId[a].setValue(i.cookieIntensity),i._cookieTransform&&(i._cookieTransformUniform[0]=i._cookieTransform.x,i._cookieTransformUniform[1]=i._cookieTransform.y,i._cookieTransformUniform[2]=i._cookieTransform.z,i._cookieTransformUniform[3]=i._cookieTransform.w,this.lightCookieMatrixId[a].setValue(i._cookieTransformUniform),i._cookieOffsetUniform[0]=i._cookieOffset.x,i._cookieOffsetUniform[1]=i._cookieOffset.y,this.lightCookieOffsetId[a].setValue(i._cookieOffsetUniform))}}dispatchLocalLights(t,e,a,o){let h=o;const r=this.device.scope,l=t[s],n=l.length;for(let t=0;t<n;t++){const s=l[t];s.mask&a&&(this.dispatchOmniLight(e,r,s,h),h++)}const d=t[i],g=d.length;for(let t=0;t<g;t++){const s=d[t];s.mask&a&&(this.dispatchSpotLight(e,r,s,h),h++)}}renderForwardPrepareMaterials(t,e,s,i,a){var o;const h=(t,e,s,i)=>{u.drawCalls.push(t),u.shaderInstances.push(e),u.isNewMaterial.push(s),u.lightMaskChanged.push(i)};u.clear();const r=this.device,l=this.scene,n=l.clusteredLightingEnabled,d=null!=(o=null==i?void 0:i.getLightHash(n))?o:0;let g,c,m=null;const p=e.length;for(let t=0;t<p;t++){const i=e[t];i.ensureMaterial(r);const o=i.material,n=i._shaderDefs,u=i.mask;o&&o===m&&n!==g&&(m=null),o!==m&&(this._materialSwitches++,o._scene=l,o.dirty&&(o.updateUniforms(r,l),o.dirty=!1));const p=i.getShaderInstance(a,d,l,this.viewUniformFormat,this.viewBindGroupFormat,s);h(i,p,o!==m,!m||u!==c),m=o,g=n,c=u}return u}renderForwardInternal(t,e,s,i,o,h){const r=this.device,l=this.scene,n=1<<i,d=h?-1:1,g=this.scene.clusteredLightingEnabled,c=e.drawCalls.length;for(let i=0;i<c;i++){var u,m;const h=e.drawCalls[i],p=e.isNewMaterial[i],f=e.lightMaskChanged[i],w=e.shaderInstances[i],I=h.material,C=h.mask;if(p){const e=!1;if(r.setShader(w.shader,e),I.setParameters(r),f){const e=this.dispatchDirectLights(s[a],l,C,t);g||this.dispatchLocalLights(s,l,C,e)}this.alphaTestId.setValue(I.alphaTest),r.setBlendState(I.blendState),r.setDepthState(I.depthState),r.setAlphaToCoverage(I.alphaToCoverage)}this.setupCullMode(t._cullFaces,d,h);const _=null!=(u=h.stencilFront)?u:I.stencilFront,S=null!=(m=h.stencilBack)?m:I.stencilBack;r.setStencilState(_,S);const v=h.mesh;h.setParameters(r,n),this.setVertexBuffers(r,v),this.setMorphing(r,h.morphInstance),this.setSkinning(r,h),this.setupMeshUniformBuffers(w,h);const V=h.renderStyle;if(r.setIndexBuffer(v.indexBuffer[V]),null==o||o(h,i),t.xr&&t.xr.session&&t.xr.views.list.length){const e=t.xr.views;for(let t=0;t<e.list.length;t++){const s=e.list[t];r.setViewport(s.viewport.x,s.viewport.y,s.viewport.z,s.viewport.w),this.projId.setValue(s.projMat.data),this.projSkyboxId.setValue(s.projMat.data),this.viewId.setValue(s.viewOffMat.data),this.viewInvId.setValue(s.viewInvOffMat.data),this.viewId3.setValue(s.viewMat3.data),this.viewProjId.setValue(s.projViewOffMat.data),this.viewPosId.setValue(s.positionData),this.viewIndexId.setValue(t),0===t?this.drawInstance(r,h,v,V,!0):this.drawInstance2(r,h,v,V),this._forwardDrawCalls++}}else this.drawInstance(r,h,v,V,!0),this._forwardDrawCalls++;i<c-1&&!e.isNewMaterial[i+1]&&I.setParameters(r,h.parameters)}}renderForward(t,e,s,i,a,o,h){const r=this.renderForwardPrepareMaterials(t,e,s,o,i);this.renderForwardInternal(t,r,s,i,a,h),u.clear()}renderForwardLayer(t,e,s,i,a,o,h={}){var r,l,n;const{scene:d,device:g}=this,u=d.clusteredLightingEnabled;this.setupViewport(t,e);const m=null!=(r=h.clearColor)&&r,p=null!=(l=h.clearDepth)&&l,f=null!=(n=h.clearStencil)&&n;let w,I;if((m||p||f)&&this.clear(t,m,p,f),s){s.sortVisible(t,i);const e=s.getCulledInstances(t);w=i?e.transparent:e.opaque,d.immediate.onPreRenderLayer(s,w,i),s.requiresLightCube&&(this.lightCube.update(d.ambientLight,s._lights),this.constantLightCube.setValue(this.lightCube.colors)),I=s.splitLights}else{var C;w=h.meshInstances,I=null!=(C=h.splitLights)?C:c}if(u){var _;(null!=(_=h.lightClusters)?_:this.worldClustersAllocator.empty).activate(),s&&(this.clustersDebugRendered||d.lighting.debugLayer!==s.id||(this.clustersDebugRendered=!0))}d._activeCamera=t;const S=this.setCameraUniforms(t,e);g.supportsUniformBuffers&&this.setupViewUniformBuffers(o,this.viewUniformFormat,this.viewBindGroupFormat,S);const v=!!(t._flipFaces^(null==e?void 0:e.flipY)),V=this._forwardDrawCalls;this.renderForward(t,w,I,a,null==s?void 0:s.onDrawCall,s,v),s&&(s._forwardDrawCalls+=this._forwardDrawCalls-V)}setSceneConstants(){const t=this.scene;if(this.dispatchGlobalLights(t),t.fog!==o){if(this.fogColor[0]=t.fogColor.r,this.fogColor[1]=t.fogColor.g,this.fogColor[2]=t.fogColor.b,t.gammaCorrection)for(let t=0;t<3;t++)this.fogColor[t]=Math.pow(this.fogColor[t],2.2);this.fogColorId.setValue(this.fogColor),t.fog===h?(this.fogStartId.setValue(t.fogStart),this.fogEndId.setValue(t.fogEnd)):this.fogDensityId.setValue(t.fogDensity)}const e=this.device;this._screenSize[0]=e.width,this._screenSize[1]=e.height,this._screenSize[2]=1/e.width,this._screenSize[3]=1/e.height,this.screenSizeId.setValue(this._screenSize),this.pcssDiskSamplesId.setValue(this.pcssDiskSamples),this.pcssSphereSamplesId.setValue(this.pcssSphereSamples)}buildFrameGraph(t,e){const s=this.scene,i=this.device.isWebGL1;if(t.reset(),this.update(e),s.clusteredLightingEnabled){const{shadowsEnabled:e,cookiesEnabled:i}=s.lighting;this._renderPassUpdateClustered.update(t,e,i,this.lights,this.localLights),t.addRenderPass(this._renderPassUpdateClustered)}else this._shadowRendererLocal.buildNonClusteredRenderPasses(t,this.localLights);let a=0,o=!0,h=null;const l=e._renderActions;for(let s=a;s<l.length;s++){const n=l[s],{layer:d,camera:c}=n;if(n.useCameraPasses)c.camera.renderPasses.forEach((e=>{t.addRenderPass(e)}));else{const u=c.camera.renderPassDepthGrab;u&&i&&n.firstCameraUse&&(u.options.resizeSource=c.camera.renderTarget,u.update(this.scene),t.addRenderPass(u));const m=d.id===r;if(i&&m&&!c.renderSceneColorMap)continue;const p=m&&(c.renderSceneColorMap||c.renderSceneDepthMap);o&&(o=!1,a=s,h=n.renderTarget);const f=l[s+1],w=!!f&&f.layer.id===r&&(c.renderSceneColorMap||c.renderSceneDepthMap)&&!i,I=!!f&&(f.firstCameraUse&&this.cameraDirShadowLights.has(f.camera.camera));if(!f||f.renderTarget!==h||I||w||p){if(m&&a===s||this.addMainRenderPass(t,e,h,a,s),m){if(c.renderSceneColorMap){const e=c.camera.renderPassColorGrab;e.source=c.renderTarget,t.addRenderPass(e)}c.renderSceneDepthMap&&!i&&t.addRenderPass(c.camera.renderPassDepthGrab)}if(n.triggerPostprocess&&null!=c&&c.onPostprocessing){const e=new g(this.device,this,n);t.addRenderPass(e)}o=!0}}}}addMainRenderPass(t,e,s,i,a){const o=new d(this.device,e,this.scene,this);o.init(s);const h=e._renderActions;for(let t=i;t<=a;t++)o.addRenderAction(h[t]);t.addRenderPass(o)}update(t){this.frameUpdate(),this.shadowRenderer.frameUpdate(),this.scene._updateSkyMesh(),this.updateLayerComposition(t),this.collectLights(t),this.beginFrame(t),this.setSceneConstants(),this.cullComposition(t),this.gpuUpdate(this.processingMeshInstances)}}export{m as ForwardRenderer};