提交 c4711517 编写于 作者: M Mr.doob

Examples: Moved js/WaterShader to js/objects/Water and refactored to match Sky and Mirror.

上级 fa0e461a
......@@ -7,43 +7,61 @@
* @author Jonas Wagner / http://29a.ch/ && http://29a.ch/slides/2012/webglwater/ : Water shader explanations in WebGL
*/
THREE.Water = function ( options ) {
THREE.Water = function ( width, height, options ) {
THREE.Object3D.call( this );
THREE.Mesh.call( this, new THREE.PlaneBufferGeometry( width, height ) );
function optionalParameter( value, defaultValue ) {
var scope = this;
return value !== undefined ? value : defaultValue;
options = options || {};
}
var textureWidth = options.textureWidth !== undefined ? options.textureWidth : 512;
var textureHeight = options.textureHeight !== undefined ? options.textureHeight : 512;
var clipBias = options.clipBias !== undefined ? options.clipBias : 0.0;
var alpha = options.alpha !== undefined ? options.alpha : 1.0;
var time = options.time !== undefined ? options.time : 0.0;
var normalSampler = options.waterNormals !== undefined ? options.waterNormals : null;
var sunDirection = options.sunDirection !== undefined ? options.sunDirection : new THREE.Vector3( 0.70707, 0.70707, 0.0 );
var sunColor = new THREE.Color( options.sunColor !== undefined ? options.sunColor : 0xffffff );
var waterColor = new THREE.Color( options.waterColor !== undefined ? options.waterColor : 0x7F7F7F );
var eye = options.eye !== undefined ? options.eye : new THREE.Vector3( 0, 0, 0 );
var distortionScale = options.distortionScale !== undefined ? options.distortionScale : 20.0;
var side = options.side !== undefined ? options.side : THREE.FrontSide;
var fog = options.fog !== undefined ? options.fog : false;
//
var mirrorPlane = new THREE.Plane();
var normal = new THREE.Vector3();
var mirrorWorldPosition = new THREE.Vector3();
var cameraWorldPosition = new THREE.Vector3();
var rotationMatrix = new THREE.Matrix4();
var lookAtPosition = new THREE.Vector3( 0, 0, - 1 );
var clipPlane = new THREE.Vector4();
var view = new THREE.Vector3();
var target = new THREE.Vector3();
var q = new THREE.Vector4();
options = options || {};
var textureMatrix = new THREE.Matrix4();
var mirrorCamera = new THREE.PerspectiveCamera();
var parameters = {
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBFormat,
stencilBuffer: false
};
var renderTarget = new THREE.WebGLRenderTarget( textureWidth, textureHeight, parameters );
var width = optionalParameter( options.textureWidth, 512 );
var height = optionalParameter( options.textureHeight, 512 );
this.clipBias = optionalParameter( options.clipBias, 0.0 );
this.alpha = optionalParameter( options.alpha, 1.0 );
this.time = optionalParameter( options.time, 0.0 );
this.normalSampler = optionalParameter( options.waterNormals, null );
this.sunDirection = optionalParameter( options.sunDirection, new THREE.Vector3( 0.70707, 0.70707, 0.0 ) );
this.sunColor = new THREE.Color( optionalParameter( options.sunColor, 0xffffff ) );
this.waterColor = new THREE.Color( optionalParameter( options.waterColor, 0x7F7F7F ) );
this.eye = optionalParameter( options.eye, new THREE.Vector3( 0, 0, 0 ) );
this.distortionScale = optionalParameter( options.distortionScale, 20.0 );
this.side = optionalParameter( options.side, THREE.FrontSide );
this.fog = optionalParameter( options.fog, false );
this.mirrorPlane = new THREE.Plane();
this.normal = new THREE.Vector3( 0, 0, 1 );
this.mirrorWorldPosition = new THREE.Vector3();
this.cameraWorldPosition = new THREE.Vector3();
this.rotationMatrix = new THREE.Matrix4();
this.lookAtPosition = new THREE.Vector3( 0, 0, - 1 );
this.clipPlane = new THREE.Vector4();
this.textureMatrix = new THREE.Matrix4();
this.renderTarget = new THREE.WebGLRenderTarget( width, height );
if ( ! THREE.Math.isPowerOfTwo( textureWidth ) || ! THREE.Math.isPowerOfTwo( textureHeight ) ) {
renderTarget.texture.generateMipmaps = false;
}
var mirrorShader = {
......@@ -163,143 +181,106 @@ THREE.Water = function ( options ) {
};
var mirrorUniforms = THREE.UniformsUtils.clone( mirrorShader.uniforms );
this.material = new THREE.ShaderMaterial( {
var material = new THREE.ShaderMaterial( {
fragmentShader: mirrorShader.fragmentShader,
vertexShader: mirrorShader.vertexShader,
uniforms: mirrorUniforms,
uniforms: THREE.UniformsUtils.clone( mirrorShader.uniforms ),
transparent: true,
lights: true,
side: this.side,
fog: this.fog
side: side,
fog: fog
} );
this.material.uniforms.mirrorSampler.value = this.renderTarget.texture;
this.material.uniforms.textureMatrix.value = this.textureMatrix;
this.material.uniforms.alpha.value = this.alpha;
this.material.uniforms.time.value = this.time;
this.material.uniforms.normalSampler.value = this.normalSampler;
this.material.uniforms.sunColor.value = this.sunColor;
this.material.uniforms.waterColor.value = this.waterColor;
this.material.uniforms.sunDirection.value = this.sunDirection;
this.material.uniforms.distortionScale.value = this.distortionScale;
this.material.uniforms.size.value = this.size;
this.material.uniforms.eye.value = this.eye;
if ( ! THREE.Math.isPowerOfTwo( width ) || ! THREE.Math.isPowerOfTwo( height ) ) {
this.renderTarget.texture.generateMipmaps = false;
this.renderTarget.texture.minFilter = THREE.LinearFilter;
}
material.uniforms.mirrorSampler.value = renderTarget.texture;
material.uniforms.textureMatrix.value = textureMatrix;
material.uniforms.alpha.value = alpha;
material.uniforms.time.value = time;
material.uniforms.normalSampler.value = normalSampler;
material.uniforms.sunColor.value = sunColor;
material.uniforms.waterColor.value = waterColor;
material.uniforms.sunDirection.value = sunDirection;
material.uniforms.distortionScale.value = distortionScale;
};
material.uniforms.eye.value = eye;
THREE.Water.prototype = Object.create( THREE.Object3D.prototype );
THREE.Water.prototype.constructor = THREE.Water;
scope.material = material;
scope.onBeforeRender = function ( renderer, scene, camera ) {
THREE.Water.prototype.updateTextureMatrix = function ( camera ) {
mirrorWorldPosition.setFromMatrixPosition( scope.matrixWorld );
cameraWorldPosition.setFromMatrixPosition( camera.matrixWorld );
this.mirrorCamera = this.mirrorCamera || camera.clone();
rotationMatrix.extractRotation( scope.matrixWorld );
this.updateMatrixWorld();
camera.updateMatrixWorld();
normal.set( 0, 0, 1 );
normal.applyMatrix4( rotationMatrix );
this.mirrorWorldPosition.setFromMatrixPosition( this.matrixWorld );
this.cameraWorldPosition.setFromMatrixPosition( camera.matrixWorld );
view.subVectors( mirrorWorldPosition, cameraWorldPosition );
this.rotationMatrix.extractRotation( this.matrixWorld );
// Avoid rendering when mirror is facing away
this.normal.set( 0, 0, 1 );
this.normal.applyMatrix4( this.rotationMatrix );
if ( view.dot( normal ) > 0 ) return;
var view = this.mirrorWorldPosition.clone().sub( this.cameraWorldPosition );
view.reflect( this.normal ).negate();
view.add( this.mirrorWorldPosition );
view.reflect( normal ).negate();
view.add( mirrorWorldPosition );
this.rotationMatrix.extractRotation( camera.matrixWorld );
rotationMatrix.extractRotation( camera.matrixWorld );
this.lookAtPosition.set( 0, 0, -1 );
this.lookAtPosition.applyMatrix4( this.rotationMatrix );
this.lookAtPosition.add( this.cameraWorldPosition );
lookAtPosition.set( 0, 0, - 1 );
lookAtPosition.applyMatrix4( rotationMatrix );
lookAtPosition.add( cameraWorldPosition );
var target = this.mirrorWorldPosition.clone().sub( this.lookAtPosition );
target.reflect( this.normal ).negate();
target.add( this.mirrorWorldPosition );
target.subVectors( mirrorWorldPosition, lookAtPosition );
target.reflect( normal ).negate();
target.add( mirrorWorldPosition );
this.up.set( 0, - 1, 0 );
this.up.applyMatrix4( this.rotationMatrix );
this.up.reflect( this.normal ).negate();
mirrorCamera.position.copy( view );
mirrorCamera.up.set( 0, 1, 0 );
mirrorCamera.up.applyMatrix4( rotationMatrix );
mirrorCamera.up.reflect( normal );
mirrorCamera.lookAt( target );
this.mirrorCamera.position.copy( view );
this.mirrorCamera.up = this.up;
this.mirrorCamera.lookAt( target );
this.mirrorCamera.aspect = camera.aspect;
mirrorCamera.far = camera.far; // Used in WebGLBackground
this.mirrorCamera.updateProjectionMatrix();
this.mirrorCamera.updateMatrixWorld();
mirrorCamera.updateMatrixWorld();
mirrorCamera.projectionMatrix.copy( camera.projectionMatrix );
// Update the texture matrix
this.textureMatrix.set(
0.5, 0.0, 0.0, 0.5,
0.0, 0.5, 0.0, 0.5,
0.0, 0.0, 0.5, 0.5,
0.0, 0.0, 0.0, 1.0
);
this.textureMatrix.multiply( this.mirrorCamera.projectionMatrix );
this.textureMatrix.multiply( this.mirrorCamera.matrixWorldInverse );
// Update the texture matrix
textureMatrix.set(
0.5, 0.0, 0.0, 0.5,
0.0, 0.5, 0.0, 0.5,
0.0, 0.0, 0.5, 0.5,
0.0, 0.0, 0.0, 1.0
);
textureMatrix.multiply( mirrorCamera.projectionMatrix );
textureMatrix.multiply( mirrorCamera.matrixWorldInverse );
// Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html
// Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
this.mirrorPlane.setFromNormalAndCoplanarPoint( this.normal, this.mirrorWorldPosition );
this.mirrorPlane.applyMatrix4( this.mirrorCamera.matrixWorldInverse );
// Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html
// Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
mirrorPlane.setFromNormalAndCoplanarPoint( normal, mirrorWorldPosition );
mirrorPlane.applyMatrix4( mirrorCamera.matrixWorldInverse );
this.clipPlane.set( this.mirrorPlane.normal.x, this.mirrorPlane.normal.y, this.mirrorPlane.normal.z, this.mirrorPlane.constant );
clipPlane.set( mirrorPlane.normal.x, mirrorPlane.normal.y, mirrorPlane.normal.z, mirrorPlane.constant );
var q = new THREE.Vector4();
var projectionMatrix = this.mirrorCamera.projectionMatrix;
var projectionMatrix = mirrorCamera.projectionMatrix;
q.x = ( Math.sign( this.clipPlane.x ) + projectionMatrix.elements[ 8 ] ) / projectionMatrix.elements[ 0 ];
q.y = ( Math.sign( this.clipPlane.y ) + projectionMatrix.elements[ 9 ] ) / projectionMatrix.elements[ 5 ];
q.z = - 1.0;
q.w = ( 1.0 + projectionMatrix.elements[ 10 ] ) / projectionMatrix.elements[ 14 ];
q.x = ( Math.sign( clipPlane.x ) + projectionMatrix.elements[ 8 ] ) / projectionMatrix.elements[ 0 ];
q.y = ( Math.sign( clipPlane.y ) + projectionMatrix.elements[ 9 ] ) / projectionMatrix.elements[ 5 ];
q.z = - 1.0;
q.w = ( 1.0 + projectionMatrix.elements[ 10 ] ) / projectionMatrix.elements[ 14 ];
// Calculate the scaled plane vector
var c = this.clipPlane.multiplyScalar( 2.0 / this.clipPlane.dot( q ) );
// Calculate the scaled plane vector
clipPlane.multiplyScalar( 2.0 / clipPlane.dot( q ) );
// Replacing the third row of the projection matrix
projectionMatrix.elements[ 2 ] = c.x;
projectionMatrix.elements[ 6 ] = c.y;
projectionMatrix.elements[ 10 ] = c.z + 1.0 - this.clipBias;
projectionMatrix.elements[ 14 ] = c.w;
// Replacing the third row of the projection matrix
projectionMatrix.elements[ 2 ] = clipPlane.x;
projectionMatrix.elements[ 6 ] = clipPlane.y;
projectionMatrix.elements[ 10 ] = clipPlane.z + 1.0 - clipBias;
projectionMatrix.elements[ 14 ] = clipPlane.w;
var worldCoordinates = new THREE.Vector3();
worldCoordinates.setFromMatrixPosition( camera.matrixWorld );
this.eye = worldCoordinates;
this.material.uniforms.eye.value = this.eye;
eye.setFromMatrixPosition( camera.matrixWorld );
};
THREE.WaterMesh = function ( width, height, options ) {
var waterMaterial = new THREE.Water( options );
THREE.Mesh.call( this, new THREE.PlaneBufferGeometry( width, height ), waterMaterial.material );
var scope = this;
scope.name = 'water_' + scope.id;
scope.water = waterMaterial;
scope.add( waterMaterial );
scope.onBeforeRender = function ( renderer, scene, camera ) {
scope.water.updateTextureMatrix( camera );
//
var currentRenderTarget = renderer.getRenderTarget();
......@@ -311,7 +292,7 @@ THREE.WaterMesh = function ( width, height, options ) {
renderer.vr.enabled = false; // Avoid camera modification and recursion
renderer.shadowMap.autoUpdate = false; // Avoid re-computing shadows
renderer.render( scene, scope.water.mirrorCamera, scope.water.renderTarget, true );
renderer.render( scene, mirrorCamera, renderTarget, true );
scope.visible = true;
......@@ -321,8 +302,8 @@ THREE.WaterMesh = function ( width, height, options ) {
renderer.setRenderTarget( currentRenderTarget );
};
};
THREE.WaterMesh.prototype = Object.create( THREE.Mesh.prototype );
THREE.WaterMesh.prototype.constructor = THREE.WaterMesh;
THREE.Water.prototype = Object.create( THREE.Mesh.prototype );
THREE.Water.prototype.constructor = THREE.Water;
......@@ -33,7 +33,7 @@
<script src="../build/three.js"></script>
<script src="js/controls/OrbitControls.js"></script>
<script src="js/WaterShader.js"></script>
<script src="js/objects/Water.js"></script>
<script src="js/Detector.js"></script>
<script src="js/libs/stats.min.js"></script>
......@@ -54,9 +54,9 @@
var parameters = {
oceanSide: 2000,
size: 0.3,
size: 1.0,
distortionScale: 3.7,
alpha: 0.96
alpha: 1.0
};
var waterNormals;
......@@ -101,13 +101,13 @@
setWater();
//
//
setSkybox();
//
var geometry = new THREE.IcosahedronGeometry( 20, 4 );
var geometry = new THREE.IcosahedronGeometry( 20, 2 );
for ( var i = 0, j = geometry.faces.length; i < j; i ++ ) {
......@@ -117,7 +117,7 @@
var material = new THREE.MeshPhongMaterial( {
vertexColors: THREE.FaceColors,
shininess: 100,
shininess: 10,
envMap: cubeMap,
side: THREE.DoubleSide
} );
......@@ -147,8 +147,8 @@
function setWater() {
water = new THREE.WaterMesh(
parameters.oceanSide * 5,
water = new THREE.Water(
parameters.oceanSide * 5,
parameters.oceanSide * 5,
{
textureWidth: 512,
......@@ -234,10 +234,10 @@
light.shadow.camera.top = 45;
light.shadow.camera.right = 40;
light.shadow.camera.left = light.shadow.camera.bottom = -40;
light.shadow.camera.near = 1;
light.shadow.camera.near = 1;
light.shadow.camera.far = 200;
scene.add( light, new THREE.AmbientLight( 0x444444 ) );
scene.add( light, new THREE.AmbientLight( 0x888888 ) );
}
......@@ -260,11 +260,11 @@
function render() {
var time = performance.now() * 0.003;
var time = performance.now() * 0.001;
sphere.position.y = Math.sin( time ) * 2 + 5;
sphere.rotation.x = time * 0.1;
sphere.rotation.z = time * 0.11;
sphere.position.y = Math.sin( time ) * 20 + 5;
sphere.rotation.x = time * 0.5;
sphere.rotation.z = time * 0.51;
water.material.uniforms.time.value += 1.0 / 60.0;
water.material.uniforms.size.value = parameters.size;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册