WebGL 着色器属性未准确传递 [英] WebGL shader attribute is not being passed accurately

查看:31
本文介绍了WebGL 着色器属性未准确传递的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm attempting to adopt the threejs example for wireframes ( https://threejs.org/examples/?q=wire#webgl_materials_wireframe ) using WebGL instancing.

这个简单的复制代码笔(https://codepen.io/ubermario/pen/gzByjP?editors=1000 ) 显示当使用 THREE.BufferAttribute 将中心"属性传递给顶点/片段着色器时,会渲染线框立方体.

This simple reproduction codepen ( https://codepen.io/ubermario/pen/gzByjP?editors=1000 ) shows that a wireframed cube is rendered when a 'center' attribute is passed to the vertex/fragment shaders with THREE.BufferAttribute.

但是,当将center"属性传递给具有 THREE.InstancedBufferAttribute 的相同着色器时,它不会重绘为线框.

However, it is not renedered as wireframe when the 'center' attribute is passed to the same shaders with THREE.InstancedBufferAttribute.

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

No errors are generated. Ideas?

<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>

推荐答案

解决方案:该问题似乎是 Three.js r83 中的一个错误,在 BoxBufferGeometry 与 InstancedBufferGeometry 上创建了网格;请参阅更新的 codepen,在评论中对此进行了说明.

Solution: The problem appears to be a bug in three.js r83 with meshes created on BoxBufferGeometry vs InstancedBufferGeometry; see the updated codepen that illustrates this in the comments.

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

The wireframe attribute for material_1 is not applied when its value is false. It appears to be 'stuck' on 'true'; forcing it to 'false' will have no affect on the first cube.

这导致了基于material_2的立方体在一直正确的时候出错的误解;因为它尊重false"的默认线框属性值.设置为true"时,它将显示为线框立方体.

This lead to the misperception that the cube based on material_2 was in error when it was right all along; because it was respecting the default wireframe attribute value of 'false'. When set to 'true' it will display as a wireframed cube.

<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>

这篇关于WebGL 着色器属性未准确传递的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆