/**
* @author alteredq / http://alteredqualia.com/
*
* Convolution shader
* ported from o3d sample to WebGL / GLSL
* http://o3d.googlecode.com/svn/trunk/samples/convolution.html
*/
//卷積
THREE.ConvolutionShader = {
defines: {
"KERNEL_SIZE_FLOAT": "25.0",
"KERNEL_SIZE_INT": "25"
},
uniforms: {
"tDiffuse": { value: null },
"uImageIncrement": { value: new THREE.Vector2( 0.001953125, 0.0 ) },
"cKernel": { value: [] }
},
vertexShader: [
"uniform vec2 uImageIncrement;",
"varying vec2 vUv;",
"void main() {",
"vUv = uv - ( ( KERNEL_SIZE_FLOAT - 1.0 ) / 2.0 ) * uImageIncrement;",
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
"}"
].join( "\n" ),
fragmentShader: [
"uniform float cKernel[ KERNEL_SIZE_INT ];",
"uniform sampler2D tDiffuse;",
"uniform vec2 uImageIncrement;",
"varying vec2 vUv;",
"void main() {",
"vec2 imageCoord = vUv;",
"vec4 sum = vec4( 0.0, 0.0, 0.0, 0.0 );",
"for( int i = 0; i < KERNEL_SIZE_INT; i ++ ) {",
"vec4 tex = texture2D( tDiffuse, imageCoord );",
"float xx = 1.0; ",
"#if defined( USE_COLOR_WEIGTH )",
"if((tex.r + tex.g + tex.b) / 3.0 > 0.0) xx = 2.5; else xx = 0.4;",
"#endif",
"sum += texture2D( tDiffuse, imageCoord ) * cKernel[ i ] * xx;",
"imageCoord += uImageIncrement;",
"}",
"gl_FragColor = sum;",
"}"
].join( "\n" ),
buildKernel: function ( sigma ) {
// We lop off the sqrt(2 * pi) * sigma term, since we're going to normalize anyway.
function gauss( x, sigma ) {
return Math.exp( - ( x * x ) / ( 2.0 * sigma * sigma ) );
}
var i, values, sum, halfWidth, kMaxKernelSize = 25, kernelSize = 2 * Math.ceil( sigma * 3.0 ) + 1;
if ( kernelSize > kMaxKernelSize ) kernelSize = kMaxKernelSize;
halfWidth = ( kernelSize - 1 ) * 0.5;
//創建一個數組
values = new Array( kernelSize );
sum = 0.0;
for ( i = 0; i < kernelSize; ++ i ) {
values[ i ] = gauss( i - halfWidth, sigma );
sum += values[ i ];
}
// normalize the kernel
for ( i = 0; i < kernelSize; ++ i ) values[ i ] /= sum;
return values;
}
};
/**
* @author alteredq / http://alteredqualia.com/
*/
//圖片邊緣有過度色,物體沒有
//邊緣檢測是個好主意
THREE.BloomPass2 = function ( scenes, camera, resolution, strength, kernelSize, sigma) {
THREE.Pass.call( this );
//多個場景
this.renderScenes = scenes;
this.renderCamera = camera;
this.frontScenes = scenes[scenes.length - 1];
strength = ( strength !== undefined ) ? strength : 1;
kernelSize = ( kernelSize !== undefined ) ? kernelSize : 25;
sigma = ( sigma !== undefined ) ? sigma : 4.0;
resolution = ( resolution !== undefined ) ? resolution : new THREE.Vector2(256,256);
this.step = 4.0;
//this.blurX = new THREE.Vector2( this.step / resolution.x, 0.0 );
//this.blurY = new THREE.Vector2( 0, this.step / resolution.y );
this.blurY = new THREE.Vector2(0.0, 0.001953125);
this.blurX = new THREE.Vector2(this.blurY.y * resolution.y / resolution.x, 0.0);
// render targets
var backBufferPars = {
format: THREE.RGBAFormat,
stencilBuffer: false
};
this.renderTargetBackBuffer = new THREE.WebGLMultisampleRenderTarget(resolution.x, resolution.y, backBufferPars);
this.renderTargetBackBuffer.texture.name = "BloomPass2.back";
this.renderTargetBackBuffer.texture.generateMipmaps = false;
var frontBufferPars = {
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBAFormat,
stencilBuffer: false
};
this.renderTargetX = new THREE.WebGLRenderTarget(resolution.x, resolution.y, frontBufferPars );
this.renderTargetX.texture.name = "BloomPass2.x";
this.renderTargetY = new THREE.WebGLRenderTarget(resolution.x, resolution.y, frontBufferPars );
this.renderTargetY.texture.name = "BloomPass2.y";
this.frontMaterial = this.getFrontMaterial();
this.frontMaterial1 = this.getFrontMaterial1();
// copy material
if ( THREE.CopyShader === undefined )
console.error( "THREE.BloomPass2 relies on THREE.CopyShader" );
var copyShader = THREE.CopyShader;
this.copyUniforms = THREE.UniformsUtils.clone( copyShader.uniforms );
this.copyUniforms[ "opacity" ].value = strength;
this.materialCopy = new THREE.ShaderMaterial( {
uniforms: this.copyUniforms,
vertexShader: copyShader.vertexShader,
fragmentShader: copyShader.fragmentShader,
blending: THREE.AdditiveBlending,
transparent: true
} );
// convolution material
if ( THREE.ConvolutionShader === undefined )
console.error( "THREE.BloomPass relies on THREE.ConvolutionShader" );
var convolutionShader = THREE.ConvolutionShader;
this.convolutionUniforms = THREE.UniformsUtils.clone( convolutionShader.uniforms );
this.convolutionUniforms[ "uImageIncrement" ].value = this.blurX;
this.convolutionUniforms[ "cKernel" ].value = THREE.ConvolutionShader.buildKernel( sigma );
this.materialConvolution = new THREE.ShaderMaterial( {
uniforms: this.convolutionUniforms,
vertexShader: convolutionShader.vertexShader,
fragmentShader: convolutionShader.fragmentShader,
defines: {
"KERNEL_SIZE_FLOAT": kernelSize.toFixed( 1 ),
"KERNEL_SIZE_INT": kernelSize.toFixed(0),
"USE_COLOR_WEIGTH": true
},
transparent: true
});
this.needsSwap = false;
this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
this.scene = new THREE.Scene();
this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
this.quad.frustumCulled = false; // Avoid getting clipped
this.scene.add( this.quad );
};
THREE.BloomPass2.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.BloomPass2,
render: function ( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) {
//保存原始參數
if ( maskActive ) renderer.context.disable( renderer.context.STENCIL_TEST );
var oldClearColor = new THREE.Color().copy(renderer.getClearColor());
var oldClearAlpha = renderer.getClearAlpha();
var oldAutoClear = renderer.autoClear;
renderer.autoClear = false;
//渲染物體
renderer.setRenderTarget(this.renderTargetBackBuffer);
renderer.clear();
renderer.render(this.renderScenes[0].add(this.renderScenes[1]), this.renderCamera);
//拷貝顏色
if(this.renderToScreen)
renderer.setRenderTarget(null);
else
renderer.setRenderTarget(readBuffer);
renderer.setClearColor(oldClearColor, oldClearAlpha);
renderer.clear();
this.quad.material = this.materialCopy;
this.copyUniforms[ "tDiffuse" ].value = this.renderTargetBackBuffer.texture;
renderer.render(this.scene, this.camera);
//清除顏色保留深度、渲染前景
renderer.setClearColor(new THREE.Color(0.0,0.0,0.0), 0.0);
renderer.setRenderTarget(this.renderTargetBackBuffer);
renderer.clearColor();
renderer.render(this.frontScenes, this.renderCamera);
// 3 blur
this.quad.material = this.materialConvolution;
this.convolutionUniforms[ "tDiffuse" ].value = this.renderTargetBackBuffer.texture;
this.convolutionUniforms[ "uImageIncrement" ].value = this.blurX;
renderer.setRenderTarget( this.renderTargetX );
renderer.clear();
renderer.render( this.scene, this.camera );
this.convolutionUniforms[ "tDiffuse" ].value = this.renderTargetX.texture;
this.convolutionUniforms[ "uImageIncrement" ].value = this.blurY;
renderer.setRenderTarget( this.renderTargetY );
renderer.clear();
renderer.render( this.scene, this.camera );
if(this.renderToScreen)
renderer.setRenderTarget(null);
else
renderer.setRenderTarget(readBuffer);
//這一部分鋸齒比較嚴重
this.quad.material = this.frontMaterial1;
this.frontMaterial1.uniforms[ "tDiffuse" ].value = this.renderTargetBackBuffer.texture;
renderer.render( this.scene, this.camera);
this.quad.material = this.frontMaterial;
this.frontMaterial.uniforms[ "tDiffuse" ].value = this.renderTargetY.texture;
renderer.render( this.scene, this.camera);
if (maskActive) renderer.context.enable(renderer.context.STENCIL_TEST);
renderer.setClearColor(oldClearColor, oldClearAlpha);
renderer.autoClear = oldAutoClear;
//TODO
this.renderScenes[0].remove(this.renderScenes[1])
},
setSize: function(width,height){
this.renderTargetBackBuffer.setSize(width,height);
this.renderTargetX.setSize(width,height);
this.renderTargetY.setSize(width,height);
//this.blurX.x = this.step / width;
//this.blurY.y = this.step / height;
this.blurX = new THREE.Vector2(this.blurY.y * height / width, 0.0);
},
//使用dxfx中前後像素的差值看看趨勢
getFrontMaterial: function() {
let material = new THREE.ShaderMaterial({
uniforms: {
"tDiffuse": { value: null },
"opacity": { value: 1.0 },
},
vertexShader:
`varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}`,
fragmentShader:
`uniform float opacity;
uniform sampler2D tDiffuse;
varying vec2 vUv;
void main() {
vec4 texel = texture2D( tDiffuse, vUv );
gl_FragColor = vec4(texel.rgb, opacity);
if((texel.r + texel.g + texel.b) == 0.0)
discard;
}`,
transparent: true,
blending:THREE.AdditiveBlending
});
return material;
},
getFrontMaterial1: function() {
let material = new THREE.ShaderMaterial({
uniforms: {
"tDiffuse": { value: null }
},
vertexShader:
`varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}`,
fragmentShader:
`
uniform sampler2D tDiffuse;
varying vec2 vUv;
void main() {
vec4 texel = texture2D( tDiffuse, vUv );
gl_FragColor = texel;
if(texel.r < 0.01 && texel.g < 0.01 && texel.b < 0.01)
discard;
}`,
});
return material;
}
} );
three.js 的泛光效果沒有深度監測方面的處理,上面是處理的代碼,後續會繼續完善