@animech-public/playcanvas
Version:
PlayCanvas WebGL game engine
2 lines (1 loc) • 4.97 kB
JavaScript
import{BLENDEQUATION_ADD as t,BLENDMODE_ONE as e}from"../platform/graphics/constants.js";import{drawQuadWithShader as s}from"./graphics/quad-render-utils.js";import{RenderTarget as r}from"../platform/graphics/render-target.js";import{createShaderFromCode as i}from"./shader-lib/utils.js";import{BlendState as h}from"../platform/graphics/blend-state.js";const o=new h(!0,t,e,e);class a{constructor(t){this.morph=t,t.incRefCount(),this.device=t.device,this._weights=[],this._weightMap=new Map;for(let e=0;e<t._targets.length;e++){const s=t._targets[e];s.name&&this._weightMap.set(s.name,e),this.setWeight(e,s.defaultWeight)}if(this._activeTargets=[],t.useTextureMorph){this.shaderCache={},this.maxSubmitCount=this.device.maxTextures,this._shaderMorphWeights=new Float32Array(this.maxSubmitCount);const e=(e,s)=>(this[s]=t._createTexture(e,t._renderTextureFormat),new r({colorBuffer:this[s],depth:!1}));t.morphPositions&&(this.rtPositions=e("MorphRTPos","texturePositions")),t.morphNormals&&(this.rtNormals=e("MorphRTNrm","textureNormals")),this._textureParams=new Float32Array([t.morphTextureWidth,t.morphTextureHeight,1/t.morphTextureWidth,1/t.morphTextureHeight]);for(let t=0;t<this.maxSubmitCount;t++)this[`morphBlendTex${t}`]=this.device.scope.resolve(`morphBlendTex${t}`);this.morphFactor=this.device.scope.resolve("morphFactor[0]"),this.zeroTextures=!1}else this.maxSubmitCount=8,this._shaderMorphWeights=new Float32Array(this.maxSubmitCount),this._shaderMorphWeightsA=new Float32Array(this._shaderMorphWeights.buffer,0,4),this._shaderMorphWeightsB=new Float32Array(this._shaderMorphWeights.buffer,16,4),this._activeVertexBuffers=new Array(this.maxSubmitCount)}destroy(){this.shader=null;const t=this.morph;t&&(this.morph=null,t.decRefCount(),t.refCount<1&&t.destroy()),this.rtPositions&&(this.rtPositions.destroy(),this.rtPositions=null),this.texturePositions&&(this.texturePositions.destroy(),this.texturePositions=null),this.rtNormals&&(this.rtNormals.destroy(),this.rtNormals=null),this.textureNormals&&(this.textureNormals.destroy(),this.textureNormals=null)}clone(){return new a(this.morph)}_getWeightIndex(t){if("string"==typeof t){return this._weightMap.get(t)}return t}getWeight(t){const e=this._getWeightIndex(t);return this._weights[e]}setWeight(t,e){const s=this._getWeightIndex(t);this._weights[s]=e,this._dirty=!0}_getFragmentShader(t){let e="";t>0&&(e+=`varying vec2 uv0;\nuniform highp float morphFactor[${t}];\n`);for(let s=0;s<t;s++)e+=`uniform highp sampler2D morphBlendTex${s};\n`;e+="void main (void) {\n highp vec4 color = vec4(0, 0, 0, 1);\n";for(let s=0;s<t;s++)e+=` color.xyz += morphFactor[${s}] * texture2D(morphBlendTex${s}, uv0).xyz;\n`;return e+=" gl_FragColor = color;\n}\n",e}_getShader(t){let e=this.shaderCache[t];if(!e){const s=this._getFragmentShader(t);e=i(this.device,"\n\tattribute vec2 vertex_position;\n\tvarying vec2 uv0;\n\tvoid main(void) {\n\t\tgl_Position = vec4(vertex_position, 0.5, 1.0);\n\t\tuv0 = vertex_position.xy * 0.5 + 0.5;\n\t}\n\t",s,`textureMorph${t}`),this.shaderCache[t]=e}return e}_updateTextureRenderTarget(t,e){const r=this.device,i=(e,i)=>{this.morphFactor.setValue(this._shaderMorphWeights),r.setBlendState(i?o:h.NOBLEND);const a=this._getShader(e);s(r,t,a)};let a=0,n=!1;const g=this._activeTargets.length;for(let t=0;t<g;t++){const s=this._activeTargets[t],r=s.target[e];r&&(this[`morphBlendTex${a}`].setValue(r),this._shaderMorphWeights[a]=s.weight,a++,a>=this.maxSubmitCount&&(i(a,n),a=0,n=!0))}(a>0||0===g&&!this.zeroTextures)&&i(a,n)}_updateTextureMorph(){this.device,(this._activeTargets.length>0||!this.zeroTextures)&&(this.rtPositions&&this._updateTextureRenderTarget(this.rtPositions,"texturePositions"),this.rtNormals&&this._updateTextureRenderTarget(this.rtNormals,"textureNormals"),this.zeroTextures=0===this._activeTargets.length)}_updateVertexMorph(){const t=this.maxSubmitCount;for(let e=0;e<t;e++)this._shaderMorphWeights[e]=0,this._activeVertexBuffers[e]=null;let e=0,s=this.morph.morphPositions?4:0;for(let t=0;t<this._activeTargets.length;t++){const r=this._activeTargets[t].target;r._vertexBufferPositions&&(this._activeVertexBuffers[e]=r._vertexBufferPositions,this._shaderMorphWeights[e]=this._activeTargets[t].weight,e++),r._vertexBufferNormals&&(this._activeVertexBuffers[s]=r._vertexBufferNormals,this._shaderMorphWeights[s]=this._activeTargets[t].weight,s++)}}update(){this._dirty=!1;const t=this.morph._targets;let e=0;for(let s=0;s<t.length;s++){const r=Math.abs(this.getWeight(s));if(r>1e-5){this._activeTargets.length<=e&&(this._activeTargets[e]={});const i=this._activeTargets[e++];i.absWeight=r,i.weight=this.getWeight(s),i.target=t[s]}}this._activeTargets.length=e;const s=this.morph.maxActiveTargets;this._activeTargets.length>s&&(this._activeTargets.sort(((t,e)=>t.absWeight<e.absWeight?1:e.absWeight<t.absWeight?-1:0)),this._activeTargets.length=s),this.morph.useTextureMorph?this._updateTextureMorph():this._updateVertexMorph()}}export{a as MorphInstance};