UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

145 lines (113 loc) 4.32 kB
import { DoubleSide, HalfFloatType, Mesh, MeshNormalMaterial, NearestFilter, RGBAFormat, Scene, Vector2, WebGLMultisampleRenderTarget } from "three"; import { StandardFrameBuffers } from "../../../StandardFrameBuffers.js"; import { three_setSceneAutoUpdate } from "../../../three/three_setSceneAutoUpdate.js"; import { ThreeBypassRenderer } from "../../utils/ThreeBypassRenderer.js"; import { FrameBuffer } from "../FrameBuffer.js"; export class NormalFrameBuffer extends FrameBuffer { constructor(id) { super(id); this.dependencies.push(StandardFrameBuffers.ColorAndDepth); } initialize(renderer) { super.initialize(renderer); // enable floating texture extension renderer.extensions.get('EXT_color_buffer_float'); const size = new Vector2(); renderer.getSize(size); const target = new WebGLMultisampleRenderTarget(size.x, size.y, { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat, // note, three.js required RGBA render texture, even though RGB would do here type: HalfFloatType, depthBuffer: true, stencilBuffer: false, generateMipmaps: false }); target.texture.internalFormat = 'RGBA16F'; this.renderTarget = target; this.__material_static = new MeshNormalMaterial({ depthWrite: true }); this.__material_skinned = new MeshNormalMaterial({ depthWrite: true }); //SET material to double-sided, to support double-sided materials. This is an overkill, and will hurt performance a little. A full-blown material cache might be a better solution in the long run this.__material_static.side = DoubleSide; this.__material_skinned.side = DoubleSide; const scene = new Scene(); /** * @type {Scene} * @private */ this.__scene = scene; three_setSceneAutoUpdate(scene, false); scene.matrixAutoUpdate = false; scene.matrixWorldNeedsUpdate = false; } /** * * @param {THREE.Mesh|{customNormalMaterial:THREE.Material}} mesh * @return {MeshNormalMaterial} * @private */ __bindMaterial(mesh) { let target_material; if (mesh.customNormalMaterial !== undefined) { target_material = mesh.customNormalMaterial; } else { /** * * @type {Material} */ const source_material = mesh.material; // TODO take normal map into account if (mesh.isSkinnedMesh) { target_material = this.__material_skinned; } else { target_material = this.__material_static; } if (source_material !== undefined) { // assign normal map and color map if (source_material.alphaTest > 0) { target_material.map = source_material.map; } else { target_material.map = null; } target_material.normalMap = source_material.normalMap; } } return target_material; } /** * * @see {@link OutlineRenderer} for details on this technique * @param renderer * @param camera * @param scene * @param dependencies */ render(renderer, camera, scene, dependencies) { this.__renderer = renderer; // read current state const _state_rt = renderer.getRenderTarget(); renderer.setRenderTarget(this.renderTarget); renderer.clear(true, true, false); ThreeBypassRenderer.INSTANCE.build_scene({ scene: this.__scene, input: scene.children, input_size: scene.children.length, object_filter: object3D => object3D.visible, material_extractor: this.__bindMaterial, material_extractor_context: this }); renderer.render(this.__scene, camera); // restore state renderer.setRenderTarget(_state_rt); } }