【后处理】THREE后处理管道分析

1.EffectComposer初始化

1.初始化两个WebGLRenderTarget,分别是
writeBuffer = new WebGLRenderTarget()
readBuffer = new WebGLRenderTarget()
2.renderToScreen=true
3.this.passes = [];//放置通道

// 这里就是默认先初始化一个当前场景的图片,给一个
4.this.copyPass = new ShaderPass( CopyShader );

2.render

var pass, i, il = this.passes.length;
for ( i = 0; i < il; i ++ ) {
		pass = this.passes[ i ];
		//pass关闭的话就忽略
		if ( pass.enabled === false ) continue;
		// 此处判断如果后面的pass都是关闭的话将该pass直接输出
		pass.renderToScreen = ( this.renderToScreen && this.isLastEnabledPass( i ) );
		// 该pass渲染操作
		pass.render( this.renderer, this.writeBuffer, this.readBuffer, deltaTime, maskActive );
		// 交换writeBuffer和readBuffer,继续管道上的操作
		if ( pass.needsSwap ) {
			this.swapBuffers();
		}
}

3.第一个通道RenderPass分析

在这里插入图片描述

一般先初始化一个THREE.RenderPass通道,并加到管道中

构造函数

var RenderPass = function (scene, camera, overrideMaterial, clearColor, clearAlpha) {
	Pass.call(this);
	this.scene = scene;
	this.camera = camera;
	this.overrideMaterial = overrideMaterial;// false
	this.clearColor = clearColor;// undefine
	this.clearAlpha = (clearAlpha !== undefined) ? clearAlpha : 0; //0==false
	this.clear = true;
	this.clearDepth = false;
	this.needsSwap = false;
};

render=》第一次渲染scene,输出到readBuffer

render: function ( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {
	var oldAutoClear = renderer.autoClear;// false
	renderer.autoClear = false;
	renderer.setRenderTarget( this.renderToScreen ? null : readBuffer );
	// TODO: Avoid using autoClear properties, see https://github.com/mrdoob/three.js/pull/15571#issuecomment-465669600
	// // true/true/true
	if ( this.clear ) renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
	renderer.render( this.scene, this.camera );
	renderer.autoClear = oldAutoClear;
}

4.本次第二个通道使用并分析UnrealBloomPass

在这里插入图片描述

4.1 初始化

this.enabled = true;
// 不交换read和write缓冲区
this.needsSwap = flase;
this.clear = false;
this.renderToScreen = false;

var UnrealBloomPass = function ( resolution, strength, radius, threshold ) {

	Pass.call( this );

	this.strength = ( strength !== undefined ) ? strength : 1;
	this.radius = radius;
	this.threshold = threshold;
	this.resolution = ( resolution !== undefined ) ? new Vector2( resolution.x, resolution.y ) : new Vector2( 256, 256 );

	// create color only once here, reuse it later inside the render function
	this.clearColor = new Color( 0, 0, 0 );//不重要可忽略

	// render targets
	var pars = { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat };
	this.renderTargetsHorizontal = [];
	this.renderTargetsVertical = [];
	this.nMips = 5;
	var resx = Math.round( this.resolution.x / 2 );
	var resy = Math.round( this.resolution.y / 2 );
 
    // 这里是render中第一个`1. Extract Bright Areas`需要输出的target
	this.renderTargetBright = new WebGLRenderTarget( resx, resy, pars );
	this.renderTargetBright.texture.name = "UnrealBloomPass.bright";
	this.renderTargetBright.texture.generateMipmaps = false;

   // 这里是render中第二个`2. Blur All the mips progressively` 需要输出的target,一共十个,其中renderTargetHorizonal[i]是个中间处理target,renderTargetVertical是每一轮最终的输出
	for ( var i = 0; i < this.nMips; i ++ ) {

		var renderTargetHorizonal = new WebGLRenderTarget( resx, resy, pars );

		renderTargetHorizonal.texture.name = "UnrealBloomPass.h" + i;
		renderTargetHorizonal.texture.generateMipmaps = false;

		this.renderTargetsHorizontal.push( renderTargetHorizonal );

		var renderTargetVertical = new WebGLRenderTarget( resx, resy, pars );

		renderTargetVertical.texture.name = "UnrealBloomPass.v" + i;
		renderTargetVertical.texture.generateMipmaps = false;

		this.renderTargetsVertical.push( renderTargetVertical );

		resx = Math.round( resx / 2 );

		resy = Math.round( resy / 2 );

	}
     
    // 下面部分是`1. Extract Bright Areas`需要初始化的一个shader材质
	// luminosity high pass material
    
	if ( LuminosityHighPassShader === undefined )
		console.error( "UnrealBloomPass relies on LuminosityHighPassShader" );

	var highPassShader = LuminosityHighPassShader;
	this.highPassUniforms = UniformsUtils.clone( highPassShader.uniforms );

	this.highPassUniforms[ "luminosityThreshold" ].value = threshold;
	this.highPassUniforms[ "smoothWidth" ].value = 0.01;

	this.materialHighPassFilter = new ShaderMaterial( {
		uniforms: this.highPassUniforms,
		vertexShader: highPassShader.vertexShader,
		fragmentShader: highPassShader.fragmentShader,
		defines: {}
	} );

    // 下面部分是`2. Blur All the mips progressively`需要初始化的一个shader材质数组
	// Gaussian Blur Materials
	this.separableBlurMaterials = [];
	var kernelSizeArray = [ 3, 5, 7, 9, 11 ];
	var resx = Math.round( this.resolution.x / 2 );
	var resy = Math.round( this.resolution.y / 2 );

	for ( var i = 0; i < this.nMips; i ++ ) {

		this.separableBlurMaterials.push( this.getSeperableBlurMaterial( kernelSizeArray[ i ] ) );

		this.separableBlurMaterials[ i ].uniforms[ "texSize" ].value = new Vector2( resx, resy );

		resx = Math.round( resx / 2 );

		resy = Math.round( resy / 2 );

	}

    // 下面部分是最终的结果,融合上面步骤的结果,需要初始化的一个shader材质
	// Composite material
	this.compositeMaterial = this.getCompositeMaterial( this.nMips );
	this.compositeMaterial.uniforms[ "blurTexture1" ].value = this.renderTargetsVertical[ 0 ].texture;
	this.compositeMaterial.uniforms[ "blurTexture2" ].value = this.renderTargetsVertical[ 1 ].texture;
	this.compositeMaterial.uniforms[ "blurTexture3" ].value = this.renderTargetsVertical[ 2 ].texture;
	this.compositeMaterial.uniforms[ "blurTexture4" ].value = this.renderTargetsVertical[ 3 ].texture;
	this.compositeMaterial.uniforms[ "blurTexture5" ].value = this.renderTargetsVertical[ 4 ].texture;
	this.compositeMaterial.uniforms[ "bloomStrength" ].value = strength;
	this.compositeMaterial.uniforms[ "bloomRadius" ].value = 0.1;
	this.compositeMaterial.needsUpdate = true;

	var bloomFactors = [ 1.0, 0.8, 0.6, 0.4, 0.2 ];
	this.compositeMaterial.uniforms[ "bloomFactors" ].value = bloomFactors;
	this.bloomTintColors = [ new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ),
							 new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ) ];
	this.compositeMaterial.uniforms[ "bloomTintColors" ].value = this.bloomTintColors;

	// copy material
	if ( CopyShader === undefined ) {

		console.error( "UnrealBloomPass relies on CopyShader" );

	}

	var copyShader = CopyShader;

	this.copyUniforms = UniformsUtils.clone( copyShader.uniforms );
	this.copyUniforms[ "opacity" ].value = 1.0;

	this.materialCopy = new ShaderMaterial( {
		uniforms: this.copyUniforms,
		vertexShader: copyShader.vertexShader,
		fragmentShader: copyShader.fragmentShader,
		blending: AdditiveBlending,
		depthTest: false,
		depthWrite: false,
		transparent: true
	} );

	this.enabled = true;
	this.needsSwap = false;

	this.oldClearColor = new Color();
	this.oldClearAlpha = 1;

	this.basic = new MeshBasicMaterial();

    // 用于渲染一个平铺面
	this.fsQuad = new Pass.FullScreenQuad( null );

};

4.2 render

render: function ( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) {

	this.oldClearColor.copy( renderer.getClearColor() );// 0 0 0
	this.oldClearAlpha = renderer.getClearAlpha();// 0
	var oldAutoClear = renderer.autoClear;// false
	renderer.autoClear = false; // 这个一直是不自动清楚的,一直是false
	renderer.setClearColor( this.clearColor, 0 );
	
	// 看结果下面整个注释了也行
	// 下面会清除mapbox要素,需要改动
	// if ( this.renderToScreen ) {
	// 	this.fsQuad.material = this.basic;
	// 	this.basic.map = readBuffer.texture;
	// 	renderer.setRenderTarget( null );
	// 	renderer.clear(false,true,true); // 第一个color需要改为false,禁止清除color缓冲区
	// 	//this.fsQuad.render( renderer ); //还需要注释此行
	// }

	// 1. Extract Bright Areas

	this.highPassUniforms[ "tDiffuse" ].value = readBuffer.texture;
	this.highPassUniforms[ "luminosityThreshold" ].value = this.threshold;
	this.fsQuad.material = this.materialHighPassFilter;

	renderer.setRenderTarget( this.renderTargetBright );
	renderer.clear();
	this.fsQuad.render( renderer );

	// 2. Blur All the mips progressively

	var inputRenderTarget = this.renderTargetBright;

	for ( var i = 0; i < this.nMips; i ++ ) {

		this.fsQuad.material = this.separableBlurMaterials[ i ];

		this.separableBlurMaterials[ i ].uniforms[ "colorTexture" ].value = inputRenderTarget.texture;
		this.separableBlurMaterials[ i ].uniforms[ "direction" ].value = UnrealBloomPass.BlurDirectionX;
		renderer.setRenderTarget( this.renderTargetsHorizontal[ i ] );
		renderer.clear();
		this.fsQuad.render( renderer );

		this.separableBlurMaterials[ i ].uniforms[ "colorTexture" ].value = this.renderTargetsHorizontal[ i ].texture;
		this.separableBlurMaterials[ i ].uniforms[ "direction" ].value = UnrealBloomPass.BlurDirectionY;
		renderer.setRenderTarget( this.renderTargetsVertical[ i ] );//这里每次处理后renderTargetsHorizontal结果会输出到renderTargetsVertical里面二次处理,因此最终只需要renderTargetsVertical的texture
		renderer.clear();
		this.fsQuad.render( renderer );

		inputRenderTarget = this.renderTargetsVertical[ i ];

	}

	// Composite All the mips
    // compositeMaterial就是上面五次处理后的输出纹理后的最终材质,具体构造如下:
    // 	this.compositeMaterial = this.getCompositeMaterial( this.nMips );
	//this.compositeMaterial.uniforms[ "blurTexture1" ].value = this.renderTargetsVertical[ 0 ].texture;
	//this.compositeMaterial.uniforms[ "blurTexture2" ].value = this.renderTargetsVertical[ 1 ].texture;
	//this.compositeMaterial.uniforms[ "blurTexture3" ].value = this.renderTargetsVertical[ 2 ].texture;
	//this.compositeMaterial.uniforms[ "blurTexture4" ].value = this.renderTargetsVertical[ 3 ].texture;
	//this.compositeMaterial.uniforms[ "blurTexture5" ].value = this.renderTargetsVertical[ 4 ].texture;
	//this.compositeMaterial.uniforms[ "bloomStrength" ].value = strength;
	//this.compositeMaterial.uniforms[ "bloomRadius" ].value = 0.1;
	//this.compositeMaterial.needsUpdate = true;
	//var bloomFactors = [ 1.0, 0.8, 0.6, 0.4, 0.2 ];
	//this.compositeMaterial.uniforms[ "bloomFactors" ].value = bloomFactors;
	//this.bloomTintColors = [ new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ),
	//						 new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ) ];
	//this.compositeMaterial.uniforms[ "bloomTintColors" ].value = this.bloomTintColors;
	//this.fsQuad.material = this.compositeMaterial;
	//this.compositeMaterial.uniforms[ "bloomStrength" ].value = this.strength;
	//this.compositeMaterial.uniforms[ "bloomRadius" ].value = this.radius;
	//this.compositeMaterial.uniforms[ "bloomTintColors" ].value = this.bloomTintColors;

	renderer.setRenderTarget( this.renderTargetsHorizontal[ 0 ] );// 这里其实传入一个新的WebGLRenderTarget也行,意思将最终的处理结果输出到这里
	renderer.clear();
	this.fsQuad.render( renderer );

	// Blend it additively over the input texture

	this.fsQuad.material = this.materialCopy;
	this.copyUniforms[ "tDiffuse" ].value = this.renderTargetsHorizontal[ 0 ].texture;


	if ( this.renderToScreen ) {

		renderer.setRenderTarget( null );
		this.fsQuad.render( renderer );

	} else {

		renderer.setRenderTarget( readBuffer );
		this.fsQuad.render( renderer );

	}

	// Restore renderer settings

	renderer.setClearColor( this.oldClearColor, this.oldClearAlpha );
	renderer.autoClear = oldAutoClear;

}

5 . outlinepass

https://blog.csdn.net/tianyapai/article/details/103627396

6.原生的帧缓存使用

https://blog.csdn.net/xufeng0991/article/details/76736971

6.1 初始化一个帧缓冲

function initFramebufferObject(gl) {
var framebuffer = gl.createFramebuffer();

// 新建纹理对象作为帧缓冲区的颜色缓冲区对象
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, OFFSCREEN_WIDTH, OFFSCREEN_HEIGHT, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
framebuffer.texture = texture;

// 新建渲染缓冲区对象作为帧缓冲区的深度缓冲区对象
var depthBuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, OFFSCREEN_WIDTH, OFFSCREEN_HEIGHT);

gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer);

// 检测帧缓冲区对象的配置状态是否成功
var e = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
if (gl.FRAMEBUFFER_COMPLETE !== e) {
    console.log('Frame buffer object is incomplete: ' + e.toString());
    return;
}

gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.bindTexture(gl.TEXTURE_2D, null);
gl.bindRenderbuffer(gl.RENDERBUFFER, null);

return framebuffer;

}

6.1 使用

这里就是先绑定再绘制就是绘制到了fbo的texture中

gl.bindFramebuffer(gl.FRAMEBUFFER, fbo

然后解绑后就是绘制到屏幕上

gl.bindFramebuffer(gl.FRAMEBUFFER, null);

function draw(gl, fbo, plane, cube, texture, vpPlane, vpCube, rad) {
    var u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');
    var rot = getRotationMatrix(rad, 0.0, 1.0, 0.0);

    // 在帧缓冲区的颜色关联对象即纹理对象中绘制立方体,纹理使用图片
    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);// 绑定帧缓冲区对象后绘制就会在绑定帧缓冲区中进行绘制
    gl.viewport(0, 0, OFFSCREEN_WIDTH, OFFSCREEN_HEIGHT);
    gl.clearColor(0.2, 0.2, 0.4, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    var mvpCube = multiMatrix44(vpCube, rot);
    gl.uniformMatrix4fv(u_MvpMatrix, false, mvpCube);
    drawTexturedObject(gl, cube, texture);// 使用图片纹理绘制立方体

    // 在canvas上绘制矩形,纹理使用上一步在纹理对象中绘制的图像
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);// 接触绑定之后,会在默认的颜色缓冲区中绘制
    gl.viewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);

    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    /*
    * 默认绘制图形的正方两个面,所以可以看到平面的正反两个面都贴的有纹理
    * 使用下面代码可以开启消隐功能,不再绘制背面
    * */
    // gl.enable(gl.CULL_FACE);

    var mvpPlane = multiMatrix44(vpPlane, rot);
    gl.uniformMatrix4fv(u_MvpMatrix, false, mvpPlane);
    drawTexturedObject(gl, plane, fbo.texture);// 使用在帧缓冲绘制的纹理绘制矩形
} 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值