2017-07-17 1 views
1

Ich bin ein Anfänger bis three.js und 3D-Grafiken im Allgemeinen. Dies ist in erster Linie eine Lernübung für mich.Schwarz unreflektierte Gesichter mit MeshStandardMaterial in three.js

Ich versuche, ein Dodekaeder mit metallischem Aussehen zu zeigen, aber etwa die Hälfte der Gesichter sind schwarz und reflektieren nicht. Die anderen Gesichter sehen korrekt aus.

Ich weiß, dass es eine eingebaute Funktion gibt, um ein Dodekaeder zu erzeugen, und um Normalen zu berechnen, aber ich möchte es manuell tun, um mein Verständnis zu überprüfen.

Zuerst dachte ich, es könnte ein Problem mit der Vertex-Normalen geben, aber mit der VertexNormalsHelper scheint es, dass die Normalen alle in die richtigen Richtungen zeigen.

Kann mir jemand sagen, wo ich falsch liege? Danke vielmals!

Code:

<!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> 
+0

Für ein korrektes Rendering - und speziell für Metalle - benötigt 'MeshStandardMaterial' eine Umgebungskarte (' material.envMap'), so dass es etwas zu reflektieren gibt. Schau, ob das dein Problem ist. – WestLangley

+0

Vielen Dank für Ihren Kommentar - Ich habe eine Umgebungskarte hinzugefügt, und es sieht viel besser aus. Die Umgebungskarte wird nun korrekt auf allen Flächen angezeigt. Allerdings scheint das Licht nur auf etwa der Hälfte der Gesichter zu reflektieren, so dass etwas immer noch nicht stimmt ... – Zakalwe

+0

Ein gerichtetes Licht wird nur eine Seite des Modells beleuchten. – WestLangley

Antwort

0

Dank WestLangley Kommentar wurde mir klar, der Fehler in meinem Verständnis von THREE.OrbitControls war. Ich nahm fälschlicherweise an, dass die Kamera statisch war und das Modell rotierte, während es in Wirklichkeit umgekehrt war - das Modell war statisch und die Kamera bewegte sich um das Modell herum.