在three.js中使用MeshStandardMaterial的黑色非反射面

时间:2017-07-17 11:28:51

标签: javascript three.js

我一般是三人和三维图形的初学者。这主要是我的学习练习。

我试图展示具有金属外观的十二面体,但是大约一半的脸是黑色的并且没有反射。其他面孔看起来是正确的。

我知道有一个内置函数可以生成十二面体,也可以计算法线,但我想手动检查我的理解。

起初我认为顶点法线可能存在一些问题,但是使用VertexNormalsHelper,看起来法线都指向正确的方向。

任何人都可以告诉我哪里出错了?非常感谢!

代码:

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>shiny dodecahedron</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 {
                background:#000;
                color:#fff;
                padding:0;
                margin:0;
                font-weight: bold;
                overflow:hidden;
            }
            a { color: #ffffff; }
            #info {
                position: absolute;
                top: 0px; width: 100%;
                color: #ffffff;
                padding: 5px;
                font-family:Monospace;
                font-size:13px;
                text-align:center;
            }
            #vt { display:none }
            #vt, #vt a { color:orange; }
        </style>
    </head>

    <body>

        <div id="info">
            <span id="description">Dodecahedron standard material demo.</span> 
        </div>

        <script src="js/three.js"></script>
        <script src="js/controls/OrbitControls.js"></script>

        <script src="js/Detector.js"></script>
        <script src="js/libs/stats.min.js"></script>
        <script src='js/libs/dat.gui.min.js'></script>

        <script>
            if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
            var stats;
            var camera, scene, renderer;
            var settings = {
                metalness: 1.0,
                roughness: 0.4,
                ambientIntensity: 0.2
            };
            var mesh, material;
            var directionalLight, ambientLight;
            var mouseX = 0;
            var mouseY = 0;
            var windowHalfX = window.innerWidth / 2;
            var windowHalfY = window.innerHeight / 2;
            var height = 500; // of camera frustum
            var r = 0.0;

            var GOLDEN_RATIO = (1 + Math.sqrt(5)) / 2;

            var scaleFactor = 1/(1+GOLDEN_RATIO);

            var explicitDodecahedronVertices = new Float32Array([
                (2*Math.cos(2*0*Math.PI/5)), (2*Math.sin(2*0*Math.PI/5)), GOLDEN_RATIO+1, // 0
                (2*Math.cos(2*1*Math.PI/5)), (2*Math.sin(2*1*Math.PI/5)), GOLDEN_RATIO+1, // 1
                (2*Math.cos(2*2*Math.PI/5)), (2*Math.sin(2*2*Math.PI/5)), GOLDEN_RATIO+1, // 2
                (2*Math.cos(2*3*Math.PI/5)), (2*Math.sin(2*3*Math.PI/5)), GOLDEN_RATIO+1, // 3
                (2*Math.cos(2*4*Math.PI/5)), (2*Math.sin(2*4*Math.PI/5)), GOLDEN_RATIO+1, // 4

                (2*GOLDEN_RATIO*Math.cos(2*0*Math.PI/5)), (2*GOLDEN_RATIO*Math.sin(2*0*Math.PI/5)), GOLDEN_RATIO-1, // 5
                (2*GOLDEN_RATIO*Math.cos(2*1*Math.PI/5)), (2*GOLDEN_RATIO*Math.sin(2*1*Math.PI/5)), GOLDEN_RATIO-1, // 6
                (2*GOLDEN_RATIO*Math.cos(2*2*Math.PI/5)), (2*GOLDEN_RATIO*Math.sin(2*2*Math.PI/5)), GOLDEN_RATIO-1, // 7
                (2*GOLDEN_RATIO*Math.cos(2*3*Math.PI/5)), (2*GOLDEN_RATIO*Math.sin(2*3*Math.PI/5)), GOLDEN_RATIO-1, // 8
                (2*GOLDEN_RATIO*Math.cos(2*4*Math.PI/5)), (2*GOLDEN_RATIO*Math.sin(2*4*Math.PI/5)), GOLDEN_RATIO-1, // 9

                (-2*GOLDEN_RATIO*Math.cos(2*0*Math.PI/5)), (-2*GOLDEN_RATIO*Math.sin(2*0*Math.PI/5)), -(GOLDEN_RATIO-1), // 10
                (-2*GOLDEN_RATIO*Math.cos(2*1*Math.PI/5)), (-2*GOLDEN_RATIO*Math.sin(2*1*Math.PI/5)), -(GOLDEN_RATIO-1), // 11
                (-2*GOLDEN_RATIO*Math.cos(2*2*Math.PI/5)), (-2*GOLDEN_RATIO*Math.sin(2*2*Math.PI/5)), -(GOLDEN_RATIO-1), // 12
                (-2*GOLDEN_RATIO*Math.cos(2*3*Math.PI/5)), (-2*GOLDEN_RATIO*Math.sin(2*3*Math.PI/5)), -(GOLDEN_RATIO-1), // 13
                (-2*GOLDEN_RATIO*Math.cos(2*4*Math.PI/5)), (-2*GOLDEN_RATIO*Math.sin(2*4*Math.PI/5)), -(GOLDEN_RATIO-1), // 14

                (-2*Math.cos(2*0*Math.PI/5)), (-2*Math.sin(2*0*Math.PI/5)), -(GOLDEN_RATIO+1), // 15
                (-2*Math.cos(2*1*Math.PI/5)), (-2*Math.sin(2*1*Math.PI/5)), -(GOLDEN_RATIO+1), // 16
                (-2*Math.cos(2*2*Math.PI/5)), (-2*Math.sin(2*2*Math.PI/5)), -(GOLDEN_RATIO+1), // 17
                (-2*Math.cos(2*3*Math.PI/5)), (-2*Math.sin(2*3*Math.PI/5)), -(GOLDEN_RATIO+1), // 18
                (-2*Math.cos(2*4*Math.PI/5)), (-2*Math.sin(2*4*Math.PI/5)), -(GOLDEN_RATIO+1), // 19
            ]);

            var dodecahedronFaceIndexes = new Uint8Array([
                // one of pair of opposite pentagons parallel to xy plane
                // 0, 1, 2, 3, 4
                1, 3, 0, 
                1, 2, 3,
                0, 3, 4,

                // 0, 4, 5, 9, 12
                4, 12, 0,
                12, 5, 0,
                12, 4, 9,

                // 3, 4, 8, 9, 11
                3, 11, 4,
                3, 8, 11,
                4, 11, 9,

                // 2, 3, 7, 8, 10
                2, 10, 3,
                2, 7, 10,
                3, 10, 8,

                // 1, 2, 6, 7, 14
                1, 14, 2,
                1, 6, 14,
                2, 14, 7,

                // 0, 1, 5, 6, 13
                0, 13, 1,
                0, 5, 13,
                1, 13, 6,


                // 15, 16, 17, 18, 19
                15, 18, 16,
                15, 19, 18,
                16, 18, 17,

                // 15, 19, 10, 14, 7
                15, 7, 19,
                15, 10, 7,
                19, 7, 14,

                // 18, 19, 13, 14, 6
                19, 6, 18,
                6, 13, 18,
                6, 19, 14, 

                // 17, 18, 12, 13, 5
                18, 5, 17,
                5, 12, 17,
                5, 18, 13, 

                // 16, 17, 11, 12, 9
                17, 9, 16,
                9, 11, 16,
                9, 17, 12, 

                // 15, 16, 10, 11, 8
                16, 8, 15,
                8, 10, 15,
                8, 16, 11
            ]);



            var vertices;
            var normals;

            function ComputeVerticesNormals(){
                localVertices = [];
                localNormals = [];

                for (var i = 0; i < dodecahedronFaceIndexes.length; i += 3)
                {
                    var i1 = dodecahedronFaceIndexes[i] * 3;
                    var i2 = dodecahedronFaceIndexes[i + 1] * 3;
                    var i3 = dodecahedronFaceIndexes[i + 2] * 3;

                    // get the vertices for this triangular pentagon segement
                    var ax = explicitDodecahedronVertices[i1];
                    var ay = explicitDodecahedronVertices[i1 + 1];
                    var az = explicitDodecahedronVertices[i1 + 2];

                    var bx = explicitDodecahedronVertices[i2];
                    var by = explicitDodecahedronVertices[i2 + 1];
                    var bz = explicitDodecahedronVertices[i2 + 2];

                    var cx = explicitDodecahedronVertices[i3];
                    var cy = explicitDodecahedronVertices[i3 + 1];
                    var cz = explicitDodecahedronVertices[i3 + 2];

                    // calc normals
                    var ux = bx - ax;
                    var uy = by - ay;
                    var uz = bz - az;

                    var vx = bx - cx;
                    var vy = by - cy;
                    var vz = bz - cz;

                    var nx = (uz * vy) - (uy * vz);
                    var ny = (ux * vz) - (uz * vx);
                    var nz = (uy * vx) - (ux * vy);

                    // append vertices, normals to list
                    localVertices.push(ax, ay, az, bx, by, bz, cx, cy, cz);
                    localNormals.push(nx, ny, nz, nx, ny, nz, nx, ny, nz)
                }

                vertices = Float32Array.from(localVertices);
                normals = Float32Array.from(localNormals);
            }



            init();
            animate();

            function init() {
                var container = document.createElement( 'div' );
                document.body.appendChild( container );
                renderer = new THREE.WebGLRenderer();
                renderer.setPixelRatio( window.devicePixelRatio );
                renderer.setSize( window.innerWidth, window.innerHeight );
                container.appendChild( renderer.domElement );
                renderer.gammaInput = true;
                renderer.gammaOutput = true;
                //
                scene = new THREE.Scene();
                var aspect = window.innerWidth / window.innerHeight;
                camera = new THREE.OrthographicCamera( - height * aspect, height * aspect, height, - height, 1, 10000 );
                camera.position.z = 400;
                scene.add( camera );
                controls = new THREE.OrbitControls( camera, renderer.domElement );
                controls.enableZoom = false;
                controls.enableDamping = true;

                // lights
                ambientLight = new THREE.AmbientLight( 0xffffff, settings.ambientIntensity );
                scene.add( ambientLight );

                directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
                directionalLight.position.set(-50*32,0,0);

                scene.add( directionalLight );

                var path = "https://threejs.org/examples/textures/cube/SwedishRoyalCastle/";
                var format = '.jpg';
                var urls = [
                        path + 'px' + format, path + 'nx' + format,
                        path + 'py' + format, path + 'ny' + format,
                        path + 'pz' + format, path + 'nz' + format
                    ];


                var loader = new THREE.CubeTextureLoader();
                loader.setCrossOrigin( 'anonymous' );
                var reflectionCube = loader.load( urls );
                reflectionCube.format = THREE.RGBFormat;

                scene.background = reflectionCube;


                material = new THREE.MeshStandardMaterial( {
                    color: 0x888888,
                    roughness: settings.roughness,
                    metalness: settings.metalness,
                    side: THREE.FrontSide,
                    envMap: reflectionCube
                } );

                var geometry = new THREE.BufferGeometry();
                ComputeVerticesNormals();

                geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
                geometry.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );

                geometry.center();
                mesh = new THREE.Mesh( geometry, material );
                mesh.scale.multiplyScalar( 100 );

                scene.add( mesh );

                var vnh = new THREE.VertexNormalsHelper( mesh, 100, 0x00ff00, 1 ); 

                scene.add (vnh);


                stats = new Stats();
                container.appendChild( stats.dom );
                //
                window.addEventListener( 'resize', onWindowResize, false );
            }
            function onWindowResize() {
                var aspect = window.innerWidth / window.innerHeight;
                camera.left = - height * aspect;
                camera.right = height * aspect;
                camera.top = height;
                camera.bottom = - height;
                camera.updateProjectionMatrix();
                renderer.setSize( window.innerWidth, window.innerHeight );
            }
            //
            function animate() {
                requestAnimationFrame( animate );
                controls.update();
                stats.begin();
                render();
                stats.end();
            }
            function render() {
                renderer.render( scene, camera );
            }
        </script>

    </body>

</html>

1 个答案:

答案 0 :(得分:0)

感谢WestLangley的评论,我意识到错误是我对THREE.OrbitControls的理解。我错误地认为相机是静止的,模型是旋转的,而实际上它是相反的 - 模型是静态的,相机在模型周围移动。