• 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