UNPKG

three-stdlib

Version:

stand-alone library of threejs examples

190 lines (189 loc) 9.15 kB
"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const THREE = require("three"); const potpack = require("potpack"); const uv1 = require("../_polyfill/uv1.cjs"); class ProgressiveLightMap { constructor(renderer, res = 1024) { this.renderer = renderer; this.res = res; this.lightMapContainers = []; this.compiled = false; this.scene = new THREE.Scene(); this.scene.background = null; this.tinyTarget = new THREE.WebGLRenderTarget(1, 1); this.buffer1Active = false; this.firstUpdate = true; this.warned = false; const format = /(Android|iPad|iPhone|iPod)/g.test(navigator.userAgent) ? alfFloatType : THREE.FloatType; this.progressiveLightMap1 = new THREE.WebGLRenderTarget(this.res, this.res, { type: format }); this.progressiveLightMap2 = new THREE.WebGLRenderTarget(this.res, this.res, { type: format }); this.uvMat = new THREE.MeshPhongMaterial(); this.uvMat.uniforms = {}; this.uvMat.onBeforeCompile = (shader) => { shader.vertexShader = "#define USE_LIGHTMAP\n" + shader.vertexShader.slice(0, -1) + ` gl_Position = vec4((${uv1.UV1} - 0.5) * 2.0, 1.0, 1.0); }`; const bodyStart = shader.fragmentShader.indexOf("void main() {"); shader.fragmentShader = `varying vec2 v${uv1.UV1 === "uv1" ? uv1.UV1 : "Uv2"}; ` + shader.fragmentShader.slice(0, bodyStart) + " uniform sampler2D previousShadowMap;\n uniform float averagingWindow;\n" + shader.fragmentShader.slice(bodyStart - 1, -1) + ` vec3 texelOld = texture2D(previousShadowMap, v${uv1.UV1 === "uv1" ? uv1.UV1 : "Uv2"}).rgb; gl_FragColor.rgb = mix(texelOld, gl_FragColor.rgb, 1.0/averagingWindow); }`; shader.uniforms.previousShadowMap = { value: this.progressiveLightMap1.texture }; shader.uniforms.averagingWindow = { value: 100 }; this.uvMat.uniforms = shader.uniforms; this.uvMat.userData.shader = shader; this.compiled = true; }; } /** * Sets these objects' materials' lightmaps and modifies their uv1's. * @param {Object3D} objects An array of objects and lights to set up your lightmap. */ addObjectsToLightMap(objects) { this.uv_boxes = []; const padding = 3 / this.res; for (let ob = 0; ob < objects.length; ob++) { const object = objects[ob]; if (object.isLight) { this.scene.attach(object); continue; } if (!object.geometry.hasAttribute("uv")) { console.warn("All lightmap objects need UVs!"); continue; } if (this.blurringPlane == null) { this._initializeBlurPlane(this.res, this.progressiveLightMap1); } object.material.lightMap = this.progressiveLightMap2.texture; object.material.dithering = true; object.castShadow = true; object.receiveShadow = true; object.renderOrder = 1e3 + ob; this.uv_boxes.push({ w: 1 + padding * 2, h: 1 + padding * 2, index: ob }); this.lightMapContainers.push({ basicMat: object.material, object }); this.compiled = false; } const dimensions = potpack(this.uv_boxes); this.uv_boxes.forEach((box) => { const uv1$1 = objects[box.index].geometry.getAttribute("uv").clone(); for (let i = 0; i < uv1$1.array.length; i += uv1$1.itemSize) { uv1$1.array[i] = (uv1$1.array[i] + box.x + padding) / dimensions.w; uv1$1.array[i + 1] = (uv1$1.array[i + 1] + box.y + padding) / dimensions.h; } objects[box.index].geometry.setAttribute(uv1.UV1, uv1$1); objects[box.index].geometry.getAttribute(uv1.UV1).needsUpdate = true; }); } /** * This function renders each mesh one at a time into their respective surface maps * @param {Camera} camera Standard Rendering Camera * @param {number} blendWindow When >1, samples will accumulate over time. * @param {boolean} blurEdges Whether to fix UV Edges via blurring */ update(camera, blendWindow = 100, blurEdges = true) { if (this.blurringPlane == null) { return; } const oldTarget = this.renderer.getRenderTarget(); this.blurringPlane.visible = blurEdges; for (let l = 0; l < this.lightMapContainers.length; l++) { this.lightMapContainers[l].object.oldScene = this.lightMapContainers[l].object.parent; this.scene.attach(this.lightMapContainers[l].object); } if (this.firstUpdate) { this.renderer.setRenderTarget(this.tinyTarget); this.renderer.render(this.scene, camera); this.firstUpdate = false; } for (let l = 0; l < this.lightMapContainers.length; l++) { this.uvMat.uniforms.averagingWindow = { value: blendWindow }; this.lightMapContainers[l].object.material = this.uvMat; this.lightMapContainers[l].object.oldFrustumCulled = this.lightMapContainers[l].object.frustumCulled; this.lightMapContainers[l].object.frustumCulled = false; } const activeMap = this.buffer1Active ? this.progressiveLightMap1 : this.progressiveLightMap2; const inactiveMap = this.buffer1Active ? this.progressiveLightMap2 : this.progressiveLightMap1; this.renderer.setRenderTarget(activeMap); this.uvMat.uniforms.previousShadowMap = { value: inactiveMap.texture }; this.blurringPlane.material.uniforms.previousShadowMap = { value: inactiveMap.texture }; this.buffer1Active = !this.buffer1Active; this.renderer.render(this.scene, camera); for (let l = 0; l < this.lightMapContainers.length; l++) { this.lightMapContainers[l].object.frustumCulled = this.lightMapContainers[l].object.oldFrustumCulled; this.lightMapContainers[l].object.material = this.lightMapContainers[l].basicMat; this.lightMapContainers[l].object.oldScene.attach(this.lightMapContainers[l].object); } this.renderer.setRenderTarget(oldTarget); } /** DEBUG * Draw the lightmap in the main scene. Call this after adding the objects to it. * @param {boolean} visible Whether the debug plane should be visible * @param {Vector3} position Where the debug plane should be drawn */ showDebugLightmap(visible, position = void 0) { if (this.lightMapContainers.length == 0) { if (!this.warned) { console.warn("Call this after adding the objects!"); this.warned = true; } return; } if (this.labelMesh == null) { this.labelMaterial = new THREE.MeshBasicMaterial({ map: this.progressiveLightMap1.texture, side: THREE.DoubleSide }); this.labelPlane = new THREE.PlaneGeometry(100, 100); this.labelMesh = new THREE.Mesh(this.labelPlane, this.labelMaterial); this.labelMesh.position.y = 250; this.lightMapContainers[0].object.parent.add(this.labelMesh); } if (position != void 0) { this.labelMesh.position.copy(position); } this.labelMesh.visible = visible; } /** * INTERNAL Creates the Blurring Plane * @param {number} res The square resolution of this object's lightMap. * @param {WebGLRenderTexture} lightMap The lightmap to initialize the plane with. */ _initializeBlurPlane(res, lightMap = null) { const blurMaterial = new THREE.MeshBasicMaterial(); blurMaterial.uniforms = { previousShadowMap: { value: null }, pixelOffset: { value: 1 / res }, polygonOffset: true, polygonOffsetFactor: -1, polygonOffsetUnits: 3 }; blurMaterial.onBeforeCompile = (shader) => { shader.vertexShader = "#define USE_UV\n" + shader.vertexShader.slice(0, -1) + " gl_Position = vec4((uv - 0.5) * 2.0, 1.0, 1.0); }"; const bodyStart = shader.fragmentShader.indexOf("void main() {"); shader.fragmentShader = "#define USE_UV\n" + shader.fragmentShader.slice(0, bodyStart) + " uniform sampler2D previousShadowMap;\n uniform float pixelOffset;\n" + shader.fragmentShader.slice(bodyStart - 1, -1) + ` gl_FragColor.rgb = ( texture2D(previousShadowMap, vUv + vec2( pixelOffset, 0.0 )).rgb + texture2D(previousShadowMap, vUv + vec2( 0.0 , pixelOffset)).rgb + texture2D(previousShadowMap, vUv + vec2( 0.0 , -pixelOffset)).rgb + texture2D(previousShadowMap, vUv + vec2(-pixelOffset, 0.0 )).rgb + texture2D(previousShadowMap, vUv + vec2( pixelOffset, pixelOffset)).rgb + texture2D(previousShadowMap, vUv + vec2(-pixelOffset, pixelOffset)).rgb + texture2D(previousShadowMap, vUv + vec2( pixelOffset, -pixelOffset)).rgb + texture2D(previousShadowMap, vUv + vec2(-pixelOffset, -pixelOffset)).rgb)/8.0; }`; shader.uniforms.previousShadowMap = { value: lightMap.texture }; shader.uniforms.pixelOffset = { value: 0.5 / res }; blurMaterial.uniforms = shader.uniforms; blurMaterial.userData.shader = shader; this.compiled = true; }; this.blurringPlane = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), blurMaterial); this.blurringPlane.name = "Blurring Plane"; this.blurringPlane.frustumCulled = false; this.blurringPlane.renderOrder = 0; this.blurringPlane.material.depthWrite = false; this.scene.add(this.blurringPlane); } } exports.ProgressiveLightMap = ProgressiveLightMap; //# sourceMappingURL=ProgressiveLightmap.cjs.map