pull/821/MERGE
ChenX 5 years ago
parent 69d19ca74b
commit 10c3f32a3d

@ -129,17 +129,6 @@ export async function copyTextToClipboard(text: string)
return await navigator["clipboard"].writeText(text); return await navigator["clipboard"].writeText(text);
} }
globalThis["copy"] = (text: string) =>
{
console.log("你有2秒的时间让页面聚焦,否则将无法拷贝!");
setTimeout(async () =>
{
await copyTextToClipboard(text);
console.log("拷贝成功!");
}, 2000);
};
//ref: https://stackoverflow.com/questions/400212/how-do-i-copy-to-the-clipboard-in-javascript //ref: https://stackoverflow.com/questions/400212/how-do-i-copy-to-the-clipboard-in-javascript
/** /**

@ -1,6 +1,7 @@
import { Intent } from '@blueprintjs/core'; import { Intent } from '@blueprintjs/core';
import { Cache, Layers, Object3D } from 'three'; import { Cache, Layers, Object3D } from 'three';
import { ErrorMonitoring } from './Common/ErrorMonitoring'; import { ErrorMonitoring } from './Common/ErrorMonitoring';
import { copyTextToClipboard } from './Common/Utils';
import { AppToaster } from './UI/Components/Toaster'; import { AppToaster } from './UI/Components/Toaster';
import './UI/Css/blue.less'; import './UI/Css/blue.less';
import './UI/Css/golden.less'; import './UI/Css/golden.less';
@ -121,3 +122,13 @@ window.onload = function ()
new ErrorMonitoring(); new ErrorMonitoring();
new WebCAD(); new WebCAD();
}; };
globalThis["copy"] = (text: string) =>
{
console.log("你有2秒的时间让页面聚焦,否则将无法拷贝!");
setTimeout(async () =>
{
await copyTextToClipboard(text);
console.log("拷贝成功!");
}, 2000);
};

@ -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,344 +0,0 @@
/**
* @author Mugen87 / https://github.com/Mugen87
*
*/
THREE.Refractor = function (width, height, options)
{
THREE.Mesh.call(this, new THREE.PlaneBufferGeometry(width, height));
this.type = 'Refractor';
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.Refractor.RefractorShader;
//
var virtualCamera = new THREE.PerspectiveCamera();
virtualCamera.matrixAutoUpdate = false;
virtualCamera.userData.refractor = true;
//
var refractorPlane = new THREE.Plane();
var textureMatrix = new THREE.Matrix4();
// render target
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;
}
// material
this.material = new THREE.ShaderMaterial({
uniforms: THREE.UniformsUtils.clone(shader.uniforms),
vertexShader: shader.vertexShader,
fragmentShader: shader.fragmentShader,
transparent: true // ensures, refractors are drawn from farthest to closest
});
this.material.uniforms.color.value = color;
this.material.uniforms.tDiffuse.value = renderTarget.texture;
this.material.uniforms.textureMatrix.value = textureMatrix;
// functions
var visible = (function ()
{
var refractorWorldPosition = new THREE.Vector3();
var cameraWorldPosition = new THREE.Vector3();
var rotationMatrix = new THREE.Matrix4();
var view = new THREE.Vector3();
var normal = new THREE.Vector3();
return function visible(camera)
{
refractorWorldPosition.setFromMatrixPosition(scope.matrixWorld);
cameraWorldPosition.setFromMatrixPosition(camera.matrixWorld);
view.subVectors(refractorWorldPosition, cameraWorldPosition);
rotationMatrix.extractRotation(scope.matrixWorld);
normal.set(0, 0, 1);
normal.applyMatrix4(rotationMatrix);
return view.dot(normal) < 0;
};
})();
var updateRefractorPlane = (function ()
{
var normal = new THREE.Vector3();
var position = new THREE.Vector3();
var quaternion = new THREE.Quaternion();
var scale = new THREE.Vector3();
return function updateRefractorPlane()
{
scope.matrixWorld.decompose(position, quaternion, scale);
normal.set(0, 0, 1).applyQuaternion(quaternion).normalize();
// flip the normal because we want to cull everything above the plane
normal.negate();
refractorPlane.setFromNormalAndCoplanarPoint(normal, position);
};
})();
var updateVirtualCamera = (function ()
{
var clipPlane = new THREE.Plane();
var clipVector = new THREE.Vector4();
var q = new THREE.Vector4();
return function updateVirtualCamera(camera)
{
virtualCamera.matrixWorld.copy(camera.matrixWorld);
virtualCamera.matrixWorldInverse.getInverse(virtualCamera.matrixWorld);
virtualCamera.projectionMatrix.copy(camera.projectionMatrix);
virtualCamera.far = camera.far; // used in WebGLBackground
// The following code creates an oblique view frustum for clipping.
// see: Lengyel, Eric. “Oblique View Frustum Depth Projection and Clipping”.
// Journal of Game Development, Vol. 1, No. 2 (2005), Charles River Media, pp. 516
clipPlane.copy(refractorPlane);
clipPlane.applyMatrix4(virtualCamera.matrixWorldInverse);
clipVector.set(clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.constant);
// calculate the clip-space corner point opposite the clipping plane and
// transform it into camera space by multiplying it by the inverse of the projection matrix
var projectionMatrix = virtualCamera.projectionMatrix;
q.x = (Math.sign(clipVector.x) + projectionMatrix.elements[8]) / projectionMatrix.elements[0];
q.y = (Math.sign(clipVector.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
clipVector.multiplyScalar(2.0 / clipVector.dot(q));
// replacing the third row of the projection matrix
projectionMatrix.elements[2] = clipVector.x;
projectionMatrix.elements[6] = clipVector.y;
projectionMatrix.elements[10] = clipVector.z + 1.0 - clipBias;
projectionMatrix.elements[14] = clipVector.w;
};
})();
// This will update the texture matrix that is used for projective texture mapping in the shader.
// see: http://developer.download.nvidia.com/assets/gamedev/docs/projective_texture_mapping.pdf
function updateTextureMatrix(camera)
{
// this matrix does range mapping to [ 0, 1 ]
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
);
// we use "Object Linear Texgen", so we need to multiply the texture matrix T
// (matrix above) with the projection and view matrix of the virtual camera
// and the model matrix of the refractor
textureMatrix.multiply(camera.projectionMatrix);
textureMatrix.multiply(camera.matrixWorldInverse);
textureMatrix.multiply(scope.matrixWorld);
}
//
var render = (function ()
{
var viewport = new THREE.Vector4();
return function render(renderer, scene, camera)
{
scope.visible = false;
var currentRenderTarget = renderer.getRenderTarget();
var currentVrEnabled = renderer.vr.enabled;
var currentShadowAutoUpdate = renderer.shadowMap.autoUpdate;
renderer.vr.enabled = false; // avoid camera modification
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.onBeforeRender = function (renderer, scene, camera)
{
// ensure refractors are rendered only once per frame
if (camera.userData.refractor === true) return;
// avoid rendering when the refractor is viewed from behind
if (!visible(camera) === true) return;
// update
updateRefractorPlane();
updateTextureMatrix(camera);
updateVirtualCamera(camera);
render(renderer, scene, camera);
};
this.getRenderTarget = function ()
{
return renderTarget;
};
};
THREE.Refractor.prototype = Object.create(THREE.Mesh.prototype);
THREE.Refractor.prototype.constructor = THREE.Refractor;
THREE.Refractor.RefractorShader = {
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,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…
Cancel
Save