WebGL着色器属性未正确传递

时间:2018-05-17 07:49:02

标签: three.js webgl

我正在尝试使用WebGL实例化为线框(https://threejs.org/examples/?q=wire#webgl_materials_wireframe)采用threejs示例。

这个简单的再现编码器(https://codepen.io/ubermario/pen/gzByjP?editors=1000)显示当使用THREE.BufferAttribute将“center”属性传递给顶点/片段着色器时,会渲染线框立方体。

但是,当'center'属性通过THREE.InstancedBufferAttribute传递给相同的着色器时,它不会被重新作为线框。

不会产生任何错误。想法?

<html lang="en">
    <head>
        <title>Adopted from three.js webgl - materials - wireframe</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <style>
            body {
                margin: 0px;
                background-color: #000000;
                overflow: hidden;
            }
        </style>
    </head>
    <body>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r83/three.js"></script>  

        <script type="x-shader/x-vertex" id="vertexShader"> 
            attribute vec3 center;
            varying vec3 vCenter;

            void main() {
                vCenter = center;
                gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); 
            }
        </script>

        <script type="x-shader/x-fragment" id="fragmentShader">
            varying vec3 vCenter;

            float edgeFactorTri() {
                vec3 d = fwidth( vCenter.xyz ); 
                vec3 a3 = smoothstep( vec3( 0.0 ), d * 1.5, vCenter.xyz );  
                return min( min( a3.x, a3.y ), a3.z );
            }

            void main() {           
                gl_FragColor.rgb = mix( vec3( 1.0 ), vec3( 0.0 ), edgeFactorTri() );                
                gl_FragColor.a = 1.0;   
            }
        </script>

        <script>

            var camera, scene, renderer;

            init();

            renderer.render( scene, camera );

            function init() {

                var bufferGeometry, material, mesh;
                camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 2000 );
                camera.position.z = 700;
                scene = new THREE.Scene();

                var geometry1 =  new THREE.BoxBufferGeometry( 100, 100,100 );
                geometry1.addAttribute( 'center', new THREE.BufferAttribute( fnGetFloat32ArrayCenters( geometry1 ), 3 ) );

                var material_1 = new THREE.ShaderMaterial( {
                        uniforms: {},                             
                        vertexShader: document.getElementById( 'vertexShader' ).textContent,
                        fragmentShader: document.getElementById( 'fragmentShader' ).textContent

                    } );
                material_1.extensions.derivatives = true;   

                mesh1 = new THREE.Mesh( geometry1, material_1 );
                mesh1.position.x = -100;
                scene.add( mesh1 );


                var  bufferGeometry = new THREE.BoxBufferGeometry( 100, 100,100 );
                var geometry2 = new THREE.InstancedBufferGeometry();
                    geometry2.index = bufferGeometry.index;
                    geometry2.attributes.position = bufferGeometry.attributes.position;   
                    geometry2.attributes.uv = bufferGeometry.attributes.uv;         

                //Now with instancing
                geometry2.addAttribute( 'center', new THREE.InstancedBufferAttribute(  fnGetFloat32ArrayCenters( geometry2 ), 3 ) );    


                var material_2 = new THREE.ShaderMaterial( {
                        uniforms: {},                             
                        vertexShader: document.getElementById( 'vertexShader' ).textContent,
                        fragmentShader: document.getElementById( 'fragmentShader' ).textContent

                    } );
                material_2.extensions.derivatives = true;   

                mesh2 = new THREE.Mesh( geometry2, material_2 );
                mesh2.position.x = 100;
                scene.add( mesh2 );


                // renderer

                renderer = new THREE.WebGLRenderer( { antialias: true } );
                renderer.setPixelRatio( window.devicePixelRatio );
                renderer.setSize( window.innerWidth, window.innerHeight );
                document.body.appendChild( renderer.domElement );

                // events

                window.addEventListener( 'resize', onWindowResize, false );

                function fnGetFloat32ArrayCenters( geometry ) {


                    var vectors = [
                        new THREE.Vector3( 1, 0, 0 ),
                        new THREE.Vector3( 0, 1, 0 ),
                        new THREE.Vector3( 0, 0, 1 )
                    ];

                    var position = geometry.attributes.position;
                    var centers = new Float32Array( position.count * 3 );


                    for ( var i = 0, l = position.count; i < l; i ++ ) {

                        vectors[ i % 3 ].toArray( centers, i * 3 );

                    }

                    return centers;


                } //fnGetFloat32ArrayCenters                


            } //init




            function onWindowResize() {

                camera.aspect = window.innerWidth / window.innerHeight;
                camera.updateProjectionMatrix();

                renderer.setSize( window.innerWidth, window.innerHeight );

            }



        </script>

    </body>
</html>

1 个答案:

答案 0 :(得分:1)

解决方案:问题似乎是three.js r83中的一个错误,其中在BoxBufferGeometry和InstancedBufferGeometry上创建了网格物体;请参阅评论中说明此内容的更新codepen

当其值为false时,不应用material_1的线框属性。它似乎被“卡住”在'真实'上;强制它为'false'对第一个立方体没有影响。

这导致人们误以为基于material_2的立方体一直都是错误的;因为它尊重默认的线框属性值'false'。设置为“true”时,它将显示为线框立方体。

<html lang="en">
    <head>
        <title>Adopted from three.js webgl - materials - wireframe</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <style>
            body {
                margin: 0px;
                background-color: #000000;
                overflow: hidden;
            }
        </style>
    </head>
    <body>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r83/three.js"></script>  

        <script type="x-shader/x-vertex" id="vertexShader"> 
            attribute vec3 center;
            varying vec3 vCenter;

            void main() {
                vCenter = center;
                gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); 
            }
        </script>

        <script type="x-shader/x-fragment" id="fragmentShader">
            varying vec3 vCenter;

            float edgeFactorTri() {
                vec3 d = fwidth( vCenter.xyz ); 
                vec3 a3 = smoothstep( vec3( 0.0 ), d * 1.5, vCenter.xyz );  
                return min( min( a3.x, a3.y ), a3.z );
            }

            void main() {           
                gl_FragColor.rgb = mix( vec3( 1.0 ), vec3( 0.0 ), edgeFactorTri() );                
                gl_FragColor.a = 1.0;   
            }
        </script>

        <script>

            var camera, scene, renderer;

            init();

            renderer.render( scene, camera );

            function init() {

                var bufferGeometry, material, mesh;
                camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 2000 );
                camera.position.z = 700;
                scene = new THREE.Scene();

                var geometry1 =  new THREE.BoxBufferGeometry( 100, 100,100 );
                geometry1.addAttribute( 'center', new THREE.BufferAttribute( fnGetFloat32ArrayCenters( geometry1 ), 3 ) );

                var material_1 = new THREE.ShaderMaterial( {
                        uniforms: {},                             
                        vertexShader: document.getElementById( 'vertexShader' ).textContent,
                        fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
            wireframe: false //bug:For r83/three.js, property is not applied when the THREE.Mesh constructor is invoked. https://threejs.org/docs/index.html#api/materials/ShaderMaterial.wireframe

                    } );
                material_1.extensions.derivatives = true;   

                mesh1 = new THREE.Mesh( geometry1, material_1 );  //bug: material_1's wireframe:false property is not applied for r83/three.js
                mesh1.position.x = -100;
                scene.add( mesh1 );


                var  bufferGeometry = new THREE.BoxBufferGeometry( 100, 100,100 );
                var geometry2 = new THREE.InstancedBufferGeometry();
                    geometry2.index = bufferGeometry.index;
                    geometry2.attributes.position = bufferGeometry.attributes.position;   
                    geometry2.attributes.uv = bufferGeometry.attributes.uv;         

                //Now with instancing
                geometry2.addAttribute( 'center', new THREE.InstancedBufferAttribute(  fnGetFloat32ArrayCenters( geometry2 ), 3 ) );    


                var material_2 = new THREE.ShaderMaterial( {
                        uniforms: {},                             
                        vertexShader: document.getElementById( 'vertexShader' ).textContent,
                        fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
            wireframe:true  //See: documentation: https://threejs.org/docs/index.html#api/materials/ShaderMaterial.wireframe

                    } );
                material_2.extensions.derivatives = true;   

                mesh2 = new THREE.Mesh( geometry2, material_2 );
                mesh2.position.x = 100;
                scene.add( mesh2 );


                // renderer

                renderer = new THREE.WebGLRenderer( { antialias: true } );
                renderer.setPixelRatio( window.devicePixelRatio );
                renderer.setSize( window.innerWidth, window.innerHeight );
                document.body.appendChild( renderer.domElement );

                // events

                window.addEventListener( 'resize', onWindowResize, false );

                function fnGetFloat32ArrayCenters( geometry ) {


                    var vectors = [
                        new THREE.Vector3( 1, 0, 0 ),
                        new THREE.Vector3( 0, 1, 0 ),
                        new THREE.Vector3( 0, 0, 1 )
                    ];

                    var position = geometry.attributes.position;
                    var centers = new Float32Array( position.count * 3 );


                    for ( var i = 0, l = position.count; i < l; i ++ ) {

                        vectors[ i % 3 ].toArray( centers, i * 3 );

                    }

                    return centers;


                } //fnGetFloat32ArrayCenters                


            } //init




            function onWindowResize() {

                camera.aspect = window.innerWidth / window.innerHeight;
                camera.updateProjectionMatrix();

                renderer.setSize( window.innerWidth, window.innerHeight );

            }



        </script>

    </body>
</html>