@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
146 lines (113 loc) • 4.65 kB
JavaScript
import { Mesh, OrthographicCamera, Scene } from "three";
import { assert } from "../../../../core/assert.js";
import { isValueBetweenInclusive } from "../../../../core/math/interval/isValueBetweenInclusive.js";
import { FULL_SCREEN_TRIANGLE_GEOMETRY } from "../../../graphics/geometry/FULL_SCREEN_TRIANGLE_GEOMETRY.js";
import { buildScreenSpaceFogOfWarShader } from "./screenSpaceFogOfWarShader.js";
/**
*
* @param {FogOfWar} fow
* @param {function(number, number, number, number)} callback
*/
export function computeUvTransformFromFogOfWar(fow, callback) {
const sampler = fow.sampler;
const samplerWidth = sampler.width;
const samplerHeight = sampler.height;
const scaleX = (fow.scale * fow.size.x) * (samplerWidth / (samplerWidth - 3));
const scaleY = (fow.scale * fow.size.y) * (samplerHeight / (samplerHeight - 3));
const offsetX = 1.5 / samplerWidth;
const offsetY = 1.5 / samplerHeight;
callback(offsetX, offsetY, 1 / scaleX, 1 / scaleY);
}
export class FogOfWarRenderer {
constructor() {
/**
*
* @type {ShaderMaterial}
*/
this.material = buildScreenSpaceFogOfWarShader();
this.quad = new Mesh(FULL_SCREEN_TRIANGLE_GEOMETRY, this.material);
this.camera = new OrthographicCamera(-1, 1, 1, -1, 0, 1);
this.scene = new Scene();
this.scene.add(this.quad);
}
/**
*
* @param {FogOfWar} fow
*/
setUvTransformFromFog(fow) {
computeUvTransformFromFogOfWar(fow, (offsetX, offsetY, scaleX, scaleY) => {
this.setUvTransform(offsetX, offsetY, scaleX, scaleY);
});
}
/**
*
* @param {number} offsetX UV u offset, between 0 and 1
* @param {number} offsetY UV v offset, between 0 and 1
* @param {number} scaleX Transform scale from world coordinate position to UV u coordinate, minus offsetX
* @param {number} scaleY Transform scale from world coordinate position to UV v coordinate, minus offsetY
*/
setUvTransform(offsetX, offsetY, scaleX, scaleY) {
assert.isNumber(offsetX, 'offsetX');
assert.notNaN(offsetX, 'offsetX');
assert.ok(isValueBetweenInclusive(offsetX, 0, 1), `expected offsetX to be between 0 and 1, instead was '${offsetX}'`);
assert.isNumber(offsetY, 'offsetY');
assert.notNaN(offsetY, 'offsetY');
assert.ok(isValueBetweenInclusive(offsetY, 0, 1), `expected offsetY to be between 0 and 1, instead was '${offsetY}'`);
assert.isNumber(scaleX, 'scaleX');
assert.notNaN(scaleX, 'scaleX');
assert.isFiniteNumber(scaleX, 'scaleX');
assert.isNumber(scaleY, 'scaleY');
assert.notNaN(scaleY, 'scaleY');
assert.isFiniteNumber(scaleY, 'scaleY');
this.material.uniforms.uFogUvTransform.value.set(offsetX, offsetY, scaleX, scaleY);
}
/**
*
* @param {Texture} texture
*/
setDepthBuffer(texture) {
// assert.equal(texture.type, UnsignedShortType, `expected texture type to be UnsignedShort(=${UnsignedShortType}), instead got something else (=${texture.type})`)
this.material.uniforms.tDepth.value = texture;
}
/**
*
* @param {Texture} buffer
*/
setFogBuffer(buffer) {
this.material.uniforms.tFog.value = buffer;
}
/**
* Resolution of the fog texture
* @param {number} x
* @param {number} y
*/
setResolution(x, y) {
this.material.uniforms.uResolution.value.set(x, y);
}
/**
*
* @param {Vector4} color
*/
setFogColor(color) {
this.material.uniforms.uColor.value.copy(color);
}
/**
*
* @param {WebGLRenderer} renderer
* @param {PerspectiveCamera|OrthographicCamera} camera
* @param {Scene} scene
* @param {WebGLRenderTarget} target
*/
render(renderer, camera, scene, target) {
assert.ok(camera.isCamera, 'Not a camera');
assert.ok(camera.isPerspectiveCamera || camera.isOrthographicCamera, 'Unsupported Camera type. Expected PerspectiveCamera or OrthographicCamera');
//set up uniforms
const uniforms = this.material.uniforms;
uniforms.uProjectionInverse.value.copy(camera.projectionMatrixInverse);
uniforms.uViewInverse.value.copy(camera.matrixWorld);
renderer.setRenderTarget(target);
renderer.clearColor();
renderer.render(this.scene, this.camera);
renderer.setRenderTarget(null);
}
}