- Blog.csdn.net/LensFlare/a…
- Create the RenderTarget, which must be a floating point texture, using WebGL2
function createRenderTargets() {
// Need to use floating point texture
let data_type = THREE.FloatType
if( renderer.extensions.get( 'OES_texture_float_linear') = = =null ) {
data_type = THREE.HalfFloatType
}
// True screen resolution rate
var dpr = renderer.getPixelRatio();
let w = window.innerWidth * dpr
let h = window.innerHeight * dpr
// Render target
colorTarget = new THREE.WebGLRenderTarget(
w, h,
{
minFilter: THREE.NearestFilter,
magFilter: THREE.NearestFilter,
//wrapS: THREE.ClampToEdgeWrapping,
//wrapT: THREE.ClampToEdgeWrapping
fromat: THREE.RGBAFormat,
type:data_type
})
/ / alpha accumulation
alphaTarget = new THREE.WebGLRenderTarget(
w, h,
{
minFilter: THREE.NearestFilter,
magFilter: THREE.NearestFilter,
//fromat: THREE.RGBAFormat,
fromat: THREE.RedFormat,
type:data_type
})
// Render opaque objects
opaqueTarget = new THREE.WebGLRenderTarget(
w, h,
{
minFilter: THREE.NearestFilter,
magFilter: THREE.NearestFilter,
fromat: THREE.RGBAFormat,
type: data_type
})
opaqueTarget.stencilBuffer = false;
opaqueTarget.depthBuffer = true;
opaqueTarget.depthTexture = new THREE.DepthTexture();
opaqueTarget.depthTexture.type = THREE.FloatType;
}
Copy the code
- The material used to create the OIT is used to set the render state and replace the shader code.
//OIT material is cloned from the original transparent material
materialColor = material.clone();
// Set the blending parameters
materialColor.blending = THREE.CustomBlending
materialColor.blendSrc = THREE.OneFactor
materialColor.blendDst = THREE.OneFactor
materialColor.blendSrcAlpha = THREE.ZeroFactor
materialColor.blendDstAlpha = THREE.OneMinusSrcAlphaFactor
//materialColor.blendEquation = THREE.AddEquation
materialColor.depthWrite = false;
materialColor.depthTest = false
materialColor.depthFunc = THREE.AlwaysDepth
// Set the callback function to replace the shader code before compilation
materialColor.onBeforeCompile = colorOnBeforeCompile;
/ / OIT alpha texturesmaterialAlpha = materialColor.clone(); materialAlpha.onBeforeCompile = alphaOnBeforeCompile; ./ / replace shader
function colorOnBeforeCompile(shader) {
shader.uniforms.uOpaqueDepth = globalPeelUniforms.uOpaqueDepth
shader.uniforms.uScreenSize = globalPeelUniforms.uScreenSize
/ / change color
shader.fragmentShader = shader.fragmentShader.replace(
/}$/gm.` float w = weight(gl_FragCoord.z, gl_FragColor.a); gl_FragColor.rgb = gl_FragColor.rgb * gl_FragColor.a; gl_FragColor = vec4(gl_FragColor.rgb * w, gl_FragColor.a); vec2 screenPos = gl_FragCoord.xy * uScreenSize; vec4 dep = texture2D( uOpaqueDepth, screenPos ); //float dddd = unpackRGBAToDepth(dep); float dddd = dep.r; if (gl_FragCoord.z > dddd) discard; } `
)
weightShader(shader);
}
function alphaOnBeforeCompile(shader) {
shader.uniforms.uOpaqueDepth = globalPeelUniforms.uOpaqueDepth
shader.uniforms.uScreenSize = globalPeelUniforms.uScreenSize
/ / change color
shader.fragmentShader = shader.fragmentShader.replace(
/}$/gm.` float w = weight(gl_FragCoord.z, gl_FragColor.a); gl_FragColor = vec4(gl_FragColor.a*w, gl_FragColor.a*w, gl_FragColor.a*w, gl_FragColor.a*w); vec2 screenPos = gl_FragCoord.xy * uScreenSize; vec4 dep = texture2D( uOpaqueDepth, screenPos ); float dddd = dep.r; //float dddd = unpackRGBAToDepth(dep); if (gl_FragCoord.z > dddd) discard; / / gl_FragColor. RGB = vec3 (0, 1); } `
)
weightShader(shader);
}
function weightShader(shader) {
shader.fragmentShader = shader.fragmentShader.replace('#include <packing>'.' ')
shader.fragmentShader = ` #include <packing> uniform sampler2D uOpaqueDepth; uniform vec2 uScreenSize; //calc weight float weight(float z, float a) {return clamp(pow(min(1.0, a * 10.0) + 0.01, (3.0) * 1 e8 * pow - z * 0.9, 1.0, 3.0), 1 e - 2, 3 e3); }${shader.fragmentShader}
`
}
Copy the code
- Weighted and averaged, and finally mixed with opaque pixels
<script type="x-shader/x-vertex" id="vertexShader">
varying vec2 vUv;
void main()
{
vUv = uv;
gl_Position = vec4(position.xy, 0.0.1.0);
}
</script>
<script type="x-shader/x-fragment" id="fragmentShader">
//precision highp float;
varying vec2 vUv;
uniform sampler2D uAccumulate;
uniform sampler2D uAccumulateAlpha;
uniform sampler2D uOpaque;
void main() {
vec4 accum = texture2D( uAccumulate, vUv );
float r = accum.a;
accum.a = texture2D(uAccumulateAlpha, vUv).r;
vec4 color = vec4(accum.rgb / clamp(accum.a, 0.0001.50000.0), r);
color.rgb = pow(color.rgb, vec3(1.0/2.2));
color = vec4((1.0-r) * accum.rgb / clamp(accum.a, 0.001.50000.0), r);
vec4 opaqueColor = texture2D(uOpaque, vUv).rgba;
vec3 outputColor = mix(color.rgb, opaqueColor.rgb, color.a);
gl_FragColor = vec4(outputColor.rgb, 1);
}
</script>
//---------------------------------------
// Mix two frames
pmaterial = new THREE.ShaderMaterial( {
uniforms: {
"uAccumulate": { value: null },
"uAccumulateAlpha": { value: null },
"uOpaque": { value: null}},vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent
} );
pmaterial.blending = THREE.CustomBlending
//material.blending = THREE.NoBlending
pmaterial.blendSrc = THREE.OneFactor
pmaterial.blendDst = THREE.OneMinusSrcAlphaFactor
//material.blendSrcAlpha = THREE.ZeroFactor
//material.blendDstAlpha = THREE.OneMinusSrcAlphaFactor
Copy the code
- Rendering function
TransparencyObjects.forEach(o= >o.visible = false)
OpaqueObjects.forEach(o= >o.visible = true)
// Draw an opaque object
renderer.setClearColor(0.1);
OpaqueObjects.forEach((o) = >{
o.visible = true
})
renderer.render(scene, camera, opaqueTarget, true);
OpaqueObjects.forEach(o= >o.visible = false)
//-----------
renderer.setClearColor(0.1);
globalPeelUniforms.uOpaqueDepth.value = opaqueTarget.depthTexture;
TransparencyObjects.forEach((o) = >{
o.material = materialColor
o.visible = true
)
renderer.render(scene, camera, colorTarget, true);
TransparencyObjects.forEach((o) = >{
o.material = materialAlpha
})
renderer.render(scene, camera, alphaTarget, true);
// Take the weighted average and finally mix with the opaque pixels
pmaterial.uniforms.uAccumulate.value = colorTarget.texture;
pmaterial.uniforms.uAccumulateAlpha.value = alphaTarget.texture;
pmaterial.uniforms.uOpaque.value = opaqueTarget.texture;
renderer.render(composScene, ocamera);
Copy the code