UNPKG

@animech-public/playcanvas

Version:
2 lines (1 loc) 17.9 kB
import{Vec2 as e}from"../../core/math/vec2.js";import{Vec3 as t}from"../../core/math/vec3.js";import{Vec4 as s}from"../../core/math/vec4.js";import{Mat3 as r}from"../../core/math/mat3.js";import{Mat4 as i}from"../../core/math/mat4.js";import{BoundingSphere as a}from"../../core/shape/bounding-sphere.js";import{SORTKEY_FORWARD as o,SORTKEY_DEPTH as l,VIEW_CENTER as n,PROJECTION_ORTHOGRAPHIC as h,LIGHTTYPE_DIRECTIONAL as d,SHADOWUPDATE_NONE as c,SHADOWUPDATE_THISFRAME as u}from"../constants.js";import{LightTextureAtlas as p}from"../lighting/light-texture-atlas.js";import{Material as m}from"../materials/material.js";import{LightCube as f}from"../graphics/light-cube.js";import{CLEARFLAG_COLOR as w,CLEARFLAG_DEPTH as g,CLEARFLAG_STENCIL as v,CULLFACE_FRONT as x,CULLFACE_BACK as _,CULLFACE_NONE as M,UNIFORMTYPE_MAT4 as I,UNIFORMTYPE_MAT3 as C,UNIFORMTYPE_VEC3 as S,UNIFORMTYPE_FLOAT as V,UNIFORMTYPE_VEC2 as b,UNIFORMTYPE_INT as y,UNIFORM_BUFFER_DEFAULT_SLOT_NAME as T,SHADERSTAGE_VERTEX as B,SHADERSTAGE_FRAGMENT as L,TEXTUREDIMENSION_2D as P,SAMPLETYPE_UNFILTERABLE_FLOAT as j,SAMPLETYPE_DEPTH as F,SAMPLETYPE_FLOAT as U,BINDGROUP_VIEW as D,BINDGROUP_MESH as R,SEMANTIC_ATTR as N}from"../../platform/graphics/constants.js";import{UniformBuffer as k}from"../../platform/graphics/uniform-buffer.js";import{BindGroup as z}from"../../platform/graphics/bind-group.js";import{UniformFormat as A,UniformBufferFormat as J}from"../../platform/graphics/uniform-buffer-format.js";import{BindUniformBufferFormat as O,BindTextureFormat as G,BindGroupFormat as W}from"../../platform/graphics/bind-group-format.js";import{ShadowMapCache as E}from"./shadow-map-cache.js";import{ShadowRendererLocal as Y}from"./shadow-renderer-local.js";import{ShadowRendererDirectional as q}from"./shadow-renderer-directional.js";import{ShadowRenderer as Z}from"./shadow-renderer.js";import{WorldClustersAllocator as H}from"./world-clusters-allocator.js";import{RenderPassUpdateClustered as K}from"./render-pass-update-clustered.js";import{getBlueNoiseTexture as Q}from"../graphics/noise-textures.js";import{BlueNoise as X}from"../../core/math/blue-noise.js";let $=0;const ee=new i,te=new i,se=new i,re=new r,ie=new a,ae=(new i).setScale(1,-1,1),oe=new Set,le=new Set,ne=(new i).set([1,0,0,0,0,1,0,0,0,0,.5,0,0,0,.5,1]),he=[new e(.5,.333333),new e(.25,.666667),new e(.75,.111111),new e(.125,.444444),new e(.625,.777778),new e(.375,.222222),new e(.875,.555556),new e(.0625,.888889),new e(.5625,.037037),new e(.3125,.37037),new e(.8125,.703704),new e(.1875,.148148),new e(.6875,.481481),new e(.4375,.814815),new e(.9375,.259259),new e(.03125,.592593)],de=new i,ce=new i,ue=new i,pe=new i,me=new i,fe=new i,we=new Set,ge=[],ve=[];class xe{constructor(e){this.clustersDebugRendered=!1,this.processingMeshInstances=new Set,this.worldClustersAllocator=void 0,this.lights=[],this.localLights=[],this.cameraDirShadowLights=new Map,this.dirLightShadows=new Map,this.blueNoise=new X(123),this.device=e,this.scene=null,this.worldClustersAllocator=new H(e),this.lightTextureAtlas=new p(e),this.shadowMapCache=new E,this.shadowRenderer=new Z(this,this.lightTextureAtlas),this._shadowRendererLocal=new Y(this,this.shadowRenderer),this._shadowRendererDirectional=new q(this,this.shadowRenderer),this._renderPassUpdateClustered=new K(this.device,this,this.shadowRenderer,this._shadowRendererLocal,this.lightTextureAtlas),this.viewUniformFormat=null,this.viewBindGroupFormat=null,this._skinTime=0,this._morphTime=0,this._cullTime=0,this._shadowMapTime=0,this._lightClustersTime=0,this._layerCompositionUpdateTime=0,this._shadowDrawCalls=0,this._skinDrawCalls=0,this._instancedDrawCalls=0,this._shadowMapUpdates=0,this._numDrawCallsCulled=0,this._camerasRendered=0,this._lightClusters=0;const t=e.scope;this.boneTextureId=t.resolve("texture_poseMap"),this.boneTextureSizeId=t.resolve("texture_poseMapSize"),this.poseMatrixId=t.resolve("matrix_pose[0]"),this.modelMatrixId=t.resolve("matrix_model"),this.normalMatrixId=t.resolve("matrix_normal"),this.viewInvId=t.resolve("matrix_viewInverse"),this.viewPos=new Float32Array(3),this.viewPosId=t.resolve("view_position"),this.projId=t.resolve("matrix_projection"),this.projSkyboxId=t.resolve("matrix_projectionSkybox"),this.viewId=t.resolve("matrix_view"),this.viewId3=t.resolve("matrix_view3"),this.viewProjId=t.resolve("matrix_viewProjection"),this.flipYId=t.resolve("projectionFlipY"),this.tbnBasis=t.resolve("tbnBasis"),this.nearClipId=t.resolve("camera_near"),this.farClipId=t.resolve("camera_far"),this.cameraParams=new Float32Array(4),this.cameraParamsId=t.resolve("camera_params"),this.viewIndexId=t.resolve("view_index"),this.blueNoiseJitterVersion=0,this.blueNoiseJitterVec=new s,this.blueNoiseJitterData=new Float32Array(4),this.blueNoiseJitterId=t.resolve("blueNoiseJitter"),this.blueNoiseTextureId=t.resolve("blueNoiseTex32"),this.alphaTestId=t.resolve("alpha_ref"),this.opacityMapId=t.resolve("texture_opacityMap"),this.exposureId=t.resolve("exposure"),this.twoSidedLightingNegScaleFactorId=t.resolve("twoSidedLightingNegScaleFactor"),this.twoSidedLightingNegScaleFactorId.setValue(0),this.morphWeightsA=t.resolve("morph_weights_a"),this.morphWeightsB=t.resolve("morph_weights_b"),this.morphPositionTex=t.resolve("morphPositionTex"),this.morphNormalTex=t.resolve("morphNormalTex"),this.morphTexParams=t.resolve("morph_tex_params"),this.lightCube=new f,this.constantLightCube=t.resolve("lightCube[0]")}destroy(){this.shadowRenderer=null,this._shadowRendererLocal=null,this._shadowRendererDirectional=null,this.shadowMapCache.destroy(),this.shadowMapCache=null,this._renderPassUpdateClustered.destroy(),this._renderPassUpdateClustered=null,this.lightTextureAtlas.destroy(),this.lightTextureAtlas=null}sortCompare(e,t){if(e.layer===t.layer){if(e.drawOrder&&t.drawOrder)return e.drawOrder-t.drawOrder;if(e.zdist&&t.zdist)return t.zdist-e.zdist;if(e.zdist2&&t.zdist2)return e.zdist2-t.zdist2}return t._key[o]-e._key[o]}sortCompareMesh(e,t){if(e.layer===t.layer){if(e.drawOrder&&t.drawOrder)return e.drawOrder-t.drawOrder;if(e.zdist&&t.zdist)return t.zdist-e.zdist}const s=e._key[o],r=t._key[o];return s===r&&e.mesh&&t.mesh?t.mesh.id-e.mesh.id:r-s}sortCompareDepth(e,t){const s=e._key[l],r=t._key[l];return s===r&&e.mesh&&t.mesh?t.mesh.id-e.mesh.id:r-s}setupViewport(e,t){const s=this.device,r=t?t.width:s.width,i=t?t.height:s.height,a=e.rect;let o=Math.floor(a.x*r),l=Math.floor(a.y*i),n=Math.floor(a.z*r),h=Math.floor(a.w*i);if(s.setViewport(o,l,n,h),e._scissorRectClear){const t=e.scissorRect;o=Math.floor(t.x*r),l=Math.floor(t.y*i),n=Math.floor(t.z*r),h=Math.floor(t.w*i)}s.setScissor(o,l,n,h)}setCameraUniforms(e,r){const i=null==r?void 0:r.flipY;let a=1;if(e.xr&&e.xr.session){var o;const t=(null==(o=e._node)||null==(o=o.parent)?void 0:o.getWorldTransform())||null,s=e.xr.views;a=s.list.length;for(let r=0;r<a;r++){const i=s.list[r];i.updateTransforms(t),e.frustum.setFromMat4(i.projViewOffMat)}}else{let a=e.projectionMatrix;e.calculateProjection&&e.calculateProjection(a,n);let o=e.getProjectionMatrixSkybox();i&&(a=de.mul2(ae,a),o=ce.mul2(ae,o)),this.device.isWebGPU&&(a=ue.mul2(ne,a),o=pe.mul2(ne,o));const{jitter:l}=e;let h=0,d=0;if(l>0){const e=r?r.width:this.device.width,t=r?r.height:this.device.height,s=he[this.device.renderVersion%he.length];h=l*(2*s.x-1)/e,d=l*(2*s.y-1)/t,a=me.copy(a),a.data[8]=h,a.data[9]=d,o=fe.copy(o),o.data[8]=h,o.data[9]=d,this.blueNoiseJitterVersion!==this.device.renderVersion&&(this.blueNoiseJitterVersion=this.device.renderVersion,this.blueNoise.vec4(this.blueNoiseJitterVec))}const c=l>0?this.blueNoiseJitterVec:s.ZERO;if(this.blueNoiseJitterData[0]=c.x,this.blueNoiseJitterData[1]=c.y,this.blueNoiseJitterData[2]=c.z,this.blueNoiseJitterData[3]=c.w,this.blueNoiseJitterId.setValue(this.blueNoiseJitterData),this.projId.setValue(a.data),this.projSkyboxId.setValue(o.data),e.calculateTransform)e.calculateTransform(te,n);else{const s=e._node.getPosition(),r=e._node.getRotation();te.setTRS(s,r,t.ONE)}this.viewInvId.setValue(te.data),se.copy(te).invert(),this.viewId.setValue(se.data),re.setFromMat4(se),this.viewId3.setValue(re.data),ee.mul2(a,se),this.viewProjId.setValue(ee.data),e._storeShaderMatrices(ee,h,d,this.device.renderVersion),this.flipYId.setValue(i?-1:1),this.dispatchViewPos(e._node.getPosition()),e.frustum.setFromMat4(ee)}this.tbnBasis.setValue(i?-1:1);const l=e._nearClip,d=e._farClip;return this.nearClipId.setValue(l),this.farClipId.setValue(d),this.cameraParams[0]=1/d,this.cameraParams[1]=d,this.cameraParams[2]=l,this.cameraParams[3]=e.projection===h?1:0,this.cameraParamsId.setValue(this.cameraParams),this.exposureId.setValue(this.scene.physicalUnits?e.getExposure():this.scene.exposure),a}clear(e,t,s,r){const i=((null!=t?t:e._clearColorBuffer)?w:0)|((null!=s?s:e._clearDepthBuffer)?g:0)|((null!=r?r:e._clearStencilBuffer)?v:0);if(i){this.device.clear({color:[e._clearColor.r,e._clearColor.g,e._clearColor.b,e._clearColor.a],depth:e._clearDepth,stencil:e._clearStencil,flags:i})}}setCamera(e,t,s,r=null){this.setCameraUniforms(e,t),this.clearView(e,t,s,!1)}clearView(e,t,s,r){const i=this.device;if(i.setRenderTarget(t),i.updateBegin(),r&&(i.setColorWrite(!0,!0,!0,!0),i.setDepthWrite(!0)),this.setupViewport(e,t),s){const t=e._clearOptions;i.clear(t||{color:[e._clearColor.r,e._clearColor.g,e._clearColor.b,e._clearColor.a],depth:e._clearDepth,flags:(e._clearColorBuffer?w:0)|(e._clearDepthBuffer?g:0)|(e._clearStencilBuffer?v:0),stencil:e._clearStencil})}}setupCullMode(e,t,s){const r=s.material;let i=M;if(e){let e=1;r.cull!==x&&r.cull!==_||(e=t*s.flipFacesFactor*s.node.worldScaleSign),i=e<0?r.cull===x?_:x:r.cull}this.device.setCullMode(i),i===M&&r.cull===M&&this.twoSidedLightingNegScaleFactorId.setValue(s.node.worldScaleSign)}updateCameraFrustum(e){if(e.xr&&e.xr.views.list.length){const t=e.xr.views.list[0];return ee.mul2(t.projMat,t.viewOffMat),void e.frustum.setFromMat4(ee)}const s=e.projectionMatrix;if(e.calculateProjection&&e.calculateProjection(s,n),e.calculateTransform)e.calculateTransform(te,n);else{const s=e._node.getPosition(),r=e._node.getRotation();te.setTRS(s,r,t.ONE),this.viewInvId.setValue(te.data)}se.copy(te).invert(),ee.mul2(s,se),e.frustum.setFromMat4(ee)}setBaseConstants(e,t){e.setCullMode(t.cull),t.opacityMap&&this.opacityMapId.setValue(t.opacityMap),(t.opacityMap||t.alphaTest>0)&&this.alphaTestId.setValue(t.alphaTest)}updateCpuSkinMatrices(e){$++;const t=e.length;if(0!==t)for(let s=0;s<t;s++){const t=e[s].skinInstance;t&&(t.updateMatrices(e[s].node,$),t._dirty=!0)}}updateGpuSkinMatrices(e){for(const t of e){const e=t.skinInstance;e&&e._dirty&&(e.updateMatrixPalette(t.node,$),e._dirty=!1)}}updateMorphing(e){for(const t of e){const e=t.morphInstance;e&&e._dirty&&e.update()}}updateGSplats(e){for(const s of e){var t;null==(t=s.gsplatInstance)||t.update()}}gpuUpdate(e){this.updateGpuSkinMatrices(e),this.updateMorphing(e),this.updateGSplats(e)}setVertexBuffers(e,t){e.setVertexBuffer(t.vertexBuffer)}setMorphing(e,t){if(t)if(t.morph.useTextureMorph)e.setVertexBuffer(t.morph.vertexBufferIds),this.morphPositionTex.setValue(t.texturePositions),this.morphNormalTex.setValue(t.textureNormals),this.morphTexParams.setValue(t._textureParams);else{for(let s=0;s<t._activeVertexBuffers.length;s++){const r=t._activeVertexBuffers[s];if(r){const t=N+(s+8);r.format.elements[0].name=t,r.format.elements[0].scopeId=e.scope.resolve(t),r.format.update(),e.setVertexBuffer(r)}}this.morphWeightsA.setValue(t._shaderMorphWeightsA),this.morphWeightsB.setValue(t._shaderMorphWeightsB)}}setSkinning(e,t){const s=t.skinInstance;if(s)if(this._skinDrawCalls++,e.supportsBoneTextures){const e=s.boneTexture;this.boneTextureId.setValue(e),this.boneTextureSizeId.setValue(s.boneTextureSize)}else this.poseMatrixId.setValue(s.matrixPalette)}dispatchViewPos(e){const t=this.viewPos;t[0]=e.x,t[1]=e.y,t[2]=e.z,this.viewPosId.setValue(t)}initViewBindGroupFormat(e){if(this.device.supportsUniformBuffers&&!this.viewUniformFormat){const t=[new A("matrix_viewProjection",I),new A("cubeMapRotationMatrix",C),new A("view_position",S),new A("skyboxIntensity",V),new A("exposure",V),new A("textureBias",V)];e&&t.push(new A("clusterCellsCountByBoundsSize",S),new A("clusterTextureSize",S),new A("clusterBoundsMin",S),new A("clusterBoundsDelta",S),new A("clusterCellsDot",S),new A("clusterCellsMax",S),new A("clusterCompressionLimit0",b),new A("shadowAtlasParams",b),new A("clusterMaxCells",y),new A("clusterSkip",V)),this.viewUniformFormat=new J(this.device,t);const s=[new O(T,B|L),new G("lightsTextureFloat",L,P,j),new G("lightsTexture8",L,P,j),new G("shadowAtlasTexture",L,P,F),new G("cookieAtlasTexture",L,P,U),new G("areaLightsLutTex1",L,P,U),new G("areaLightsLutTex2",L,P,U)];e&&s.push(new G("clusterWorldTexture",L,P,j)),this.viewBindGroupFormat=new W(this.device,s)}}setupViewUniformBuffers(e,t,s,r){const i=this.device;for(;e.length<r;){const r=new k(i,t,!1),a=new z(i,s,r);e.push(a)}const a=e[0];a.defaultUniformBuffer.update(),a.update(),i.setBindGroup(D,a)}setupMeshUniformBuffers(e,t){const s=this.device;if(s.supportsUniformBuffers){this.modelMatrixId.setValue(t.node.worldTransform.data),this.normalMatrixId.setValue(t.node.normalMatrix.data);const r=e.getBindGroup(s);r.defaultUniformBuffer.update(),r.update(),s.setBindGroup(R,r)}}drawInstance(e,t,s,r,i){const a=t.node.worldTransform;this.modelMatrixId.setValue(a.data),i&&this.normalMatrixId.setValue(t.node.normalMatrix.data);const o=t.instancingData;o?o.count>0?(this._instancedDrawCalls++,e.setVertexBuffer(o.vertexBuffer),e.draw(s.primitive[r],o.count)):e.clearVertexBuffer():e.draw(s.primitive[r])}drawInstance2(e,t,s,r){const i=t.instancingData;i?i.count>0?(this._instancedDrawCalls++,e.draw(s.primitive[r],i.count,!0)):e.clearVertexBuffer():e.draw(s.primitive[r],void 0,!0)}cull(e,t,s){const r=s.opaque;r.length=0;const i=s.transparent;i.length=0;const a=e.frustumCulling,o=t.length;for(let s=0;s<o;s++){const o=t[s];if(o.visible){if(!a||!o.cull||o._isVisible(e)){o.visibleThisFrame=!0;(o.transparent?i:r).push(o),(o.skinInstance||o.morphInstance||o.gsplatInstance)&&(this.processingMeshInstances.add(o),o.gsplatInstance&&o.gsplatInstance.cameras.push(e))}}}}collectLights(e){this.lights.length=0,this.localLights.length=0;const t=this.scene._stats,s=e.layerList.length;for(let t=0;t<s;t++){const s=e.layerList[t];if(!le.has(s)){le.add(s);const e=s._lights;for(let t=0;t<e.length;t++){const s=e[t];oe.has(s)||(oe.add(s),this.lights.push(s),s._type!==d&&this.localLights.push(s))}}}t.lights=this.lights.length,oe.clear(),le.clear()}cullLights(e,t){const s=this.scene.clusteredLightingEnabled,r=this.scene.physicalUnits;for(let i=0;i<t.length;i++){const a=t[i];if(a.enabled)if(a._type!==d)if(a.getBoundingSphere(ie),e.frustum.containsSphere(ie)){a.visibleThisFrame=!0,a.usePhysicalUnits=r;const t=e.getScreenSize(ie);a.maxScreenSize=Math.max(a.maxScreenSize,t)}else s||a.castShadows&&!a.shadowMap&&(a.visibleThisFrame=!0);else a.usePhysicalUnits=this.scene.physicalUnits}}cullShadowmaps(e){const t=this.scene.clusteredLightingEnabled;for(let s=0;s<this.localLights.length;s++){const r=this.localLights[s];r._type!==d&&(t?r.atlasSlotUpdated&&r.shadowUpdateMode===c&&(r.shadowUpdateMode=u):r.shadowUpdateMode===c&&r.castShadows&&(r.getRenderData(null,0).shadowCamera.renderTarget||(r.shadowUpdateMode=u)),r.visibleThisFrame&&r.castShadows&&r.shadowUpdateMode!==c&&this._shadowRendererLocal.cull(r,e))}this.cameraDirShadowLights.clear();const s=e.cameras;for(let t=0;t<s.length;t++){const i=s[t];if(i.enabled){const t=i.camera;let s;const a=t.layers;for(let i=0;i<a.length;i++){const o=e.getLayerById(a[i]);if(o){const i=o.splitLights[d];for(let a=0;a<i.length;a++){const o=i[a];var r;if(o.castShadows&&!we.has(o))we.add(o),s=null!=(r=s)?r:[],s.push(o),this._shadowRendererDirectional.cull(o,e,t)}}}s&&this.cameraDirShadowLights.set(t,s),we.clear()}}}cullComposition(e){this.processingMeshInstances.clear();const t=e.cameras.length;for(let r=0;r<t;r++){const t=e.cameras[r];let i,a=!0;this._camerasRendered++;const o=t.layers;for(let r=0;r<o.length;r++){const l=e.getLayerById(o[r]);if(l&&l.enabled){var s;const r=null!=(s=t.renderTarget)?s:l.renderTarget;(a||r!==i)&&(a=!1,i=r,t.frameUpdate(r),this.updateCameraFrustum(t.camera)),this.cullLights(t.camera,l._lights),null==l.onPreCull||l.onPreCull(e.camerasMap.get(t));const o=l.getCulledInstances(t.camera);this.cull(t.camera,l.meshInstances,o),null==l.onPostCull||l.onPostCull(e.camerasMap.get(t))}}}this.scene.clusteredLightingEnabled&&this.updateLightTextureAtlas(),this.cullShadowmaps(e)}updateShaders(e,t){const s=e.length;for(let r=0;r<s;r++){const s=e[r].material;if(s&&!we.has(s)&&(we.add(s),s.getShaderVariant!==m.prototype.getShaderVariant)){if(t&&(!s.useLighting||s.emitter&&!s.emitter.lighting))continue;s.clearVariants()}}we.clear()}updateFrameUniforms(){this.blueNoiseTextureId.setValue(Q(this.device))}beginFrame(e){const t=this.scene,s=t.updateShaders,r=e.layerList,i=r.length;for(let e=0;e<i;e++){const t=r[e].meshInstances,i=t.length;for(let e=0;e<i;e++){const r=t[e];r.visibleThisFrame=!1,s&&ge.push(r),r.skinInstance&&ve.push(r)}}if(s){const e=!t.updateShaders;this.updateShaders(ge,e),t.updateShaders=!1,t._shaderVersion++}this.updateFrameUniforms(),this.updateCpuSkinMatrices(ve),ge.length=0,ve.length=0;const a=this.lights,o=a.length;for(let e=0;e<o;e++)a[e].beginFrame()}updateLightTextureAtlas(){this.lightTextureAtlas.update(this.localLights,this.scene.lighting)}updateLayerComposition(e){const t=e.layerList.length;for(let s=0;s<t;s++)e.layerList[s]._postRenderCounter=0;const s=this.scene._shaderVersion;for(let r=0;r<t;r++){const t=e.layerList[r];t._shaderVersion=s,t._preRenderCalledForCameras=0,t._postRenderCalledForCameras=0;const i=e.subLayerList[r];t._postRenderCounter|=i?2:1,t._postRenderCounterMax=t._postRenderCounter}e._update()}frameUpdate(){this.clustersDebugRendered=!1,this.initViewBindGroupFormat(this.scene.clusteredLightingEnabled),this.dirLightShadows.clear()}}export{xe as Renderer};