three.js bloom添加深度測試

/**
 * @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 的泛光效果沒有深度監測方面的處理,上面是處理的代碼,後續會繼續完善

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章