проблема с рендерингом - PullRequest
0 голосов
/ 06 марта 2019

У меня проблема с тройкой и инстансингом. Кажется, что объекты неправильно обрезаны ближней плоскостью камеры.

Как вы заметите, я использую измененную версию THREE.JS благодаря Mugen87, которая включает в себя UNIFORM BLOCKS, очень интересную функцию, позволяющую использовать WEBGL2.

Я установил свой экземплярный объект Mesh с параметром frustumCulled = false, чтобы экземпляры вообще не обрезались, а это не так. Поведение можно очень легко наблюдать, просто увеличив масштаб | вне.

Вы поймете, что какой-то объект, который должен быть невидимым, внезапно появляется как видимый, и наоборот. https://jsfiddle.net/uvrox3kb/2

<!DOCTYPE html>
<html lang="en">
    <head><base href="./three.js/examples/" target="_blank">
        <title>three.js webgl - scene animation</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <style>
            html, body {
                height: 100%;
            }

            body {
                background: #ffffff;
                padding: 0;
                margin: 0;
                font-family: Monospace;
                font-size: 13px;
                overflow: hidden;
            }

            #info {
                top: 0px;
                width: 100%;
                color: #000000;
                margin: 6px 0px;
                text-align: center;
            }

            #info a {
                color: #000000;
            }

            #container {
                width: 100%;
                height: calc(100% - 80px);
            }
            .selectBox {
                border: 1px solid #55aaff;
                background-color: rgba(75, 160, 255, 0.3);
                position: fixed;
            }
        </style>
        </style>
    </head>

    <body>

        <div id="container"></div>
        <div id="info">
        <script type="text/javascript" src="https://yume.human-interactive.org/examples/ubo/three.js"></script> 
        <!--<script type="text/javascript" src="/libs/three_v101.js"></script>-->
        <script type="text/javascript" src="https://threejs.org/examples/js/utils/SceneUtils.js"></script>
        <script type="text/javascript" src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

        <script id="vertexShader1" type="x-shader/x-vertex">

            #define USE_LOGDEPTHBUF

            precision highp float;
            in float visible;
            in float selected;
            in float pickable;
            in float pn_UUID;
            in vec4 lodInfo;
            in vec3 mcol0;
            in vec3 mcol1;
            in vec3 mcol2;
            in vec3 mcol3;
            in vec3 nmcol0;
            in vec3 nmcol1;
            in vec3 nmcol2;
            in vec3 position;
            in vec3 normal;
            in vec4 color;
            uniform ViewData {
                mat4 projectionMatrix;
                mat4 viewMatrix;
            };
            //uniform mat4 modelMatrix;
            //uniform mat3 normalMatrix;

            out vec3 vPositionEye;
            out vec3 vNormalEye;
            out vec4 vColor;

            #include <common>
            #include <logdepthbuf_pars_vertex>

            void main() {
                mat3 normalMatrix = mat3(
                    vec3( nmcol0 ),
                    vec3( nmcol1 ),
                    vec3( nmcol2 )
                );

                mat4 matrix = mat4(
                        vec4( mcol0, 0 ),
                        vec4( mcol1, 0 ),
                        vec4( mcol2, 0 ),
                        vec4( mcol3, 1 )
                    );
                vec4 tposition = matrix * vec4( position, 1.0 );
                vec4 vertexPositionEye = viewMatrix * tposition;
                vPositionEye = vertexPositionEye.xyz;
                vNormalEye =  normalMatrix * normal;
                gl_Position = projectionMatrix * vertexPositionEye;


                #ifdef PICKING                                                                     
                    vColor = vec4( tposition.xyz, pn_UUID );                                        
                #else  
                    if ( selected > 0.0 ) {
                        vColor = vec4( 1.0, 0.0, 0.0, 0.5 );
                    } else {
                        vColor = color;
                    }
                #endif 


                #include <logdepthbuf_vertex>
            }
        </script>

        <script id="fragmentShader1" type="x-shader/x-fragment">
            precision highp float;
            uniform LightingData {
                vec3 position;
                vec3 ambientColor;
                vec3 diffuseColor;
                vec3 specularColor;
                float shininess;
            } Light;
            in vec4 vColor;
            in vec3 vPositionEye;
            in vec3 vNormalEye;
            out vec4 fragColor;

            void main() {

                // a very basic lighting equation (Phong reflection model) for testing
                #ifdef PICKING
                    fragColor = vColor;
                # else


                    vec3 l = normalize( Light.position - vPositionEye );
                    vec3 n = normalize( vNormalEye );
                    vec3 e = - normalize( vPositionEye );
                    vec3 r = normalize( reflect( - l, n ) );
                    float diffuseLightWeighting = max( dot( n, l ), 0.0 );
                    float specularLightWeighting = max( dot( r, e ), 0.0 );
                    specularLightWeighting = pow( specularLightWeighting, Light.shininess );
                    vec3 lightWeighting = Light.ambientColor +
                        Light.diffuseColor * diffuseLightWeighting +
                        Light.specularColor * specularLightWeighting;
                    fragColor = vec4( vColor.rgba * vec4(lightWeighting.rgb, 1.0 ));
                #endif 
                //fragColor = vColor;
            }
        </script>

        <script>
            // --------------------------------------------------------------------------------------------------------------------
            // - Global vars:
            // --------------------------------------------------------------------------------------------------------------------
            var camera, scene, renderer, controls;
            var clock;
            var dummyVector = new THREE.Vector3();
            var objectCount = 0;
            var cameraUniformBlock, lightingUniformBlock;
            var objects = [];
            var selectionBox, helper;
            var isSelecting = false;
            var canvas_h, canvas_w, canvas_x_offset, canvas_t_offset;
            var pickingScene, pickingRenderTarget;
            var gl;
            var mouse;
            var material, pmaterial;
            var mesh, pmesh;
            // --------------------------------------------------------------------------------------------------------------------
            // - Functions:
            // --------------------------------------------------------------------------------------------------------------------

            var randomizeMatrix = function() {
                var position = new THREE.Vector3();
                var rotation = new THREE.Euler();
                var quaternion = new THREE.Quaternion();
                var scale = new THREE.Vector3();
                return function( matrix ) {
                    position.x = Math.random() * 100 ;
                    position.y = Math.random() * 100 ;
                    position.z = Math.random() * 100 ;
                    rotation.x = Math.random() * 2 * Math.PI;
                    rotation.y = Math.random() * 2 * Math.PI;
                    rotation.z = Math.random() * 2 * Math.PI;
                    quaternion.setFromEuler( rotation, false );
                    scale.x = scale.y = scale.z = Math.random() * 100
                    matrix.compose( position, quaternion, scale );
                };
            }();

            function makeInstanced( geo, instanceCount ) {
                // geometry
                //geometryList.push( geo );
                geo.computeBoundingSphere();
                geo.computeBoundingBox();
                geometrySize = geo.boundingBox.getSize(dummyVector);
                console.log("geometrySize:", geometrySize);
                var sizeArray = [geometrySize.x, geometrySize.y, geometrySize.z].sort((a, b) => b - a);
                var occlussionDistance = (sizeArray[0]+ sizeArray[1]) * 0.5 * 500;
                //console.log("occlussionDistance:", occlussionDistance);
                geometryCenter = geo.boundingBox.getCenter(dummyVector);
                //console.log("geometryCenter:", geometryCenter);

                var igeo = new THREE.InstancedBufferGeometry();
                igeo.index = geo.index;
                igeo.attributes.position = geo.attributes.position;
                igeo.attributes.normal = geo.attributes.normal;
                igeo.attributes.uv = geo.attributes.uv;
                //geometryList.push( igeo );

                igeo.userData = {
                    uuid2IdArray: []
                }


                // Instanced Attributes Definition:

                // Visible:
                var visible = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 1 ), 1, true, 1 );

                // Selected:
                var selected = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 1 ), 1, true, 1 );

                var pickable = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 1 ), 1, true, 1 );

                // Absolute Transformation Matrix:
                var mcol0 = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 3 ), 3, true, 1 );
                var mcol1 = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 3 ), 3, true, 1 );
                var mcol2 = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 3 ), 3, true, 1 );
                var mcol3 = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 3 ), 3, true, 1 );

                var nmcol0 = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 3 ), 3, true, 1 );
                var nmcol1 = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 3 ), 3, true, 1 );
                var nmcol2 = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 3 ), 3, true, 1 );

                // Center and Occlussion Distance of object from camera position:
                var lodInfo = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 4 ), 4,true, 1 );

                // Scene Colors:
                var colors = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 4 ), 4, true, 1 );

                // UUID information
                var pn_UUID = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 1 ), 1 ,true, 1 );

                // Instanced Attributes Assignation:
                var matrix = new THREE.Matrix4();
                var me = matrix.elements;



                console.log(instanceCount);
                for ( var i=0;  i < instanceCount; i ++ ) {
                    objectCount ++;
                    visible.array[i] = 1;
                    pickable.array[i] = 1;
                    selected.array[i] = 0;

                    randomizeMatrix( matrix );
                    var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );
                    var nme = normalMatrix.elements;

                    var instanceCenter =  geometryCenter.applyMatrix4(matrix);
                    //console.log("instanceCenter:", instanceCenter);
                    mcol0.setXYZ( i, me[ 0 ], me[ 1 ], me[ 2 ] );
                    mcol1.setXYZ( i, me[ 4 ], me[ 5 ], me[ 6 ] );
                    mcol2.setXYZ( i, me[ 8 ], me[ 9 ], me[ 10 ] );
                    mcol3.setXYZ( i, me[ 12 ], me[ 13 ], me[ 14 ] );

                    nmcol0.setXYZ( i, nme[ 0 ], nme[ 1 ], nme[ 2 ] );
                    nmcol1.setXYZ( i, nme[ 3 ], nme[ 4 ], nme[ 5 ] );
                    nmcol2.setXYZ( i, nme[ 6 ], nme[ 7 ], nme[ 8 ] );


                    lodInfo.array[i*4] = instanceCenter.x;
                    lodInfo.array[(i*4) + 1] = instanceCenter.y;
                    lodInfo.array[(i*4) + 2] = instanceCenter.z;
                    lodInfo.array[(i*4) + 3] = occlussionDistance;

                    colors.array[i*4] = Math.random();
                    colors.array[(i*4) + 1] = Math.random();
                    colors.array[(i*4) + 2] = Math.random();
                    colors.array[(i*4) + 3] = 1.0;

                    //colors.array[i*4] = 0.0;
                    //colors.array[(i*4) + 1] = 0.0;
                    //colors.array[(i*4) + 2] = 1.0;
                    //colors.array[(i*4) + 3] = 1.0;
                    igeo.userData.uuid2IdArray[objectCount] = i;
                    pn_UUID.array[i] = objectCount;
                }

                // Instanced Attributes addition:
                igeo.addAttribute( 'visible', visible );
                igeo.addAttribute( 'selected', selected );
                igeo.addAttribute( 'pickable', pickable );
                igeo.addAttribute( 'mcol0', mcol0 );
                igeo.addAttribute( 'mcol1', mcol1 );
                igeo.addAttribute( 'mcol2', mcol2 );
                igeo.addAttribute( 'mcol3', mcol3 );
                igeo.addAttribute( 'nmcol0', nmcol0 );
                igeo.addAttribute( 'nmcol1', nmcol1 );
                igeo.addAttribute( 'nmcol2', nmcol2 );
                igeo.addAttribute( 'lodInfo', lodInfo );
                igeo.addAttribute( 'color', colors );
                igeo.addAttribute( 'pn_UUID', pn_UUID );
                // mesh
                mesh = new THREE.Mesh( igeo, material );
                mesh.frustumCulled = false;
                console.log(mesh);
                scene.add( mesh );


            }

            function init() {
                var container = document.getElementById( 'container' );
                mouse = new THREE.Vector2();

                var rect = container.getBoundingClientRect();
                canvas_w = rect.width;
                canvas_h = rect.height;
                canvas_x_offset = rect.left;
                canvas_y_offset = rect.top;

                camera = new THREE.PerspectiveCamera( 90, canvas_w / canvas_h, 1, 1e27 );

                scene = new THREE.Scene();
                clock = new THREE.Clock();

                // geometry
                //var geometry1 = new THREE.TorusBufferGeometry();
        var geometry1 = new THREE.BoxBufferGeometry( 1, 1, 1 );
                //var geometry2 =  new THREE.TorusKnotBufferGeometry();

                cameraUniformBlock = new THREE.UniformBlock();
                    cameraUniformBlock.setName( 'ViewData' );
                    cameraUniformBlock.add( { value: camera.projectionMatrix } ); // projection matrix
                    cameraUniformBlock.add( { value: camera.matrixWorldInverse } ); // view matrix

                lightingUniformBlock = new THREE.UniformBlock();
                    lightingUniformBlock.setName( 'LightingData' );
                    lightingUniformBlock.add( { value: new THREE.Vector3( 0, 0, 0 ) } ); // light position
                    lightingUniformBlock.add( { value: new THREE.Color( 0x333333 ) } ); // ambient color
                    lightingUniformBlock.add( { value: new THREE.Color( 0xaaaaaa ) } ); // diffuse color
                    lightingUniformBlock.add( { value: new THREE.Color( 0xcccccc ) } ); // specular color
                    lightingUniformBlock.add( { value: 64 } ); // shininess

                // materials

                material = new THREE.RawShaderMaterial( {
                    uniformBlocks: [ cameraUniformBlock, lightingUniformBlock ],
                    vertexShader: "#version 300 es\n" +  document.getElementById( 'vertexShader1' ).textContent,
                    fragmentShader: "#version 300 es\n" +  document.getElementById( 'fragmentShader1' ).textContent,
                    transparent: true,
                    side: THREE.DoubleSide,
                    clipping: true,
                    clipShadows: false
                } );


                console.log(material);
                makeInstanced( geometry1, 100 );

                var canvas = document.createElement( 'canvas' );
                gl = canvas.getContext( 'webgl2' );
                renderer = new THREE.WebGLRenderer( { antialias: true, logarithmicDepthBuffer: true, canvas: canvas, context: gl } );
                renderer.setPixelRatio( window.devicePixelRatio );
                renderer.setSize( window.innerWidth, window.innerHeight );


                material.uniformBlocks.dynamic= true;
                material.uniformBlocks[1].dynamic= true;
                material.uniformBlocks[1].uniforms[0].dynamic = true;
                controls = new THREE.OrbitControls( camera, renderer.domElement );
                controls.addEventListener( 'change', render );

                camera.position.set( 0, 0, 250 );
                camera.lookAt( scene.position );

                container.appendChild( renderer.domElement );

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


            function onWindowResize() {
                camera.aspect = window.innerWidth / window.innerHeight;
                camera.updateProjectionMatrix();
                renderer.setSize( window.innerWidth, window.innerHeight );
            }



            function render(){
                renderer.render( scene, camera );
                material.uniformBlocks[1].uniforms[0].value = camera.position;
            }

            // --------------------------------------------------------------------------------------------------------------------
            // - Start of Body:
            // --------------------------------------------------------------------------------------------------------------------
            init();
            render();
        </script>

    </body>
</html>

Чтобы воспроизвести проблему, просто увеличьте | и вы увидите, что видимость не работает должным образом:

Вот пример только увеличения:

ScreenShot 1 original ScreenShot 2 zoom in

С наилучшими пожеланиями

Любая подсказка?

...