UNPKG

@xeokit/xeokit-sdk

Version:

3D BIM IFC Viewer SDK for AEC engineering applications. Open Source JavaScript Toolkit based on pure WebGL for top performance, real-world coordinates and full double precision

996 lines (917 loc) 48.2 kB
/** * @author xeolabs / https://github.com/xeolabs */ import {Map} from "../../utils/Map.js"; import {DrawShaderSource} from "./DrawShaderSource.js"; import {Program} from "../../webgl/Program.js"; import {stats} from '../../stats.js'; import {WEBGL_INFO} from '../../webglInfo.js'; import {math} from "../../math/math.js"; import {getPlaneRTCPos} from "../../math/rtcCoords.js"; const tempVec3a = math.vec3(); const ids = new Map({}); /** * @private */ const DrawRenderer = function (hash, mesh) { this.id = ids.addItem({}); this._hash = hash; this._scene = mesh.scene; this._useCount = 0; this._shaderSource = new DrawShaderSource(mesh); this._allocate(mesh); }; const drawRenderers = {}; DrawRenderer.get = function (mesh) { const scene = mesh.scene; const hash = [ scene.canvas.canvas.id, (scene.gammaInput ? "gi;" : ";") + (scene.gammaOutput ? "go" : ""), scene._lightsState.getHash(), scene._sectionPlanesState.getHash(), mesh._geometry._state.hash, mesh._material._state.hash, mesh._state.drawHash ].join(";"); let renderer = drawRenderers[hash]; if (!renderer) { renderer = new DrawRenderer(hash, mesh); if (renderer.errors) { console.log(renderer.errors.join("\n")); return null; } drawRenderers[hash] = renderer; stats.memory.programs++; } renderer._useCount++; return renderer; }; DrawRenderer.prototype.put = function () { if (--this._useCount === 0) { ids.removeItem(this.id); if (this._program) { this._program.destroy(); } delete drawRenderers[this._hash]; stats.memory.programs--; } }; DrawRenderer.prototype.webglContextRestored = function () { this._program = null; }; DrawRenderer.prototype.drawMesh = function (frameCtx, mesh) { if (!this._program) { this._allocate(mesh); } const maxTextureUnits = WEBGL_INFO.MAX_TEXTURE_UNITS; const scene = mesh.scene; const material = mesh._material; const gl = scene.canvas.gl; const program = this._program; const meshState = mesh._state; const materialState = mesh._material._state; const geometryState = mesh._geometry._state; const camera = scene.camera; const origin = mesh.origin; const background = meshState.background; if (frameCtx.lastProgramId !== this._program.id) { frameCtx.lastProgramId = this._program.id; if (background) { gl.depthFunc(gl.LEQUAL); } this._bindProgram(frameCtx); } gl.uniformMatrix4fv(this._uViewMatrix, false, origin ? frameCtx.getRTCViewMatrix(meshState.originHash, origin) : camera.viewMatrix); gl.uniformMatrix4fv(this._uViewNormalMatrix, false, camera.viewNormalMatrix); if (meshState.clippable) { const numAllocatedSectionPlanes = scene._sectionPlanesState.getNumAllocatedSectionPlanes(); const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numAllocatedSectionPlanes > 0) { const sectionPlanes = scene._sectionPlanesState.sectionPlanes; const renderFlags = mesh.renderFlags; for (let sectionPlaneIndex = 0; sectionPlaneIndex < numAllocatedSectionPlanes; sectionPlaneIndex++) { const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; if (sectionPlaneUniforms) { if (sectionPlaneIndex < numSectionPlanes) { const active = renderFlags.sectionPlanesActivePerLayer[sectionPlaneIndex]; gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; if (origin) { const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a); gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); } else { gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); } gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); } } else { gl.uniform1i(sectionPlaneUniforms.active, 0); } } } } } if (materialState.id !== this._lastMaterialId) { frameCtx.textureUnit = this._baseTextureUnit; const backfaces = materialState.backfaces; if (frameCtx.backfaces !== backfaces) { if (backfaces) { gl.disable(gl.CULL_FACE); } else { gl.enable(gl.CULL_FACE); } frameCtx.backfaces = backfaces; } const frontface = materialState.frontface; if (frameCtx.frontface !== frontface) { if (frontface) { gl.frontFace(gl.CCW); } else { gl.frontFace(gl.CW); } frameCtx.frontface = frontface; } if (frameCtx.lineWidth !== materialState.lineWidth) { gl.lineWidth(materialState.lineWidth); frameCtx.lineWidth = materialState.lineWidth; } if (this._uPointSize) { gl.uniform1f(this._uPointSize, materialState.pointSize); } switch (materialState.type) { case "LambertMaterial": if (this._uMaterialAmbient) { gl.uniform3fv(this._uMaterialAmbient, materialState.ambient); } if (this._uMaterialColor) { gl.uniform4f(this._uMaterialColor, materialState.color[0], materialState.color[1], materialState.color[2], materialState.alpha); } if (this._uMaterialEmissive) { gl.uniform3fv(this._uMaterialEmissive, materialState.emissive); } break; case "PhongMaterial": if (this._uMaterialShininess) { gl.uniform1f(this._uMaterialShininess, materialState.shininess); } if (this._uMaterialAmbient) { gl.uniform3fv(this._uMaterialAmbient, materialState.ambient); } if (this._uMaterialDiffuse) { gl.uniform3fv(this._uMaterialDiffuse, materialState.diffuse); } if (this._uMaterialSpecular) { gl.uniform3fv(this._uMaterialSpecular, materialState.specular); } if (this._uMaterialEmissive) { gl.uniform3fv(this._uMaterialEmissive, materialState.emissive); } if (this._uAlphaModeCutoff) { gl.uniform4f( this._uAlphaModeCutoff, 1.0 * materialState.alpha, materialState.alphaMode === 1 ? 1.0 : 0.0, materialState.alphaCutoff, 0); } if (material._ambientMap && material._ambientMap._state.texture && this._uMaterialAmbientMap) { program.bindTexture(this._uMaterialAmbientMap, material._ambientMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uMaterialAmbientMapMatrix) { gl.uniformMatrix4fv(this._uMaterialAmbientMapMatrix, false, material._ambientMap._state.matrix); } } if (material._diffuseMap && material._diffuseMap._state.texture && this._uDiffuseMap) { program.bindTexture(this._uDiffuseMap, material._diffuseMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uDiffuseMapMatrix) { gl.uniformMatrix4fv(this._uDiffuseMapMatrix, false, material._diffuseMap._state.matrix); } } if (material._specularMap && material._specularMap._state.texture && this._uSpecularMap) { program.bindTexture(this._uSpecularMap, material._specularMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uSpecularMapMatrix) { gl.uniformMatrix4fv(this._uSpecularMapMatrix, false, material._specularMap._state.matrix); } } if (material._emissiveMap && material._emissiveMap._state.texture && this._uEmissiveMap) { program.bindTexture(this._uEmissiveMap, material._emissiveMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uEmissiveMapMatrix) { gl.uniformMatrix4fv(this._uEmissiveMapMatrix, false, material._emissiveMap._state.matrix); } } if (material._alphaMap && material._alphaMap._state.texture && this._uAlphaMap) { program.bindTexture(this._uAlphaMap, material._alphaMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uAlphaMapMatrix) { gl.uniformMatrix4fv(this._uAlphaMapMatrix, false, material._alphaMap._state.matrix); } } if (material._reflectivityMap && material._reflectivityMap._state.texture && this._uReflectivityMap) { program.bindTexture(this._uReflectivityMap, material._reflectivityMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; if (this._uReflectivityMapMatrix) { gl.uniformMatrix4fv(this._uReflectivityMapMatrix, false, material._reflectivityMap._state.matrix); } } if (material._normalMap && material._normalMap._state.texture && this._uNormalMap) { program.bindTexture(this._uNormalMap, material._normalMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uNormalMapMatrix) { gl.uniformMatrix4fv(this._uNormalMapMatrix, false, material._normalMap._state.matrix); } } if (material._occlusionMap && material._occlusionMap._state.texture && this._uOcclusionMap) { program.bindTexture(this._uOcclusionMap, material._occlusionMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uOcclusionMapMatrix) { gl.uniformMatrix4fv(this._uOcclusionMapMatrix, false, material._occlusionMap._state.matrix); } } if (material._diffuseFresnel) { if (this._uDiffuseFresnelEdgeBias) { gl.uniform1f(this._uDiffuseFresnelEdgeBias, material._diffuseFresnel.edgeBias); } if (this._uDiffuseFresnelCenterBias) { gl.uniform1f(this._uDiffuseFresnelCenterBias, material._diffuseFresnel.centerBias); } if (this._uDiffuseFresnelEdgeColor) { gl.uniform3fv(this._uDiffuseFresnelEdgeColor, material._diffuseFresnel.edgeColor); } if (this._uDiffuseFresnelCenterColor) { gl.uniform3fv(this._uDiffuseFresnelCenterColor, material._diffuseFresnel.centerColor); } if (this._uDiffuseFresnelPower) { gl.uniform1f(this._uDiffuseFresnelPower, material._diffuseFresnel.power); } } if (material._specularFresnel) { if (this._uSpecularFresnelEdgeBias) { gl.uniform1f(this._uSpecularFresnelEdgeBias, material._specularFresnel.edgeBias); } if (this._uSpecularFresnelCenterBias) { gl.uniform1f(this._uSpecularFresnelCenterBias, material._specularFresnel.centerBias); } if (this._uSpecularFresnelEdgeColor) { gl.uniform3fv(this._uSpecularFresnelEdgeColor, material._specularFresnel.edgeColor); } if (this._uSpecularFresnelCenterColor) { gl.uniform3fv(this._uSpecularFresnelCenterColor, material._specularFresnel.centerColor); } if (this._uSpecularFresnelPower) { gl.uniform1f(this._uSpecularFresnelPower, material._specularFresnel.power); } } if (material._alphaFresnel) { if (this._uAlphaFresnelEdgeBias) { gl.uniform1f(this._uAlphaFresnelEdgeBias, material._alphaFresnel.edgeBias); } if (this._uAlphaFresnelCenterBias) { gl.uniform1f(this._uAlphaFresnelCenterBias, material._alphaFresnel.centerBias); } if (this._uAlphaFresnelEdgeColor) { gl.uniform3fv(this._uAlphaFresnelEdgeColor, material._alphaFresnel.edgeColor); } if (this._uAlphaFresnelCenterColor) { gl.uniform3fv(this._uAlphaFresnelCenterColor, material._alphaFresnel.centerColor); } if (this._uAlphaFresnelPower) { gl.uniform1f(this._uAlphaFresnelPower, material._alphaFresnel.power); } } if (material._reflectivityFresnel) { if (this._uReflectivityFresnelEdgeBias) { gl.uniform1f(this._uReflectivityFresnelEdgeBias, material._reflectivityFresnel.edgeBias); } if (this._uReflectivityFresnelCenterBias) { gl.uniform1f(this._uReflectivityFresnelCenterBias, material._reflectivityFresnel.centerBias); } if (this._uReflectivityFresnelEdgeColor) { gl.uniform3fv(this._uReflectivityFresnelEdgeColor, material._reflectivityFresnel.edgeColor); } if (this._uReflectivityFresnelCenterColor) { gl.uniform3fv(this._uReflectivityFresnelCenterColor, material._reflectivityFresnel.centerColor); } if (this._uReflectivityFresnelPower) { gl.uniform1f(this._uReflectivityFresnelPower, material._reflectivityFresnel.power); } } if (material._emissiveFresnel) { if (this._uEmissiveFresnelEdgeBias) { gl.uniform1f(this._uEmissiveFresnelEdgeBias, material._emissiveFresnel.edgeBias); } if (this._uEmissiveFresnelCenterBias) { gl.uniform1f(this._uEmissiveFresnelCenterBias, material._emissiveFresnel.centerBias); } if (this._uEmissiveFresnelEdgeColor) { gl.uniform3fv(this._uEmissiveFresnelEdgeColor, material._emissiveFresnel.edgeColor); } if (this._uEmissiveFresnelCenterColor) { gl.uniform3fv(this._uEmissiveFresnelCenterColor, material._emissiveFresnel.centerColor); } if (this._uEmissiveFresnelPower) { gl.uniform1f(this._uEmissiveFresnelPower, material._emissiveFresnel.power); } } break; case "MetallicMaterial": if (this._uBaseColor) { gl.uniform3fv(this._uBaseColor, materialState.baseColor); } if (this._uMaterialMetallic) { gl.uniform1f(this._uMaterialMetallic, materialState.metallic); } if (this._uMaterialRoughness) { gl.uniform1f(this._uMaterialRoughness, materialState.roughness); } if (this._uMaterialSpecularF0) { gl.uniform1f(this._uMaterialSpecularF0, materialState.specularF0); } if (this._uMaterialEmissive) { gl.uniform3fv(this._uMaterialEmissive, materialState.emissive); } if (this._uAlphaModeCutoff) { gl.uniform4f( this._uAlphaModeCutoff, 1.0 * materialState.alpha, materialState.alphaMode === 1 ? 1.0 : 0.0, materialState.alphaCutoff, 0.0); } const baseColorMap = material._baseColorMap; if (baseColorMap && baseColorMap._state.texture && this._uBaseColorMap) { program.bindTexture(this._uBaseColorMap, baseColorMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uBaseColorMapMatrix) { gl.uniformMatrix4fv(this._uBaseColorMapMatrix, false, baseColorMap._state.matrix); } } const metallicMap = material._metallicMap; if (metallicMap && metallicMap._state.texture && this._uMetallicMap) { program.bindTexture(this._uMetallicMap, metallicMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uMetallicMapMatrix) { gl.uniformMatrix4fv(this._uMetallicMapMatrix, false, metallicMap._state.matrix); } } const roughnessMap = material._roughnessMap; if (roughnessMap && roughnessMap._state.texture && this._uRoughnessMap) { program.bindTexture(this._uRoughnessMap, roughnessMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uRoughnessMapMatrix) { gl.uniformMatrix4fv(this._uRoughnessMapMatrix, false, roughnessMap._state.matrix); } } const metallicRoughnessMap = material._metallicRoughnessMap; if (metallicRoughnessMap && metallicRoughnessMap._state.texture && this._uMetallicRoughnessMap) { program.bindTexture(this._uMetallicRoughnessMap, metallicRoughnessMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uMetallicRoughnessMapMatrix) { gl.uniformMatrix4fv(this._uMetallicRoughnessMapMatrix, false, metallicRoughnessMap._state.matrix); } } var emissiveMap = material._emissiveMap; if (emissiveMap && emissiveMap._state.texture && this._uEmissiveMap) { program.bindTexture(this._uEmissiveMap, emissiveMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uEmissiveMapMatrix) { gl.uniformMatrix4fv(this._uEmissiveMapMatrix, false, emissiveMap._state.matrix); } } var occlusionMap = material._occlusionMap; if (occlusionMap && material._occlusionMap._state.texture && this._uOcclusionMap) { program.bindTexture(this._uOcclusionMap, occlusionMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uOcclusionMapMatrix) { gl.uniformMatrix4fv(this._uOcclusionMapMatrix, false, occlusionMap._state.matrix); } } var alphaMap = material._alphaMap; if (alphaMap && alphaMap._state.texture && this._uAlphaMap) { program.bindTexture(this._uAlphaMap, alphaMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uAlphaMapMatrix) { gl.uniformMatrix4fv(this._uAlphaMapMatrix, false, alphaMap._state.matrix); } } var normalMap = material._normalMap; if (normalMap && normalMap._state.texture && this._uNormalMap) { program.bindTexture(this._uNormalMap, normalMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uNormalMapMatrix) { gl.uniformMatrix4fv(this._uNormalMapMatrix, false, normalMap._state.matrix); } } break; case "SpecularMaterial": if (this._uMaterialDiffuse) { gl.uniform3fv(this._uMaterialDiffuse, materialState.diffuse); } if (this._uMaterialSpecular) { gl.uniform3fv(this._uMaterialSpecular, materialState.specular); } if (this._uMaterialGlossiness) { gl.uniform1f(this._uMaterialGlossiness, materialState.glossiness); } if (this._uMaterialReflectivity) { gl.uniform1f(this._uMaterialReflectivity, materialState.reflectivity); } if (this._uMaterialEmissive) { gl.uniform3fv(this._uMaterialEmissive, materialState.emissive); } if (this._uAlphaModeCutoff) { gl.uniform4f( this._uAlphaModeCutoff, 1.0 * materialState.alpha, materialState.alphaMode === 1 ? 1.0 : 0.0, materialState.alphaCutoff, 0.0); } const diffuseMap = material._diffuseMap; if (diffuseMap && diffuseMap._state.texture && this._uDiffuseMap) { program.bindTexture(this._uDiffuseMap, diffuseMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uDiffuseMapMatrix) { gl.uniformMatrix4fv(this._uDiffuseMapMatrix, false, diffuseMap._state.matrix); } } const specularMap = material._specularMap; if (specularMap && specularMap._state.texture && this._uSpecularMap) { program.bindTexture(this._uSpecularMap, specularMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uSpecularMapMatrix) { gl.uniformMatrix4fv(this._uSpecularMapMatrix, false, specularMap._state.matrix); } } const glossinessMap = material._glossinessMap; if (glossinessMap && glossinessMap._state.texture && this._uGlossinessMap) { program.bindTexture(this._uGlossinessMap, glossinessMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uGlossinessMapMatrix) { gl.uniformMatrix4fv(this._uGlossinessMapMatrix, false, glossinessMap._state.matrix); } } const specularGlossinessMap = material._specularGlossinessMap; if (specularGlossinessMap && specularGlossinessMap._state.texture && this._uSpecularGlossinessMap) { program.bindTexture(this._uSpecularGlossinessMap, specularGlossinessMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uSpecularGlossinessMapMatrix) { gl.uniformMatrix4fv(this._uSpecularGlossinessMapMatrix, false, specularGlossinessMap._state.matrix); } } var emissiveMap = material._emissiveMap; if (emissiveMap && emissiveMap._state.texture && this._uEmissiveMap) { program.bindTexture(this._uEmissiveMap, emissiveMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uEmissiveMapMatrix) { gl.uniformMatrix4fv(this._uEmissiveMapMatrix, false, emissiveMap._state.matrix); } } var occlusionMap = material._occlusionMap; if (occlusionMap && occlusionMap._state.texture && this._uOcclusionMap) { program.bindTexture(this._uOcclusionMap, occlusionMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uOcclusionMapMatrix) { gl.uniformMatrix4fv(this._uOcclusionMapMatrix, false, occlusionMap._state.matrix); } } var alphaMap = material._alphaMap; if (alphaMap && alphaMap._state.texture && this._uAlphaMap) { program.bindTexture(this._uAlphaMap, alphaMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uAlphaMapMatrix) { gl.uniformMatrix4fv(this._uAlphaMapMatrix, false, alphaMap._state.matrix); } } var normalMap = material._normalMap; if (normalMap && normalMap._state.texture && this._uNormalMap) { program.bindTexture(this._uNormalMap, normalMap._state.texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; if (this._uNormalMapMatrix) { gl.uniformMatrix4fv(this._uNormalMapMatrix, false, normalMap._state.matrix); } } break; } this._lastMaterialId = materialState.id; } gl.uniformMatrix4fv(this._uModelMatrix, gl.FALSE, mesh.worldMatrix); if (this._uModelNormalMatrix) { gl.uniformMatrix4fv(this._uModelNormalMatrix, gl.FALSE, mesh.worldNormalMatrix); } if (this._uClippable) { gl.uniform1i(this._uClippable, meshState.clippable); } if (this._uColorize) { const colorize = meshState.colorize; const lastColorize = this._lastColorize; if (lastColorize[0] !== colorize[0] || lastColorize[1] !== colorize[1] || lastColorize[2] !== colorize[2] || lastColorize[3] !== colorize[3]) { gl.uniform4fv(this._uColorize, colorize); lastColorize[0] = colorize[0]; lastColorize[1] = colorize[1]; lastColorize[2] = colorize[2]; lastColorize[3] = colorize[3]; } } gl.uniform3fv(this._uOffset, meshState.offset); // Bind VBOs if (geometryState.id !== this._lastGeometryId) { if (this._uPositionsDecodeMatrix) { gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometryState.positionsDecodeMatrix); } if (this._uUVDecodeMatrix) { gl.uniformMatrix3fv(this._uUVDecodeMatrix, false, geometryState.uvDecodeMatrix); } if (this._aPosition) { this._aPosition.bindArrayBuffer(geometryState.positionsBuf); frameCtx.bindArray++; } if (this._aNormal) { this._aNormal.bindArrayBuffer(geometryState.normalsBuf); frameCtx.bindArray++; } if (this._aUV) { this._aUV.bindArrayBuffer(geometryState.uvBuf); frameCtx.bindArray++; } if (this._aColor) { this._aColor.bindArrayBuffer(geometryState.colorsBuf); frameCtx.bindArray++; } if (this._aFlags) { this._aFlags.bindArrayBuffer(geometryState.flagsBuf); frameCtx.bindArray++; } if (geometryState.indicesBuf) { geometryState.indicesBuf.bind(); frameCtx.bindArray++; } this._lastGeometryId = geometryState.id; } // Draw (indices bound in prev step) if (geometryState.indicesBuf) { gl.drawElements(geometryState.primitive, geometryState.indicesBuf.numItems, geometryState.indicesBuf.itemType, 0); frameCtx.drawElements++; } else if (geometryState.positions) { gl.drawArrays(gl.TRIANGLES, 0, geometryState.positions.numItems); frameCtx.drawArrays++; } if (background) { gl.depthFunc(gl.LESS); } }; DrawRenderer.prototype._allocate = function (mesh) { const scene = mesh.scene; const gl = scene.canvas.gl; const material = mesh._material; const lightsState = scene._lightsState; const sectionPlanesState = scene._sectionPlanesState; const materialState = mesh._material._state; this._program = new Program(gl, this._shaderSource); if (this._program.errors) { this.errors = this._program.errors; return; } const program = this._program; this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); this._uUVDecodeMatrix = program.getLocation("uvDecodeMatrix"); this._uModelMatrix = program.getLocation("modelMatrix"); this._uModelNormalMatrix = program.getLocation("modelNormalMatrix"); this._uViewMatrix = program.getLocation("viewMatrix"); this._uViewNormalMatrix = program.getLocation("viewNormalMatrix"); this._uProjMatrix = program.getLocation("projMatrix"); this._uGammaFactor = program.getLocation("gammaFactor"); this._uLightAmbient = []; this._uLightColor = []; this._uLightDir = []; this._uLightPos = []; this._uLightAttenuation = []; this._uShadowViewMatrix = []; this._uShadowProjMatrix = []; if (scene.logarithmicDepthBufferEnabled) { this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } const lights = lightsState.lights; let light; for (var i = 0, len = lights.length; i < len; i++) { light = lights[i]; switch (light.type) { case "ambient": this._uLightAmbient[i] = program.getLocation("lightAmbient"); break; case "dir": this._uLightColor[i] = program.getLocation("lightColor" + i); this._uLightPos[i] = null; this._uLightDir[i] = program.getLocation("lightDir" + i); break; case "point": this._uLightColor[i] = program.getLocation("lightColor" + i); this._uLightPos[i] = program.getLocation("lightPos" + i); this._uLightDir[i] = null; this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); break; case "spot": this._uLightColor[i] = program.getLocation("lightColor" + i); this._uLightPos[i] = program.getLocation("lightPos" + i); this._uLightDir[i] = program.getLocation("lightDir" + i); this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); break; } if (light.castsShadow) { this._uShadowViewMatrix[i] = program.getLocation("shadowViewMatrix" + i); this._uShadowProjMatrix[i] = program.getLocation("shadowProjMatrix" + i); } } if (lightsState.lightMaps.length > 0) { this._uLightMap = "lightMap"; } if (lightsState.reflectionMaps.length > 0) { this._uReflectionMap = "reflectionMap"; } this._uSectionPlanes = []; const sectionPlanes = sectionPlanesState.sectionPlanes; for (var i = 0, len = sectionPlanes.length; i < len; i++) { this._uSectionPlanes.push({ active: program.getLocation("sectionPlaneActive" + i), pos: program.getLocation("sectionPlanePos" + i), dir: program.getLocation("sectionPlaneDir" + i) }); } this._uPointSize = program.getLocation("pointSize"); switch (materialState.type) { case "LambertMaterial": this._uMaterialColor = program.getLocation("materialColor"); this._uMaterialEmissive = program.getLocation("materialEmissive"); this._uAlphaModeCutoff = program.getLocation("materialAlphaModeCutoff"); break; case "PhongMaterial": this._uMaterialAmbient = program.getLocation("materialAmbient"); this._uMaterialDiffuse = program.getLocation("materialDiffuse"); this._uMaterialSpecular = program.getLocation("materialSpecular"); this._uMaterialEmissive = program.getLocation("materialEmissive"); this._uAlphaModeCutoff = program.getLocation("materialAlphaModeCutoff"); this._uMaterialShininess = program.getLocation("materialShininess"); if (material._ambientMap) { this._uMaterialAmbientMap = "ambientMap"; this._uMaterialAmbientMapMatrix = program.getLocation("ambientMapMatrix"); } if (material._diffuseMap) { this._uDiffuseMap = "diffuseMap"; this._uDiffuseMapMatrix = program.getLocation("diffuseMapMatrix"); } if (material._specularMap) { this._uSpecularMap = "specularMap"; this._uSpecularMapMatrix = program.getLocation("specularMapMatrix"); } if (material._emissiveMap) { this._uEmissiveMap = "emissiveMap"; this._uEmissiveMapMatrix = program.getLocation("emissiveMapMatrix"); } if (material._alphaMap) { this._uAlphaMap = "alphaMap"; this._uAlphaMapMatrix = program.getLocation("alphaMapMatrix"); } if (material._reflectivityMap) { this._uReflectivityMap = "reflectivityMap"; this._uReflectivityMapMatrix = program.getLocation("reflectivityMapMatrix"); } if (material._normalMap) { this._uNormalMap = "normalMap"; this._uNormalMapMatrix = program.getLocation("normalMapMatrix"); } if (material._occlusionMap) { this._uOcclusionMap = "occlusionMap"; this._uOcclusionMapMatrix = program.getLocation("occlusionMapMatrix"); } if (material._diffuseFresnel) { this._uDiffuseFresnelEdgeBias = program.getLocation("diffuseFresnelEdgeBias"); this._uDiffuseFresnelCenterBias = program.getLocation("diffuseFresnelCenterBias"); this._uDiffuseFresnelEdgeColor = program.getLocation("diffuseFresnelEdgeColor"); this._uDiffuseFresnelCenterColor = program.getLocation("diffuseFresnelCenterColor"); this._uDiffuseFresnelPower = program.getLocation("diffuseFresnelPower"); } if (material._specularFresnel) { this._uSpecularFresnelEdgeBias = program.getLocation("specularFresnelEdgeBias"); this._uSpecularFresnelCenterBias = program.getLocation("specularFresnelCenterBias"); this._uSpecularFresnelEdgeColor = program.getLocation("specularFresnelEdgeColor"); this._uSpecularFresnelCenterColor = program.getLocation("specularFresnelCenterColor"); this._uSpecularFresnelPower = program.getLocation("specularFresnelPower"); } if (material._alphaFresnel) { this._uAlphaFresnelEdgeBias = program.getLocation("alphaFresnelEdgeBias"); this._uAlphaFresnelCenterBias = program.getLocation("alphaFresnelCenterBias"); this._uAlphaFresnelEdgeColor = program.getLocation("alphaFresnelEdgeColor"); this._uAlphaFresnelCenterColor = program.getLocation("alphaFresnelCenterColor"); this._uAlphaFresnelPower = program.getLocation("alphaFresnelPower"); } if (material._reflectivityFresnel) { this._uReflectivityFresnelEdgeBias = program.getLocation("reflectivityFresnelEdgeBias"); this._uReflectivityFresnelCenterBias = program.getLocation("reflectivityFresnelCenterBias"); this._uReflectivityFresnelEdgeColor = program.getLocation("reflectivityFresnelEdgeColor"); this._uReflectivityFresnelCenterColor = program.getLocation("reflectivityFresnelCenterColor"); this._uReflectivityFresnelPower = program.getLocation("reflectivityFresnelPower"); } if (material._emissiveFresnel) { this._uEmissiveFresnelEdgeBias = program.getLocation("emissiveFresnelEdgeBias"); this._uEmissiveFresnelCenterBias = program.getLocation("emissiveFresnelCenterBias"); this._uEmissiveFresnelEdgeColor = program.getLocation("emissiveFresnelEdgeColor"); this._uEmissiveFresnelCenterColor = program.getLocation("emissiveFresnelCenterColor"); this._uEmissiveFresnelPower = program.getLocation("emissiveFresnelPower"); } break; case "MetallicMaterial": this._uBaseColor = program.getLocation("materialBaseColor"); this._uMaterialMetallic = program.getLocation("materialMetallic"); this._uMaterialRoughness = program.getLocation("materialRoughness"); this._uMaterialSpecularF0 = program.getLocation("materialSpecularF0"); this._uMaterialEmissive = program.getLocation("materialEmissive"); this._uAlphaModeCutoff = program.getLocation("materialAlphaModeCutoff"); if (material._baseColorMap) { this._uBaseColorMap = "baseColorMap"; this._uBaseColorMapMatrix = program.getLocation("baseColorMapMatrix"); } if (material._metallicMap) { this._uMetallicMap = "metallicMap"; this._uMetallicMapMatrix = program.getLocation("metallicMapMatrix"); } if (material._roughnessMap) { this._uRoughnessMap = "roughnessMap"; this._uRoughnessMapMatrix = program.getLocation("roughnessMapMatrix"); } if (material._metallicRoughnessMap) { this._uMetallicRoughnessMap = "metallicRoughnessMap"; this._uMetallicRoughnessMapMatrix = program.getLocation("metallicRoughnessMapMatrix"); } if (material._emissiveMap) { this._uEmissiveMap = "emissiveMap"; this._uEmissiveMapMatrix = program.getLocation("emissiveMapMatrix"); } if (material._occlusionMap) { this._uOcclusionMap = "occlusionMap"; this._uOcclusionMapMatrix = program.getLocation("occlusionMapMatrix"); } if (material._alphaMap) { this._uAlphaMap = "alphaMap"; this._uAlphaMapMatrix = program.getLocation("alphaMapMatrix"); } if (material._normalMap) { this._uNormalMap = "normalMap"; this._uNormalMapMatrix = program.getLocation("normalMapMatrix"); } break; case "SpecularMaterial": this._uMaterialDiffuse = program.getLocation("materialDiffuse"); this._uMaterialSpecular = program.getLocation("materialSpecular"); this._uMaterialGlossiness = program.getLocation("materialGlossiness"); this._uMaterialReflectivity = program.getLocation("reflectivityFresnel"); this._uMaterialEmissive = program.getLocation("materialEmissive"); this._uAlphaModeCutoff = program.getLocation("materialAlphaModeCutoff"); if (material._diffuseMap) { this._uDiffuseMap = "diffuseMap"; this._uDiffuseMapMatrix = program.getLocation("diffuseMapMatrix"); } if (material._specularMap) { this._uSpecularMap = "specularMap"; this._uSpecularMapMatrix = program.getLocation("specularMapMatrix"); } if (material._glossinessMap) { this._uGlossinessMap = "glossinessMap"; this._uGlossinessMapMatrix = program.getLocation("glossinessMapMatrix"); } if (material._specularGlossinessMap) { this._uSpecularGlossinessMap = "materialSpecularGlossinessMap"; this._uSpecularGlossinessMapMatrix = program.getLocation("materialSpecularGlossinessMapMatrix"); } if (material._emissiveMap) { this._uEmissiveMap = "emissiveMap"; this._uEmissiveMapMatrix = program.getLocation("emissiveMapMatrix"); } if (material._occlusionMap) { this._uOcclusionMap = "occlusionMap"; this._uOcclusionMapMatrix = program.getLocation("occlusionMapMatrix"); } if (material._alphaMap) { this._uAlphaMap = "alphaMap"; this._uAlphaMapMatrix = program.getLocation("alphaMapMatrix"); } if (material._normalMap) { this._uNormalMap = "normalMap"; this._uNormalMapMatrix = program.getLocation("normalMapMatrix"); } break; } this._aPosition = program.getAttribute("position"); this._aNormal = program.getAttribute("normal"); this._aUV = program.getAttribute("uv"); this._aColor = program.getAttribute("color"); this._aFlags = program.getAttribute("flags"); this._uClippable = program.getLocation("clippable"); this._uColorize = program.getLocation("colorize"); this._uOffset = program.getLocation("offset"); this._lastMaterialId = null; this._lastVertexBufsId = null; this._lastGeometryId = null; this._lastColorize = new Float32Array(4); this._baseTextureUnit = 0; }; DrawRenderer.prototype._bindProgram = function (frameCtx) { const maxTextureUnits = WEBGL_INFO.MAX_TEXTURE_UNITS; const scene = this._scene; const gl = scene.canvas.gl; const lightsState = scene._lightsState; const project = scene.camera.project; let light; const program = this._program; program.bind(); frameCtx.useProgram++; frameCtx.textureUnit = 0; this._lastMaterialId = null; this._lastVertexBufsId = null; this._lastGeometryId = null; this._lastColorize[0] = -1; this._lastColorize[1] = -1; this._lastColorize[2] = -1; this._lastColorize[3] = -1; gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); if (scene.logarithmicDepthBufferEnabled) { const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); } for (var i = 0, len = lightsState.lights.length; i < len; i++) { light = lightsState.lights[i]; if (this._uLightAmbient[i]) { gl.uniform4f(this._uLightAmbient[i], light.color[0], light.color[1], light.color[2], light.intensity); } else { if (this._uLightColor[i]) { gl.uniform4f(this._uLightColor[i], light.color[0], light.color[1], light.color[2], light.intensity); } if (this._uLightPos[i]) { gl.uniform3fv(this._uLightPos[i], light.pos); if (this._uLightAttenuation[i]) { gl.uniform1f(this._uLightAttenuation[i], light.attenuation); } } if (this._uLightDir[i]) { gl.uniform3fv(this._uLightDir[i], light.dir); } if (light.castsShadow) { if (this._uShadowViewMatrix[i]) { gl.uniformMatrix4fv(this._uShadowViewMatrix[i], false, light.getShadowViewMatrix()); } if (this._uShadowProjMatrix[i]) { gl.uniformMatrix4fv(this._uShadowProjMatrix[i], false, light.getShadowProjMatrix()); } const shadowRenderBuf = light.getShadowRenderBuf(); if (shadowRenderBuf) { program.bindTexture("shadowMap" + i, shadowRenderBuf.getTexture(), frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; } } } } if (lightsState.lightMaps.length > 0 && lightsState.lightMaps[0].texture && this._uLightMap) { program.bindTexture(this._uLightMap, lightsState.lightMaps[0].texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; } if (lightsState.reflectionMaps.length > 0 && lightsState.reflectionMaps[0].texture && this._uReflectionMap) { program.bindTexture(this._uReflectionMap, lightsState.reflectionMaps[0].texture, frameCtx.textureUnit); frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; frameCtx.bindTexture++; } if (this._uGammaFactor) { gl.uniform1f(this._uGammaFactor, scene.gammaFactor); } this._baseTextureUnit = frameCtx.textureUnit; }; export {DrawRenderer};