@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
216 lines (161 loc) • 5.75 kB
JavaScript
import { ClampToEdgeWrapping, DataTexture, FloatType, LinearFilter, RedFormat } from "three";
import { BvhClient } from "../../../../core/bvh2/bvh3/BvhClient.js";
import { Color } from "../../../../core/color/Color.js";
import Vector1 from "../../../../core/geom/Vector1.js";
import { NumericInterval } from "../../../../core/math/interval/NumericInterval.js";
import { threeUpdateTransform } from "../../util/threeUpdateTransform.js";
import { WATER_SIZE } from "./WATER_SIZE.js";
class Water {
level = new Vector1(0);
/**
*
* @type {Color}
*/
color = new Color(0, 0.3, 0.5);
/**
* Defines what is considered as shore as well as how long is the transition between shore and deep water
* @type {NumericInterval}
*/
shoreDepthTransition = new NumericInterval(0.7, 2);
/**
* Color of the water at the shore
* @type {Color}
*/
shoreColor = new Color(0.584, 0.792, 0.850);
/**
*
* @type {Vector1}
*/
waveSpeed = new Vector1(1.8);
/**
*
* @type {Vector1}
*/
waveAmplitude = new Vector1(0.3);
/**
*
* @type {Vector1}
*/
waveFrequency = new Vector1(1);
/**
* Scattering of light, the higher this value is - the more opaque water will become
* @type {Vector1}
*/
scattering = new Vector1(1.2);
bvh = new BvhClient();
constructor(options) {
if (options !== undefined) {
console.error('Constructor options are deprecated');
this.fromJSON(options);
}
/**
*
* @type {ShaderMaterial}
*/
this.__shader = null;
/**
*
* @type {Object3D}
* @private
*/
this.__threeObject = null;
// monitor changes
this.color.onChanged.add(this.writeShaderUniforms, this);
this.shoreDepthTransition.onChanged.add(this.writeShaderUniforms, this);
this.shoreColor.onChanged.add(this.writeShaderUniforms, this);
this.waveSpeed.onChanged.add(this.writeShaderUniforms, this);
this.waveAmplitude.onChanged.add(this.writeShaderUniforms, this);
this.waveFrequency.onChanged.add(this.writeShaderUniforms, this);
this.scattering.onChanged.add(this.writeShaderUniforms, this);
}
updateTransform() {
const width = WATER_SIZE;
const height = WATER_SIZE;
const mesh = this.__threeObject;
if (mesh !== null) {
mesh.rotation.x = Math.PI * 0.5;
mesh.position.x = width / 4;
mesh.position.z = height / 4;
mesh.position.y = this.level.getValue();
threeUpdateTransform(mesh);
}
this.updateBounds();
}
updateBounds() {
const width = WATER_SIZE;
const height = WATER_SIZE;
const level = this.level.getValue();
this.bvh.resize(
-width / 4,
level,
-height / 4,
width * (3 / 4),
level,
height * (3 / 4)
);
}
/**
*
* @param {Terrain} terrain
* @param {number} waterSize
*/
updateShaderForTerrain(terrain, waterSize) {
const shader = this.__shader;
if (shader === null) {
return;
}
const tW = terrain.size.x * terrain.gridScale;
const tH = terrain.size.y * terrain.gridScale;
const heightTexture = new DataTexture(terrain.samplerHeight.data, terrain.samplerHeight.width, terrain.samplerHeight.height, RedFormat, FloatType);
heightTexture.wrapS = ClampToEdgeWrapping;
heightTexture.wrapT = ClampToEdgeWrapping;
heightTexture.generateMipmaps = false;
heightTexture.minFilter = LinearFilter;
heightTexture.magFilter = LinearFilter;
heightTexture.flipY = false;
heightTexture.internalFormat = 'R32F';
shader.uniforms.tHeightTexture.value = heightTexture;
shader.uniforms.vHeightUv.value.set(
-0.25,
-0.25,
(waterSize / tW),
(waterSize / tH)
);
shader.uniforms.vHeightTextureResolution.value.set(terrain.samplerHeight.width, terrain.samplerHeight.height);
}
writeShaderUniforms() {
/**
*
* @type {ShaderMaterial}
*/
const shader = this.__shader;
if (shader === null) {
//no shader attached
return;
}
const uniforms = shader.uniforms;
uniforms.waterColor.value.setRGB(this.color.r, this.color.g, this.color.b);
uniforms.shoreColor.value.setRGB(this.shoreColor.r, this.shoreColor.g, this.shoreColor.b);
uniforms.fWaveSpeed.value = this.waveSpeed.getValue();
uniforms.fWaveAmplitude.value = this.waveAmplitude.getValue();
uniforms.fWaveFrequency.value = this.waveFrequency.getValue();
uniforms.fScattering.value = this.scattering.getValue();
uniforms.vShoreDepthTransition.value.set(this.shoreDepthTransition.min, this.shoreDepthTransition.max);
}
fromJSON(json) {
if (typeof json.level === 'number') {
this.level.fromJSON(json.level);
}
if (typeof json.color === 'object') {
this.color.fromJSON(json.color);
}
}
toJSON() {
return {
level: this.level.toJSON(),
color: this.color.toJSON()
};
}
}
Water.typeName = "Water";
export default Water;