mirror of https://gitee.com/cf-fz/WebCAD.git
pull/821/MERGE
parent
69d19ca74b
commit
10c3f32a3d
@ -1,265 +0,0 @@
|
||||
/**
|
||||
* @author Slayvin / http://slayvin.net
|
||||
*/
|
||||
|
||||
THREE.Reflector = function (width, height, options)
|
||||
{
|
||||
|
||||
THREE.Mesh.call(this, new THREE.PlaneBufferGeometry(width, height));
|
||||
|
||||
this.type = 'Reflector';
|
||||
|
||||
var scope = this;
|
||||
|
||||
options = options || {};
|
||||
|
||||
var color = (options.color !== undefined) ? new THREE.Color(options.color) : new THREE.Color(0x7F7F7F);
|
||||
var textureWidth = options.textureWidth || 512;
|
||||
var textureHeight = options.textureHeight || 512;
|
||||
var clipBias = options.clipBias || 0;
|
||||
var shader = options.shader || THREE.Reflector.ReflectorShader;
|
||||
var recursion = options.recursion !== undefined ? options.recursion : 0;
|
||||
|
||||
//
|
||||
|
||||
var reflectorPlane = new THREE.Plane();
|
||||
var normal = new THREE.Vector3();
|
||||
var reflectorWorldPosition = 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 viewport = new THREE.Vector4();
|
||||
|
||||
var view = new THREE.Vector3();
|
||||
var target = new THREE.Vector3();
|
||||
var q = new THREE.Vector4();
|
||||
|
||||
var textureMatrix = new THREE.Matrix4();
|
||||
var virtualCamera = new THREE.PerspectiveCamera();
|
||||
|
||||
var parameters = {
|
||||
minFilter: THREE.LinearFilter,
|
||||
magFilter: THREE.LinearFilter,
|
||||
format: THREE.RGBFormat,
|
||||
stencilBuffer: false
|
||||
};
|
||||
|
||||
var renderTarget = new THREE.WebGLRenderTarget(textureWidth, textureHeight, parameters);
|
||||
|
||||
if (!THREE.Math.isPowerOfTwo(textureWidth) || !THREE.Math.isPowerOfTwo(textureHeight)) {
|
||||
|
||||
renderTarget.texture.generateMipmaps = false;
|
||||
|
||||
}
|
||||
|
||||
var material = new THREE.ShaderMaterial({
|
||||
uniforms: THREE.UniformsUtils.clone(shader.uniforms),
|
||||
fragmentShader: shader.fragmentShader,
|
||||
vertexShader: shader.vertexShader,
|
||||
|
||||
});
|
||||
|
||||
material.uniforms.tDiffuse.value = renderTarget.texture;
|
||||
material.uniforms.color.value = color;
|
||||
material.uniforms.textureMatrix.value = textureMatrix;
|
||||
|
||||
this.material = material;
|
||||
|
||||
this.onBeforeRender = function (renderer, scene, camera)
|
||||
{
|
||||
|
||||
if ('recursion' in camera.userData) {
|
||||
|
||||
if (camera.userData.recursion === recursion) return;
|
||||
|
||||
camera.userData.recursion++;
|
||||
|
||||
}
|
||||
|
||||
reflectorWorldPosition.setFromMatrixPosition(scope.matrixWorld);
|
||||
cameraWorldPosition.setFromMatrixPosition(camera.matrixWorld);
|
||||
|
||||
rotationMatrix.extractRotation(scope.matrixWorld);
|
||||
|
||||
normal.set(0, 0, 1);
|
||||
normal.applyMatrix4(rotationMatrix);
|
||||
|
||||
view.subVectors(reflectorWorldPosition, cameraWorldPosition);
|
||||
|
||||
// Avoid rendering when reflector is facing away
|
||||
|
||||
if (view.dot(normal) > 0) return;
|
||||
|
||||
view.reflect(normal).negate();
|
||||
view.add(reflectorWorldPosition);
|
||||
|
||||
rotationMatrix.extractRotation(camera.matrixWorld);
|
||||
|
||||
lookAtPosition.set(0, 0, - 1);
|
||||
lookAtPosition.applyMatrix4(rotationMatrix);
|
||||
lookAtPosition.add(cameraWorldPosition);
|
||||
|
||||
target.subVectors(reflectorWorldPosition, lookAtPosition);
|
||||
target.reflect(normal).negate();
|
||||
target.add(reflectorWorldPosition);
|
||||
|
||||
virtualCamera.position.copy(view);
|
||||
virtualCamera.up.set(0, 1, 0);
|
||||
virtualCamera.up.applyMatrix4(rotationMatrix);
|
||||
virtualCamera.up.reflect(normal);
|
||||
virtualCamera.lookAt(target);
|
||||
|
||||
virtualCamera.far = camera.far; // Used in WebGLBackground
|
||||
|
||||
virtualCamera.updateMatrixWorld();
|
||||
virtualCamera.projectionMatrix.copy(camera.projectionMatrix);
|
||||
|
||||
virtualCamera.userData.recursion = 0;
|
||||
|
||||
// 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(virtualCamera.projectionMatrix);
|
||||
textureMatrix.multiply(virtualCamera.matrixWorldInverse);
|
||||
textureMatrix.multiply(scope.matrixWorld);
|
||||
|
||||
// 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
|
||||
reflectorPlane.setFromNormalAndCoplanarPoint(normal, reflectorWorldPosition);
|
||||
reflectorPlane.applyMatrix4(virtualCamera.matrixWorldInverse);
|
||||
|
||||
clipPlane.set(reflectorPlane.normal.x, reflectorPlane.normal.y, reflectorPlane.normal.z, reflectorPlane.constant);
|
||||
|
||||
var projectionMatrix = virtualCamera.projectionMatrix;
|
||||
|
||||
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
|
||||
clipPlane.multiplyScalar(2.0 / clipPlane.dot(q));
|
||||
|
||||
// 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;
|
||||
|
||||
// Render
|
||||
|
||||
scope.visible = false;
|
||||
|
||||
var currentRenderTarget = renderer.getRenderTarget();
|
||||
|
||||
var currentVrEnabled = renderer.vr.enabled;
|
||||
var currentShadowAutoUpdate = renderer.shadowMap.autoUpdate;
|
||||
|
||||
renderer.vr.enabled = false; // Avoid camera modification and recursion
|
||||
renderer.shadowMap.autoUpdate = false; // Avoid re-computing shadows
|
||||
|
||||
renderer.render(scene, virtualCamera, renderTarget, true);
|
||||
|
||||
renderer.vr.enabled = currentVrEnabled;
|
||||
renderer.shadowMap.autoUpdate = currentShadowAutoUpdate;
|
||||
|
||||
renderer.setRenderTarget(currentRenderTarget);
|
||||
|
||||
// Restore viewport
|
||||
|
||||
var bounds = camera.bounds;
|
||||
|
||||
if (bounds !== undefined) {
|
||||
|
||||
var size = renderer.getSize();
|
||||
var pixelRatio = renderer.getPixelRatio();
|
||||
|
||||
viewport.x = bounds.x * size.width * pixelRatio;
|
||||
viewport.y = bounds.y * size.height * pixelRatio;
|
||||
viewport.z = bounds.z * size.width * pixelRatio;
|
||||
viewport.w = bounds.w * size.height * pixelRatio;
|
||||
|
||||
renderer.state.viewport(viewport);
|
||||
|
||||
}
|
||||
|
||||
scope.visible = true;
|
||||
|
||||
};
|
||||
|
||||
this.getRenderTarget = function ()
|
||||
{
|
||||
|
||||
return renderTarget;
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
THREE.Reflector.prototype = Object.create(THREE.Mesh.prototype);
|
||||
THREE.Reflector.prototype.constructor = THREE.Reflector;
|
||||
|
||||
THREE.Reflector.ReflectorShader = {
|
||||
|
||||
uniforms: {
|
||||
|
||||
'color': {
|
||||
type: 'c',
|
||||
value: null
|
||||
},
|
||||
|
||||
'tDiffuse': {
|
||||
type: 't',
|
||||
value: null
|
||||
},
|
||||
|
||||
'textureMatrix': {
|
||||
type: 'm4',
|
||||
value: null
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
vertexShader: [
|
||||
'uniform mat4 textureMatrix;',
|
||||
'varying vec4 vUv;',
|
||||
|
||||
'void main() {',
|
||||
|
||||
' vUv = textureMatrix * vec4( position, 1.0 );',
|
||||
|
||||
' gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
|
||||
|
||||
'}'
|
||||
].join('\n'),
|
||||
|
||||
fragmentShader: [
|
||||
'uniform vec3 color;',
|
||||
'uniform sampler2D tDiffuse;',
|
||||
'varying vec4 vUv;',
|
||||
|
||||
'float blendOverlay( float base, float blend ) {',
|
||||
|
||||
' return( base < 0.5 ? ( 2.0 * base * blend ) : ( 1.0 - 2.0 * ( 1.0 - base ) * ( 1.0 - blend ) ) );',
|
||||
|
||||
'}',
|
||||
|
||||
'vec3 blendOverlay( vec3 base, vec3 blend ) {',
|
||||
|
||||
' return vec3( blendOverlay( base.r, blend.r ), blendOverlay( base.g, blend.g ), blendOverlay( base.b, blend.b ) );',
|
||||
|
||||
'}',
|
||||
|
||||
'void main() {',
|
||||
|
||||
' vec4 base = texture2DProj( tDiffuse, vUv );',
|
||||
' gl_FragColor = vec4( blendOverlay( base.rgb, color ), 1.0 );',
|
||||
|
||||
'}'
|
||||
].join('\n')
|
||||
};
|
@ -1,10 +0,0 @@
|
||||
THREE.ReflectorRTT = function (width, height, options)
|
||||
{
|
||||
|
||||
THREE.Reflector.call(this, width, height, options);
|
||||
|
||||
this.geometry.setDrawRange(0, 0); // avoid rendering geometry
|
||||
|
||||
};
|
||||
|
||||
THREE.ReflectorRTT.prototype = Object.create(THREE.Reflector.prototype);
|
@ -1,72 +0,0 @@
|
||||
/**
|
||||
* @author erichlof / http://github.com/erichlof
|
||||
*
|
||||
* A shadow Mesh that follows a shadow-casting Mesh in the scene, but is confined to a single plane.
|
||||
*/
|
||||
|
||||
THREE.ShadowMesh = function (mesh)
|
||||
{
|
||||
|
||||
var shadowMaterial = new THREE.MeshBasicMaterial({
|
||||
|
||||
color: 0x000000,
|
||||
transparent: true,
|
||||
opacity: 0.6,
|
||||
depthWrite: false
|
||||
|
||||
});
|
||||
|
||||
THREE.Mesh.call(this, mesh.geometry, shadowMaterial);
|
||||
|
||||
this.meshMatrix = mesh.matrixWorld;
|
||||
|
||||
this.frustumCulled = false;
|
||||
this.matrixAutoUpdate = false;
|
||||
|
||||
};
|
||||
|
||||
THREE.ShadowMesh.prototype = Object.create(THREE.Mesh.prototype);
|
||||
THREE.ShadowMesh.prototype.constructor = THREE.ShadowMesh;
|
||||
|
||||
THREE.ShadowMesh.prototype.update = function ()
|
||||
{
|
||||
|
||||
var shadowMatrix = new THREE.Matrix4();
|
||||
|
||||
return function (plane, lightPosition4D)
|
||||
{
|
||||
|
||||
// based on https://www.opengl.org/archives/resources/features/StencilTalk/tsld021.htm
|
||||
|
||||
var dot = plane.normal.x * lightPosition4D.x +
|
||||
plane.normal.y * lightPosition4D.y +
|
||||
plane.normal.z * lightPosition4D.z +
|
||||
- plane.constant * lightPosition4D.w;
|
||||
|
||||
var sme = shadowMatrix.elements;
|
||||
|
||||
sme[0] = dot - lightPosition4D.x * plane.normal.x;
|
||||
sme[4] = - lightPosition4D.x * plane.normal.y;
|
||||
sme[8] = - lightPosition4D.x * plane.normal.z;
|
||||
sme[12] = - lightPosition4D.x * - plane.constant;
|
||||
|
||||
sme[1] = - lightPosition4D.y * plane.normal.x;
|
||||
sme[5] = dot - lightPosition4D.y * plane.normal.y;
|
||||
sme[9] = - lightPosition4D.y * plane.normal.z;
|
||||
sme[13] = - lightPosition4D.y * - plane.constant;
|
||||
|
||||
sme[2] = - lightPosition4D.z * plane.normal.x;
|
||||
sme[6] = - lightPosition4D.z * plane.normal.y;
|
||||
sme[10] = dot - lightPosition4D.z * plane.normal.z;
|
||||
sme[14] = - lightPosition4D.z * - plane.constant;
|
||||
|
||||
sme[3] = - lightPosition4D.w * plane.normal.x;
|
||||
sme[7] = - lightPosition4D.w * plane.normal.y;
|
||||
sme[11] = - lightPosition4D.w * plane.normal.z;
|
||||
sme[15] = dot - lightPosition4D.w * - plane.constant;
|
||||
|
||||
this.matrix.multiplyMatrices(shadowMatrix, this.meshMatrix);
|
||||
|
||||
};
|
||||
|
||||
}();
|
@ -1,311 +0,0 @@
|
||||
/**
|
||||
* @author jbouny / https://github.com/jbouny
|
||||
*
|
||||
* Work based on :
|
||||
* @author Slayvin / http://slayvin.net : Flat mirror for three.js
|
||||
* @author Stemkoski / http://www.adelphi.edu/~stemkoski : An implementation of water shader based on the flat mirror
|
||||
* @author Jonas Wagner / http://29a.ch/ && http://29a.ch/slides/2012/webglwater/ : Water shader explanations in WebGL
|
||||
*/
|
||||
|
||||
THREE.Water = function (width, height, options)
|
||||
{
|
||||
|
||||
THREE.Mesh.call(this, new THREE.PlaneBufferGeometry(width, height));
|
||||
|
||||
var scope = this;
|
||||
|
||||
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();
|
||||
|
||||
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);
|
||||
|
||||
if (!THREE.Math.isPowerOfTwo(textureWidth) || !THREE.Math.isPowerOfTwo(textureHeight)) {
|
||||
|
||||
renderTarget.texture.generateMipmaps = false;
|
||||
|
||||
}
|
||||
|
||||
var mirrorShader = {
|
||||
|
||||
uniforms: THREE.UniformsUtils.merge([
|
||||
THREE.UniformsLib['fog'],
|
||||
THREE.UniformsLib['lights'],
|
||||
{
|
||||
normalSampler: { value: null },
|
||||
mirrorSampler: { value: null },
|
||||
alpha: { value: 1.0 },
|
||||
time: { value: 0.0 },
|
||||
size: { value: 1.0 },
|
||||
distortionScale: { value: 20.0 },
|
||||
noiseScale: { value: 1.0 },
|
||||
textureMatrix: { value: new THREE.Matrix4() },
|
||||
sunColor: { value: new THREE.Color(0x7F7F7F) },
|
||||
sunDirection: { value: new THREE.Vector3(0.70707, 0.70707, 0) },
|
||||
eye: { value: new THREE.Vector3() },
|
||||
waterColor: { value: new THREE.Color(0x555555) }
|
||||
}
|
||||
]),
|
||||
|
||||
vertexShader: [
|
||||
'uniform mat4 textureMatrix;',
|
||||
'uniform float time;',
|
||||
|
||||
'varying vec4 mirrorCoord;',
|
||||
'varying vec4 worldPosition;',
|
||||
|
||||
THREE.ShaderChunk['fog_pars_vertex'],
|
||||
THREE.ShaderChunk['shadowmap_pars_vertex'],
|
||||
|
||||
'void main() {',
|
||||
' mirrorCoord = modelMatrix * vec4( position, 1.0 );',
|
||||
' worldPosition = mirrorCoord.xyzw;',
|
||||
' mirrorCoord = textureMatrix * mirrorCoord;',
|
||||
' vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );',
|
||||
' gl_Position = projectionMatrix * mvPosition;',
|
||||
|
||||
THREE.ShaderChunk['fog_vertex'],
|
||||
THREE.ShaderChunk['shadowmap_vertex'],
|
||||
|
||||
'}'
|
||||
].join('\n'),
|
||||
|
||||
fragmentShader: [
|
||||
'uniform sampler2D mirrorSampler;',
|
||||
'uniform float alpha;',
|
||||
'uniform float time;',
|
||||
'uniform float size;',
|
||||
'uniform float distortionScale;',
|
||||
'uniform sampler2D normalSampler;',
|
||||
'uniform vec3 sunColor;',
|
||||
'uniform vec3 sunDirection;',
|
||||
'uniform vec3 eye;',
|
||||
'uniform vec3 waterColor;',
|
||||
|
||||
'varying vec4 mirrorCoord;',
|
||||
'varying vec4 worldPosition;',
|
||||
|
||||
'vec4 getNoise( vec2 uv ) {',
|
||||
' vec2 uv0 = ( uv / 103.0 ) + vec2(time / 17.0, time / 29.0);',
|
||||
' vec2 uv1 = uv / 107.0-vec2( time / -19.0, time / 31.0 );',
|
||||
' vec2 uv2 = uv / vec2( 8907.0, 9803.0 ) + vec2( time / 101.0, time / 97.0 );',
|
||||
' vec2 uv3 = uv / vec2( 1091.0, 1027.0 ) - vec2( time / 109.0, time / -113.0 );',
|
||||
' vec4 noise = texture2D( normalSampler, uv0 ) +',
|
||||
' texture2D( normalSampler, uv1 ) +',
|
||||
' texture2D( normalSampler, uv2 ) +',
|
||||
' texture2D( normalSampler, uv3 );',
|
||||
' return noise * 0.5 - 1.0;',
|
||||
'}',
|
||||
|
||||
'void sunLight( const vec3 surfaceNormal, const vec3 eyeDirection, float shiny, float spec, float diffuse, inout vec3 diffuseColor, inout vec3 specularColor ) {',
|
||||
' vec3 reflection = normalize( reflect( -sunDirection, surfaceNormal ) );',
|
||||
' float direction = max( 0.0, dot( eyeDirection, reflection ) );',
|
||||
' specularColor += pow( direction, shiny ) * sunColor * spec;',
|
||||
' diffuseColor += max( dot( sunDirection, surfaceNormal ), 0.0 ) * sunColor * diffuse;',
|
||||
'}',
|
||||
|
||||
THREE.ShaderChunk['common'],
|
||||
THREE.ShaderChunk['packing'],
|
||||
THREE.ShaderChunk['bsdfs'],
|
||||
THREE.ShaderChunk['fog_pars_fragment'],
|
||||
THREE.ShaderChunk['lights_pars'],
|
||||
THREE.ShaderChunk['shadowmap_pars_fragment'],
|
||||
THREE.ShaderChunk['shadowmask_pars_fragment'],
|
||||
|
||||
'void main() {',
|
||||
' vec4 noise = getNoise( worldPosition.xz * size );',
|
||||
' vec3 surfaceNormal = normalize( noise.xzy * vec3( 1.5, 1.0, 1.5 ) );',
|
||||
|
||||
' vec3 diffuseLight = vec3(0.0);',
|
||||
' vec3 specularLight = vec3(0.0);',
|
||||
|
||||
' vec3 worldToEye = eye-worldPosition.xyz;',
|
||||
' vec3 eyeDirection = normalize( worldToEye );',
|
||||
' sunLight( surfaceNormal, eyeDirection, 100.0, 2.0, 0.5, diffuseLight, specularLight );',
|
||||
|
||||
' float distance = length(worldToEye);',
|
||||
|
||||
' vec2 distortion = surfaceNormal.xz * ( 0.001 + 1.0 / distance ) * distortionScale;',
|
||||
' vec3 reflectionSample = vec3( texture2D( mirrorSampler, mirrorCoord.xy / mirrorCoord.z + distortion ) );',
|
||||
|
||||
' float theta = max( dot( eyeDirection, surfaceNormal ), 0.0 );',
|
||||
' float rf0 = 0.3;',
|
||||
' float reflectance = rf0 + ( 1.0 - rf0 ) * pow( ( 1.0 - theta ), 5.0 );',
|
||||
' vec3 scatter = max( 0.0, dot( surfaceNormal, eyeDirection ) ) * waterColor;',
|
||||
' vec3 albedo = mix( ( sunColor * diffuseLight * 0.3 + scatter ) * getShadowMask(), ( vec3( 0.1 ) + reflectionSample * 0.9 + reflectionSample * specularLight ), reflectance);',
|
||||
' vec3 outgoingLight = albedo;',
|
||||
' gl_FragColor = vec4( outgoingLight, alpha );',
|
||||
|
||||
THREE.ShaderChunk['tonemapping_fragment'],
|
||||
THREE.ShaderChunk['fog_fragment'],
|
||||
|
||||
'}'
|
||||
].join('\n')
|
||||
|
||||
};
|
||||
|
||||
var material = new THREE.ShaderMaterial({
|
||||
fragmentShader: mirrorShader.fragmentShader,
|
||||
vertexShader: mirrorShader.vertexShader,
|
||||
uniforms: THREE.UniformsUtils.clone(mirrorShader.uniforms),
|
||||
transparent: true,
|
||||
lights: true,
|
||||
side: side,
|
||||
fog: fog
|
||||
});
|
||||
|
||||
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;
|
||||
|
||||
scope.material = material;
|
||||
|
||||
scope.onBeforeRender = function (renderer, scene, camera)
|
||||
{
|
||||
|
||||
mirrorWorldPosition.setFromMatrixPosition(scope.matrixWorld);
|
||||
cameraWorldPosition.setFromMatrixPosition(camera.matrixWorld);
|
||||
|
||||
rotationMatrix.extractRotation(scope.matrixWorld);
|
||||
|
||||
normal.set(0, 0, 1);
|
||||
normal.applyMatrix4(rotationMatrix);
|
||||
|
||||
view.subVectors(mirrorWorldPosition, cameraWorldPosition);
|
||||
|
||||
// Avoid rendering when mirror is facing away
|
||||
|
||||
if (view.dot(normal) > 0) return;
|
||||
|
||||
view.reflect(normal).negate();
|
||||
view.add(mirrorWorldPosition);
|
||||
|
||||
rotationMatrix.extractRotation(camera.matrixWorld);
|
||||
|
||||
lookAtPosition.set(0, 0, - 1);
|
||||
lookAtPosition.applyMatrix4(rotationMatrix);
|
||||
lookAtPosition.add(cameraWorldPosition);
|
||||
|
||||
target.subVectors(mirrorWorldPosition, lookAtPosition);
|
||||
target.reflect(normal).negate();
|
||||
target.add(mirrorWorldPosition);
|
||||
|
||||
mirrorCamera.position.copy(view);
|
||||
mirrorCamera.up.set(0, 1, 0);
|
||||
mirrorCamera.up.applyMatrix4(rotationMatrix);
|
||||
mirrorCamera.up.reflect(normal);
|
||||
mirrorCamera.lookAt(target);
|
||||
|
||||
mirrorCamera.far = camera.far; // Used in WebGLBackground
|
||||
|
||||
mirrorCamera.updateMatrixWorld();
|
||||
mirrorCamera.projectionMatrix.copy(camera.projectionMatrix);
|
||||
|
||||
// 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
|
||||
mirrorPlane.setFromNormalAndCoplanarPoint(normal, mirrorWorldPosition);
|
||||
mirrorPlane.applyMatrix4(mirrorCamera.matrixWorldInverse);
|
||||
|
||||
clipPlane.set(mirrorPlane.normal.x, mirrorPlane.normal.y, mirrorPlane.normal.z, mirrorPlane.constant);
|
||||
|
||||
var projectionMatrix = mirrorCamera.projectionMatrix;
|
||||
|
||||
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
|
||||
clipPlane.multiplyScalar(2.0 / clipPlane.dot(q));
|
||||
|
||||
// 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;
|
||||
|
||||
eye.setFromMatrixPosition(camera.matrixWorld);
|
||||
|
||||
//
|
||||
|
||||
var currentRenderTarget = renderer.getRenderTarget();
|
||||
|
||||
var currentVrEnabled = renderer.vr.enabled;
|
||||
var currentShadowAutoUpdate = renderer.shadowMap.autoUpdate;
|
||||
|
||||
scope.visible = false;
|
||||
|
||||
renderer.vr.enabled = false; // Avoid camera modification and recursion
|
||||
renderer.shadowMap.autoUpdate = false; // Avoid re-computing shadows
|
||||
|
||||
renderer.render(scene, mirrorCamera, renderTarget, true);
|
||||
|
||||
scope.visible = true;
|
||||
|
||||
renderer.vr.enabled = currentVrEnabled;
|
||||
renderer.shadowMap.autoUpdate = currentShadowAutoUpdate;
|
||||
|
||||
renderer.setRenderTarget(currentRenderTarget);
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
THREE.Water.prototype = Object.create(THREE.Mesh.prototype);
|
||||
THREE.Water.prototype.constructor = THREE.Water;
|
@ -1,341 +0,0 @@
|
||||
/**
|
||||
* @author Mugen87 / https://github.com/Mugen87
|
||||
*
|
||||
* References:
|
||||
* http://www.valvesoftware.com/publications/2010/siggraph2010_vlachos_waterflow.pdf
|
||||
* http://graphicsrunner.blogspot.de/2010/08/water-using-flow-maps.html
|
||||
*
|
||||
*/
|
||||
|
||||
THREE.Water = function (width, height, options)
|
||||
{
|
||||
|
||||
THREE.Mesh.call(this, new THREE.PlaneBufferGeometry(width, height));
|
||||
|
||||
this.type = 'Water';
|
||||
|
||||
var scope = this;
|
||||
|
||||
options = options || {};
|
||||
|
||||
var color = (options.color !== undefined) ? new THREE.Color(options.color) : new THREE.Color(0xFFFFFF);
|
||||
var textureWidth = options.textureWidth || 512;
|
||||
var textureHeight = options.textureHeight || 512;
|
||||
var clipBias = options.clipBias || 0;
|
||||
var flowDirection = options.flowDirection || new THREE.Vector2(1, 0);
|
||||
var flowSpeed = options.flowSpeed || 0.03;
|
||||
var reflectivity = options.reflectivity || 0.02;
|
||||
var scale = options.scale || 1;
|
||||
var shader = options.shader || THREE.Water.WaterShader;
|
||||
|
||||
var textureLoader = new THREE.TextureLoader();
|
||||
|
||||
var flowMap = options.flowMap || undefined;
|
||||
var normalMap0 = options.normalMap0 || textureLoader.load('textures/water/Water_1_M_Normal.jpg');
|
||||
var normalMap1 = options.normalMap1 || textureLoader.load('textures/water/Water_2_M_Normal.jpg');
|
||||
|
||||
var cycle = 0.15; // a cycle of a flow map phase
|
||||
var halfCycle = cycle * 0.5;
|
||||
var textureMatrix = new THREE.Matrix4();
|
||||
var clock = new THREE.Clock();
|
||||
|
||||
// internal components
|
||||
|
||||
if (THREE.Reflector === undefined) {
|
||||
|
||||
console.error('THREE.Water: Required component THREE.Reflector not found.');
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if (THREE.Refractor === undefined) {
|
||||
|
||||
console.error('THREE.Water: Required component THREE.Refractor not found.');
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
var reflector = new THREE.Reflector(width, height, {
|
||||
textureWidth: textureWidth,
|
||||
textureHeight: textureHeight,
|
||||
clipBias: clipBias
|
||||
});
|
||||
|
||||
var refractor = new THREE.Refractor(width, height, {
|
||||
textureWidth: textureWidth,
|
||||
textureHeight: textureHeight,
|
||||
clipBias: clipBias
|
||||
});
|
||||
|
||||
reflector.matrixAutoUpdate = false;
|
||||
refractor.matrixAutoUpdate = false;
|
||||
|
||||
// material
|
||||
|
||||
this.material = new THREE.ShaderMaterial({
|
||||
uniforms: THREE.UniformsUtils.merge([
|
||||
THREE.UniformsLib['fog'],
|
||||
shader.uniforms
|
||||
]),
|
||||
vertexShader: shader.vertexShader,
|
||||
fragmentShader: shader.fragmentShader,
|
||||
transparent: true,
|
||||
fog: true
|
||||
});
|
||||
|
||||
if (flowMap !== undefined) {
|
||||
|
||||
this.material.defines.USE_FLOWMAP = '';
|
||||
this.material.uniforms.tFlowMap = {
|
||||
type: 't',
|
||||
value: flowMap
|
||||
};
|
||||
|
||||
} else {
|
||||
|
||||
this.material.uniforms.flowDirection = {
|
||||
type: 'v2',
|
||||
value: flowDirection
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// maps
|
||||
|
||||
normalMap0.wrapS = normalMap0.wrapT = THREE.RepeatWrapping;
|
||||
normalMap1.wrapS = normalMap1.wrapT = THREE.RepeatWrapping;
|
||||
|
||||
this.material.uniforms.tReflectionMap.value = reflector.getRenderTarget().texture;
|
||||
this.material.uniforms.tRefractionMap.value = refractor.getRenderTarget().texture;
|
||||
this.material.uniforms.tNormalMap0.value = normalMap0;
|
||||
this.material.uniforms.tNormalMap1.value = normalMap1;
|
||||
|
||||
// water
|
||||
|
||||
this.material.uniforms.color.value = color;
|
||||
this.material.uniforms.reflectivity.value = reflectivity;
|
||||
this.material.uniforms.textureMatrix.value = textureMatrix;
|
||||
|
||||
// inital values
|
||||
|
||||
this.material.uniforms.config.value.x = 0; // flowMapOffset0
|
||||
this.material.uniforms.config.value.y = halfCycle; // flowMapOffset1
|
||||
this.material.uniforms.config.value.z = halfCycle; // halfCycle
|
||||
this.material.uniforms.config.value.w = scale; // scale
|
||||
|
||||
// functions
|
||||
|
||||
function updateTextureMatrix(camera)
|
||||
{
|
||||
|
||||
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(camera.projectionMatrix);
|
||||
textureMatrix.multiply(camera.matrixWorldInverse);
|
||||
textureMatrix.multiply(scope.matrixWorld);
|
||||
|
||||
}
|
||||
|
||||
function updateFlow()
|
||||
{
|
||||
|
||||
var delta = clock.getDelta();
|
||||
var config = scope.material.uniforms.config;
|
||||
|
||||
config.value.x += flowSpeed * delta; // flowMapOffset0
|
||||
config.value.y = config.value.x + halfCycle; // flowMapOffset1
|
||||
|
||||
// Important: The distance between offsets should be always the value of "halfCycle".
|
||||
// Moreover, both offsets should be in the range of [ 0, cycle ].
|
||||
// This approach ensures a smooth water flow and avoids "reset" effects.
|
||||
|
||||
if (config.value.x >= cycle) {
|
||||
|
||||
config.value.x = 0;
|
||||
config.value.y = halfCycle;
|
||||
|
||||
} else if (config.value.y >= cycle) {
|
||||
|
||||
config.value.y = config.value.y - cycle;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
this.onBeforeRender = function (renderer, scene, camera)
|
||||
{
|
||||
|
||||
updateTextureMatrix(camera);
|
||||
updateFlow();
|
||||
|
||||
scope.visible = false;
|
||||
|
||||
reflector.matrixWorld.copy(scope.matrixWorld);
|
||||
refractor.matrixWorld.copy(scope.matrixWorld);
|
||||
|
||||
reflector.onBeforeRender(renderer, scene, camera);
|
||||
refractor.onBeforeRender(renderer, scene, camera);
|
||||
|
||||
scope.visible = true;
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
THREE.Water.prototype = Object.create(THREE.Mesh.prototype);
|
||||
THREE.Water.prototype.constructor = THREE.Water;
|
||||
|
||||
THREE.Water.WaterShader = {
|
||||
|
||||
uniforms: {
|
||||
|
||||
'color': {
|
||||
type: 'c',
|
||||
value: null
|
||||
},
|
||||
|
||||
'reflectivity': {
|
||||
type: 'f',
|
||||
value: 0
|
||||
},
|
||||
|
||||
'tReflectionMap': {
|
||||
type: 't',
|
||||
value: null
|
||||
},
|
||||
|
||||
'tRefractionMap': {
|
||||
type: 't',
|
||||
value: null
|
||||
},
|
||||
|
||||
'tNormalMap0': {
|
||||
type: 't',
|
||||
value: null
|
||||
},
|
||||
|
||||
'tNormalMap1': {
|
||||
type: 't',
|
||||
value: null
|
||||
},
|
||||
|
||||
'textureMatrix': {
|
||||
type: 'm4',
|
||||
value: null
|
||||
},
|
||||
|
||||
'config': {
|
||||
type: 'v4',
|
||||
value: new THREE.Vector4()
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
vertexShader: [
|
||||
|
||||
'#include <fog_pars_vertex>',
|
||||
|
||||
'uniform mat4 textureMatrix;',
|
||||
|
||||
'varying vec4 vCoord;',
|
||||
'varying vec2 vUv;',
|
||||
'varying vec3 vToEye;',
|
||||
|
||||
'void main() {',
|
||||
|
||||
' vUv = uv;',
|
||||
' vCoord = textureMatrix * vec4( position, 1.0 );',
|
||||
|
||||
' vec4 worldPosition = modelMatrix * vec4( position, 1.0 );',
|
||||
' vToEye = cameraPosition - worldPosition.xyz;',
|
||||
|
||||
' vec4 mvPosition = viewMatrix * worldPosition;', // used in fog_vertex
|
||||
' gl_Position = projectionMatrix * mvPosition;',
|
||||
|
||||
' #include <fog_vertex>',
|
||||
|
||||
'}'
|
||||
|
||||
].join('\n'),
|
||||
|
||||
fragmentShader: [
|
||||
|
||||
'#include <fog_pars_fragment>',
|
||||
|
||||
'uniform sampler2D tReflectionMap;',
|
||||
'uniform sampler2D tRefractionMap;',
|
||||
'uniform sampler2D tNormalMap0;',
|
||||
'uniform sampler2D tNormalMap1;',
|
||||
|
||||
'#ifdef USE_FLOWMAP',
|
||||
' uniform sampler2D tFlowMap;',
|
||||
'#else',
|
||||
' uniform vec2 flowDirection;',
|
||||
'#endif',
|
||||
|
||||
'uniform vec3 color;',
|
||||
'uniform float reflectivity;',
|
||||
'uniform vec4 config;',
|
||||
|
||||
'varying vec4 vCoord;',
|
||||
'varying vec2 vUv;',
|
||||
'varying vec3 vToEye;',
|
||||
|
||||
'void main() {',
|
||||
|
||||
' float flowMapOffset0 = config.x;',
|
||||
' float flowMapOffset1 = config.y;',
|
||||
' float halfCycle = config.z;',
|
||||
' float scale = config.w;',
|
||||
|
||||
' vec3 toEye = normalize( vToEye );',
|
||||
|
||||
// determine flow direction
|
||||
' vec2 flow;',
|
||||
' #ifdef USE_FLOWMAP',
|
||||
' flow = texture2D( tFlowMap, vUv ).rg * 2.0 - 1.0;',
|
||||
' #else',
|
||||
' flow = flowDirection;',
|
||||
' #endif',
|
||||
' flow.x *= - 1.0;',
|
||||
|
||||
// sample normal maps (distort uvs with flowdata)
|
||||
' vec4 normalColor0 = texture2D( tNormalMap0, ( vUv * scale ) + flow * flowMapOffset0 );',
|
||||
' vec4 normalColor1 = texture2D( tNormalMap1, ( vUv * scale ) + flow * flowMapOffset1 );',
|
||||
|
||||
// linear interpolate to get the final normal color
|
||||
' float flowLerp = abs( halfCycle - flowMapOffset0 ) / halfCycle;',
|
||||
' vec4 normalColor = mix( normalColor0, normalColor1, flowLerp );',
|
||||
|
||||
// calculate normal vector
|
||||
' vec3 normal = normalize( vec3( normalColor.r * 2.0 - 1.0, normalColor.b, normalColor.g * 2.0 - 1.0 ) );',
|
||||
|
||||
// calculate the fresnel term to blend reflection and refraction maps
|
||||
' float theta = max( dot( toEye, normal ), 0.0 );',
|
||||
' float reflectance = reflectivity + ( 1.0 - reflectivity ) * pow( ( 1.0 - theta ), 5.0 );',
|
||||
|
||||
// calculate final uv coords
|
||||
' vec3 coord = vCoord.xyz / vCoord.w;',
|
||||
' vec2 uv = coord.xy + coord.z * normal.xz * 0.05;',
|
||||
|
||||
' vec4 reflectColor = texture2D( tReflectionMap, uv );',
|
||||
' vec4 refractColor = texture2D( tRefractionMap, uv );',
|
||||
|
||||
// multiply water color with the mix of both textures
|
||||
' gl_FragColor = vec4( color, 1.0 ) * mix( refractColor, reflectColor, reflectance );',
|
||||
|
||||
' #include <tonemapping_fragment>',
|
||||
' #include <encodings_fragment>',
|
||||
' #include <fog_fragment>',
|
||||
|
||||
'}'
|
||||
|
||||
].join('\n')
|
||||
};
|
Loading…
Reference in new issue