UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

131 lines (106 loc) 4.11 kB
import { AbstractMaterialTransformer } from "../../../material/manager/AbstractMaterialTransformer.js"; import { composeCompile } from "../../../material/composeCompile.js"; import { GLSL3, Vector2 } from "three"; import { isLitMaterial } from "./isLitMaterial.js"; import { fp_build_fragment_shader } from "../materials/fp_build_fragment_shader.js"; import { fp_build_vertex_shader } from "../materials/fp_build_vertex_shader.js"; import { fp_build_vertex_lighting_shared } from "../materials/fp_build_vertex_lighting_shared.js"; /** * @readonly * @type {string} */ const PROPERTY_TRANSFORMER_MARKER = '@forward-plus-material-transformer'; export class MaterialTransformer extends AbstractMaterialTransformer { /** * * @param {LightManager} light_manager * @param {Vector2} resolution */ constructor({ light_manager, resolution }) { super(); this.__light_manager = light_manager; this.__resolution = resolution; const uniforms = this.__common_uniforms = { fp_t_light_tiles: { type: 't', value: light_manager.getTextureClusters() }, fp_t_light_lookup: { type: 't', value: light_manager.getTextureLookup() }, fp_t_light_data: { type: 't', value: light_manager.getTextureData() }, fp_t_decal_atlas: { type: 't', value: light_manager.getTextureDecalAtlas() }, fp_t_decal_atlas_resolution: { type: 't', value: new Vector2(1, 1) }, fp_f_camera_near: { type: 'f', value: 0 }, fp_f_camera_far: { type: 'f', value: 0 }, fp_resolution: { type: 'v2', value: resolution } }; this.__on_before_compile = (shader) => { Object.assign(shader.uniforms, uniforms); shader.glslVersion = GLSL3; if (shader.defines.LIGHTING_VERTEX_ONLY === true) { // Lambertial vertex-space lighting shader.vertexShader = fp_build_vertex_lighting_shared(shader.vertexShader); } else { shader.vertexShader = fp_build_vertex_shader(shader.vertexShader); shader.fragmentShader = fp_build_fragment_shader(shader.fragmentShader); } }; } /** * * @param {CameraView} c */ updateCamera(c) { const us = this.__common_uniforms; us.fp_f_camera_far.value = c.camera.far; us.fp_f_camera_near.value = c.camera.near; // TODO move to "onbefore render" us.fp_t_decal_atlas_resolution.value.set( us.fp_t_decal_atlas.value.image.width, us.fp_t_decal_atlas.value.image.height, ); } transform(source) { if (source.hasOwnProperty(PROPERTY_TRANSFORMER_MARKER)) { // already transformed if (source[PROPERTY_TRANSFORMER_MARKER] !== this) { throw new Error('The material is already transformed, but is associated with a different transformer instance'); } else { return source; } } let result = source; if (isLitMaterial(source)) { result = source.clone(); // inherit uniforms directly if (source.isShaderMaterial) { // TODO use Proxy result.uniforms = Object.assign({}, source.uniforms); result.defines = Object.assign({}, source.defines); } result.onBeforeCompile = composeCompile(source.onBeforeCompile, this.__on_before_compile); result[PROPERTY_TRANSFORMER_MARKER] = this; } return result; } }