@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
131 lines (106 loc) • 4.11 kB
JavaScript
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;
}
}