ThreeJS OIT Weight

 function createRenderTargets() {
 	//需要使用浮点数纹理
        let data_type = THREE.FloatType
        if( renderer.extensions.get( 'OES_texture_float_linear' ) === null ) {
            data_type = THREE.HalfFloatType
        }
        //真实屏幕分辨率率
        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累加
        alphaTarget = new THREE.WebGLRenderTarget(
            w, h,
            {
                minFilter: THREE.NearestFilter,
                magFilter: THREE.NearestFilter,
                //fromat: THREE.RGBAFormat,
                fromat: THREE.RedFormat,
                type:data_type
            })

		//渲染不透明物体
        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;
    }
复制代码
  • 创建OIT 用的材质,主要功能就是设置渲染状态,以及替换shader代码。
//OIT 材质  克隆原透明材质
materialColor = material.clone();
//设置混合参数
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
//设置回调函数编译前 替换shader代码
materialColor.onBeforeCompile = colorOnBeforeCompile;

//OIT alpha材质
materialAlpha = materialColor.clone();
materialAlpha.onBeforeCompile = alphaOnBeforeCompile;

..................
//替换shader
function colorOnBeforeCompile(shader) {

        shader.uniforms.uOpaqueDepth = globalPeelUniforms.uOpaqueDepth
        shader.uniforms.uScreenSize = globalPeelUniforms.uScreenSize

        //改颜色
        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

        //改颜色
        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(1,0,0);
            }
            `
        )

        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) * 1e8 * pow(1.0 - z * 0.9, 3.0), 1e-2, 3e3);
                    }

					${shader.fragmentShader}
				`
    }
复制代码
  • 加权求平均,最终与不透明的像素进行混合
<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>
//---------------------------------------

//两帧混合
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
复制代码
  • 渲染函数
TransparencyObjects.forEach(o=>o.visible = false)
OpaqueObjects.forEach(o=>o.visible = true)

//绘制不透明物体
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);

//加权求平均,最终与不透明的像素进行混合
pmaterial.uniforms.uAccumulate.value = colorTarget.texture;
pmaterial.uniforms.uAccumulateAlpha.value = alphaTarget.texture;
pmaterial.uniforms.uOpaque.value = opaqueTarget.texture;
renderer.render(composScene, ocamera);
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享