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);// 使用在帧缓冲绘制的纹理绘制矩形
}