【问题标题】:GLTF create instancesGLTF 创建实例
【发布时间】:2018-01-22 00:34:05
【问题描述】:

我是 THREEJS 的新手。过去,我使用过 AFRAME、CESIUM、XEOGL 和 BABYLONJS。但最终,由于内存消耗和性能,我意识到制作 CAD 可视化器的最佳产品是 THREEJS。

BABYLONJS 加载一个大的 GLTF 文件 (400MB) 需要 4 多分钟,而 THREEJS 只需 30 秒。 BABYLONJS 占用的内存是 THREEJS 的 4 倍。

我知道在 THREEJS 中从加载的 GLTF 文件创建实例 (GPU) 仍然存在一些问题,但我只需要更改每个实例中的位置和旋转,不需要任何动画。

我尝试过使用 GLTF1.0 和 GLTF2.0,但问题是一样的。 当我加载 GLTF 模型时,我得到了一个场景。从这个场景中,我试图从 children 数组中获取 buffergeometry。但是,当我尝试创建一个实例时,它不起作用。我的对象是静态的(根本没有动画)。

有什么方法可以创建 Object3D 的实例或从它的缓冲几何?

在 BABYLONJS 中,从加载的 GLTF 文件创建实例非常简单。我真的需要使用实例来节省 RAM 并使用 GPU 而不是 CPU 资源。我的场景需要加载相同对象的多个副本来复合场景。

我看到使用 GLFT 加载器的一些问题:

    1. 您必须识别所有包含有效几何图形的 object3D。在这个例子中是第 335 行:

    var geo = data.scene.children[0].children[0].children[0].children[0].geometry

    1. 合并示例不起作用。它在原始示例中也不起作用。
    1. IT 似乎根本无法提高性能:
  • 10000 个对象,多材质 --> 4FPS

  • 10000 个对象,单一材质--> 4FPS

  • 10000 个对象,实例化 --> 4FPS

  • 10000 个对象,合并 --> 不工作

    1. 选择实例化后,几何图形未正确渲染。

这里有我使用 Duck GLTF 示例的代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>three.js webgl - interactive instances (gpu)</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 {
        font-family: Monospace;
        background-color: #f0f0f0;
        margin: 0px;
        overflow: hidden;
      }
      .info {
        position: absolute;
        background-color: black;
        opacity: 0.8;
        color: white;
        text-align: center;
        top: 0px;
        width: 100%;
      }
      .info a {
        color: #00ffff;
      }
      #notSupported {
        width: 50%;
        margin: auto;
        border: 2px red solid;
        margin-top: 20px;
        padding: 10px;
      }
    </style>
  </head>
  <body>
    <div class="info">
      <a href="http://threejs.org" target="_blank" rel="noopener">three.js</a>
      webgl - gpu picking of geometry instances
      <div id="notSupported" style="display: none">
        Sorry your graphics card + browser does not support hardware instancing
      </div>
      <br /><br />
      <div>
        This demo compares different methods of constructing and rendering many
        instances of a single geometry.
      </div>
      <br />
      <div>
        <div style="display: inline-block">
          <span>number of<br />geometry instances</span>
          <br />
          <select id="instanceCount">
            <option>100</option>
            <option>500</option>
            <option selected>1000</option>
            <option>2000</option>
            <option>3000</option>
            <option>5000</option>
            <option>10000</option>
            <option>20000</option>
            <option>30000</option>
            <option>50000</option>
            <option>100000</option>
          </select>
        </div>
        &nbsp;&nbsp;&nbsp;
        <div style="display: inline-block">
          <span>method of<br />construction/rendering</span>
          <br />
          <select id="method">
            <option>instanced</option>
            <option>merged</option>
            <option selected>singleMaterial</option>
            <option>multiMaterial</option>
          </select>
        </div>
        &nbsp;&nbsp;&nbsp;
        <div style="display: inline-block">
          <span>render continuously<br />(to get fps reading)</span>
          <br />
          <input id="animate" type="checkbox" />
        </div>
        &nbsp;&nbsp;&nbsp;
        <div style="display: inline-block">
          <span
            >use override material<br />(only effects singleMaterial
            method)</span
          >
          <br />
          <input id="override" type="checkbox" checked />
        </div>
        &nbsp;&nbsp;&nbsp;
        <div style="display: inline-block">
          <span>construct anew<br />(to get additional timings)</span>
          <br />
          <button id="construct" type="button">do it</button>
        </div>
      </div>
      <br />
      <div>
        <span>Materials: #<span id="materialCount"></span></span>
        &nbsp;&nbsp;&nbsp;
        <span>Objects: #<span id="objectCount"></span></span>
        &nbsp;&nbsp;&nbsp;
        <span>Drawcalls: #<span id="drawcalls"></span></span>
        &nbsp;&nbsp;&nbsp;
        <span>Construction time: <span id="initTime"></span>&nbsp;ms</span>
        &nbsp;&nbsp;&nbsp;
      </div>
    </div>
    <div id="container"></div>
    <script src="../build/three.js"></script>
    <script src="js/controls/TrackballControls.js"></script>
    <script src="js/libs/stats.min.js"></script>
    <script src="js/loaders/GLTF2Loader.js"></script>
    <script id="vertMerged" type="x-shader/x-vertex">
      #define SHADER_NAME vertMerged
      precision highp float;
      uniform mat4 modelViewMatrix;
      uniform mat4 projectionMatrix;
      attribute vec3 position;
      #ifdef PICKING
      attribute vec3 pickingColor;
      #else
      attribute vec3 color;
      varying vec3 vPosition;
      #endif
      varying vec3 vColor;
      void main()   {
      vec3 positionEye = ( modelViewMatrix * vec4( position, 1.0 ) ).xyz;
      #ifdef PICKING
      vColor = pickingColor;
      #else
      vColor = color;
      vPosition = positionEye;
      #endif
      gl_Position = projectionMatrix * vec4( positionEye, 1.0 );
      }
    </script>
    <script id="fragMerged" type="x-shader/x-fragment">
      #define SHADER_NAME fragMerged
      #extension GL_OES_standard_derivatives : enable
      precision highp float;
      varying vec3 vColor;
      #ifndef PICKING
      varying vec3 vPosition;
      #endif
      void main()   {
      #ifdef PICKING
      gl_FragColor = vec4( vColor, 1.0 );
      #else
      vec3 fdx = dFdx( vPosition );
      vec3 fdy = dFdy( vPosition );
      vec3 normal = normalize( cross( fdx, fdy ) );
      float diffuse = dot( normal, vec3( 0.0, 0.0, 1.0 ) );
      gl_FragColor = vec4( diffuse * vColor, 1.0 );
      #endif
      }
    </script>
    <script id="vertInstanced" type="x-shader/x-vertex">
      #define SHADER_NAME vertInstanced
      precision highp float;
      uniform mat4 modelViewMatrix;
      uniform mat4 projectionMatrix;
      attribute vec3 position;
      attribute vec3 mcol0;
      attribute vec3 mcol1;
      attribute vec3 mcol2;
      attribute vec3 mcol3;
      #ifdef PICKING
      attribute vec3 pickingColor;
      #else
      attribute vec3 color;
      varying vec3 vPosition;
      #endif
      varying vec3 vColor;
      void main()   {
      mat4 matrix = mat4(
      vec4( mcol0, 0 ),
      vec4( mcol1, 0 ),
      vec4( mcol2, 0 ),
      vec4( mcol3, 1 )
      );
      vec3 positionEye = ( modelViewMatrix * matrix * vec4( position, 1.0 ) ).xyz;
      #ifdef PICKING
      vColor = pickingColor;
      #else
      vColor = color;
      vPosition = positionEye;
      #endif
      gl_Position = projectionMatrix * vec4( positionEye, 1.0 );
      }
    </script>
    <script id="fragInstanced" type="x-shader/x-fragment">
      #define SHADER_NAME fragInstanced
      #extension GL_OES_standard_derivatives : enable
      precision highp float;
      varying vec3 vColor;
      #ifndef PICKING
      varying vec3 vPosition;
      #endif
      void main()   {
      #ifdef PICKING
      gl_FragColor = vec4( vColor, 1.0 );
      #else
      vec3 fdx = dFdx( vPosition );
      vec3 fdy = dFdy( vPosition );
      vec3 normal = normalize( cross( fdx, fdy ) );
      float diffuse = dot( normal, vec3( 0.0, 0.0, 1.0 ) );
      gl_FragColor = vec4( diffuse * vColor, 1.0 );
      #endif
      }
    </script>
    <script id="vertMaterial" type="x-shader/x-vertex">
      #define SHADER_NAME vertMaterial
      precision highp float;
      uniform mat4 modelViewMatrix;
      uniform mat4 projectionMatrix;
      attribute vec3 position;
      #ifndef PICKING
      varying vec3 vPosition;
      #endif
      void main()   {
      vec3 positionEye = ( modelViewMatrix * vec4( position, 1.0 ) ).xyz;
      #ifndef PICKING
      vPosition = positionEye;
      #endif
      gl_Position = projectionMatrix * vec4( positionEye, 1.0 );
      }
    </script>
    <script id="fragMaterial" type="x-shader/x-fragment">
      #define SHADER_NAME fragMaterial
      #extension GL_OES_standard_derivatives : enable
      precision highp float;
      #ifdef PICKING
      uniform vec3 pickingColor;
      #else
      uniform vec3 color;
      varying vec3 vPosition;
      #endif
      void main()   {
      #ifdef PICKING
      gl_FragColor = vec4( pickingColor, 1.0 );
      #else
      vec3 fdx = dFdx( vPosition );
      vec3 fdy = dFdy( vPosition );
      vec3 normal = normalize( cross( fdx, fdy ) );
      float diffuse = dot( normal, vec3( 0.0, 0.0, 1.0 ) );
      gl_FragColor = vec4( diffuse * color, 1.0 );
      #endif
      }
    </script>
    <script>
      var container, stats;
      var camera, controls, scene, renderer;
      var pickingData, pickingRenderTarget, pickingScene;
      var useOverrideMaterial = true;
      var singleMaterial, singlePickingMaterial;
      var highlightBox;
      var materialList = [];
      var geometryList = [];
      var objectCount = 0;
      var geometrySize;
      var mouse = new THREE.Vector2();
      var scale = 1.03;
      var loader = new THREE.GLTF2Loader();
      var pixelBuffer = new Uint8Array(4);
      var instanceCount, method, doAnimate;
      gui();
      init();
      initMesh();
      if (doAnimate) animate();
      function gui() {
        var instanceCountElm = document.getElementById("instanceCount");
        instanceCount = parseInt(instanceCountElm.value);
        instanceCountElm.addEventListener("change", function () {
          instanceCount = parseInt(instanceCountElm.value);
          initMesh();
        });
        var methodElm = document.getElementById("method");
        method = methodElm.value;
        methodElm.addEventListener("change", function () {
          method = methodElm.value;
          initMesh();
        });
        var animateElm = document.getElementById("animate");
        doAnimate = animateElm.checked;
        animateElm.addEventListener("click", function () {
          doAnimate = animateElm.checked;
          animate();
        });
        var overrideElm = document.getElementById("override");
        useOverrideMaterial = overrideElm.checked;
        overrideElm.addEventListener("click", function () {
          useOverrideMaterial = overrideElm.checked;
          initMesh();
        });
        var constructElm = document.getElementById("construct");
        constructElm.addEventListener("click", function () {
          initMesh();
        });
      }
      function clean() {
        THREE.Cache.clear();
        materialList.forEach(function (m) {
          m.dispose();
        });
        geometryList.forEach(function (g) {
          g.dispose();
        });
        scene = new THREE.Scene();
        scene.background = new THREE.Color(0xffffff);
        scene.add(camera);
        scene.add(highlightBox);
        pickingScene = new THREE.Scene();
        pickingData = {};
        materialList = [];
        geometryList = [];
        objectCount = 0;
        singleMaterial = undefined;
        singlePickingMaterial = undefined;
      }
      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() * 40 - 20;
          position.y = Math.random() * 40 - 20;
          position.z = Math.random() * 40 - 20;
          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 = 0.001;
          matrix.compose(position, quaternion, scale);
        };
      })();
      function initMesh() {
        clean();
        loader.load("models/gltf/Duck/glTF-Binary/Duck.glb", function (data) {
          console.log(data);
          var geo =
            data.scene.children[0].children[0].children[0].children[0].geometry;
          console.log("geo:");
          console.log(geo);
          geo.computeBoundingBox();
          geometrySize = geo.boundingBox.getSize();
          geometryList.push(geo);
          var start = window.performance.now();
          switch (method) {
            case "merged":
              makeMerged(geo);
              break;
            case "instanced":
              makeInstanced(geo);
              break;
            case "singleMaterial":
              makeSingleMaterial(geo);
              break;
            case "multiMaterial":
              makeMultiMaterial(geo);
              break;
          }
          render();
          var end = window.performance.now();
          document.getElementById("materialCount").innerText =
            materialList.length;
          document.getElementById("objectCount").innerText = objectCount;
          document.getElementById("drawcalls").innerText =
            renderer.info.render.calls;
          document.getElementById("initTime").innerText = (end - start).toFixed(
            2
          );
        });
      }
      function makeMultiMaterial(geo) {
        var vert = document.getElementById("vertMaterial").textContent;
        var frag = document.getElementById("fragMaterial").textContent;
        var material = new THREE.RawShaderMaterial({
          vertexShader: vert,
          fragmentShader: frag,
          uniforms: {
            color: {
              value: new THREE.Color(),
            },
          },
        });
        var pickingMaterial = new THREE.RawShaderMaterial({
          vertexShader: "#define PICKING\n" + vert,
          fragmentShader: "#define PICKING\n" + frag,
          uniforms: {
            pickingColor: {
              value: new THREE.Color(),
            },
          },
        });
        var matrix = new THREE.Matrix4();
        for (var i = 0; i < instanceCount; i++) {
          var object = new THREE.Mesh(geo, material);
          objectCount++;
          randomizeMatrix(matrix);
          object.applyMatrix(matrix);
          var pickingObject = object.clone();
          objectCount++;
          object.material = material.clone();
          object.material.uniforms.color.value.setHex(Math.random() * 0xffffff);
          materialList.push(object.material);
          pickingObject.material = pickingMaterial.clone();
          pickingObject.material.uniforms.pickingColor.value.setHex(i + 1);
          materialList.push(pickingObject.material);
          pickingData[i + 1] = object;
          scene.add(object);
          pickingScene.add(pickingObject);
        }
        material.dispose();
        pickingMaterial.dispose();
      }
      function makeSingleMaterial(geo) {
        var vert = document.getElementById("vertMaterial").textContent;
        var frag = document.getElementById("fragMaterial").textContent;
        var material = new THREE.RawShaderMaterial({
          vertexShader: vert,
          fragmentShader: frag,
          uniforms: {
            color: {
              value: new THREE.Color(),
            },
          },
        });
        materialList.push(material);
        var pickingMaterial = new THREE.RawShaderMaterial({
          vertexShader: "#define PICKING\n" + vert,
          fragmentShader: "#define PICKING\n" + frag,
          uniforms: {
            pickingColor: {
              value: new THREE.Color(),
            },
          },
        });
        materialList.push(pickingMaterial);
        if (useOverrideMaterial) {
          singleMaterial = material;
          singlePickingMaterial = pickingMaterial;
        }
        var matrix = new THREE.Matrix4();
        function onBeforeRender(
          renderer,
          scene,
          camera,
          geometry,
          material,
          group
        ) {
          var updateList = [];
          var u = material.uniforms;
          var d = this.userData;
          if (u.pickingColor) {
            u.pickingColor.value.setHex(d.pickingColor);
            updateList.push("pickingColor");
          }
          if (u.color) {
            u.color.value.setHex(d.color);
            updateList.push("color");
          }
          if (updateList.length) {
            var materialProperties = renderer.properties.get(material);
            if (materialProperties.program) {
              var gl = renderer.getContext();
              var p = materialProperties.program;
              gl.useProgram(p.program);
              var pu = p.getUniforms();
              updateList.forEach(function (name) {
                pu.setValue(gl, name, u[name].value);
              });
            }
          }
        }
        for (var i = 0; i < instanceCount; i++) {
          var object = new THREE.Mesh(geo, material);
          objectCount++;
          randomizeMatrix(matrix);
          object.applyMatrix(matrix);
          var pickingObject;
          if (!useOverrideMaterial) {
            pickingObject = object.clone();
            objectCount++;
          }
          object.material = material;
          object.userData["color"] = Math.random() * 0xffffff;
          if (useOverrideMaterial) {
            object.userData["pickingColor"] = i + 1;
            object.onBeforeRender = onBeforeRender;
          } else {
            pickingObject.material = pickingMaterial;
            pickingObject.userData["pickingColor"] = i + 1;
            pickingObject.onBeforeRender = onBeforeRender;
          }
          pickingData[i + 1] = object;
          scene.add(object);
          if (!useOverrideMaterial) pickingScene.add(pickingObject);
        }
      }
      function makeMerged(geo) {
        var vert = document.getElementById("vertMerged").textContent;
        var frag = document.getElementById("fragMerged").textContent;
        var material = new THREE.RawShaderMaterial({
          vertexShader: vert,
          fragmentShader: frag,
        });
        materialList.push(material);
        var pickingMaterial = new THREE.RawShaderMaterial({
          vertexShader: "#define PICKING\n" + vert,
          fragmentShader: "#define PICKING\n" + frag,
        });
        materialList.push(pickingMaterial);
        var bgeo = geo.clone();
        geometryList.push(bgeo);
        var mgeo = new THREE.BufferGeometry();
        geometryList.push(mgeo);
        var pos = bgeo.attributes.position;
        var posLen = bgeo.attributes.position.count * 3;
        var vertices = new THREE.BufferAttribute(
          new Float32Array(instanceCount * posLen),
          3
        );

        var matrix = new THREE.Matrix4();
        for (var i = 0, ul = instanceCount; i < ul; i++) {
          randomizeMatrix(matrix);
          var object = new THREE.Object3D();
          objectCount++;
          object.applyMatrix(matrix);
          pickingData[i + 1] = object;
          vertices.set(pos.array, i * posLen);
          //matrix.applyToVector3Array( vertices.array, i * posLen, posLen )
        }
        mgeo.addAttribute("position", vertices);
        var colCount = posLen / 3;
        var colors = new THREE.BufferAttribute(
          new Float32Array(instanceCount * colCount * 3),
          3
        );

        var randCol = function () {
          return Math.random();
        };
        for (var i = 0, ul = instanceCount; i < ul; i++) {
          var r = randCol(),
            g = randCol(),
            b = randCol();
          for (var j = i * colCount, jl = (i + 1) * colCount; j < jl; j++) {
            colors.setXYZ(j, r, g, b);
          }
        }
        mgeo.addAttribute("color", colors);
        var col = new THREE.Color();
        var pickingColors = new THREE.BufferAttribute(
          new Float32Array(instanceCount * colCount * 3),
          3
        );
        for (var i = 0, ul = instanceCount; i < ul; i++) {
          col.setHex(i + 1);
          for (var j = i * colCount, jl = (i + 1) * colCount; j < jl; j++) {
            pickingColors.setXYZ(j, col.r, col.g, col.b);
          }
        }
        mgeo.addAttribute("pickingColor", pickingColors);
        var mesh = new THREE.Mesh(mgeo, material);
        scene.add(mesh);
        var pickingMesh = new THREE.Mesh(mgeo, pickingMaterial);
        pickingScene.add(pickingMesh);
      }
      function makeInstanced(geo) {
        var vert = document.getElementById("vertInstanced").textContent;
        var frag = document.getElementById("fragInstanced").textContent;
        var material = new THREE.RawShaderMaterial({
          vertexShader: vert,
          fragmentShader: frag,
        });
        materialList.push(material);
        var pickingMaterial = new THREE.RawShaderMaterial({
          vertexShader: "#define PICKING\n" + vert,
          fragmentShader: "#define PICKING\n" + frag,
        });
        materialList.push(pickingMaterial);
        var bgeo = geo.clone();
        geometryList.push(bgeo);
        var igeo = new THREE.InstancedBufferGeometry();
        geometryList.push(igeo);
        var vertices = bgeo.attributes.position.clone();
        igeo.addAttribute("position", vertices);
        var mcol0 = new THREE.InstancedBufferAttribute(
          new Float32Array(instanceCount * 3),
          3,
          1
        );
        var mcol1 = new THREE.InstancedBufferAttribute(
          new Float32Array(instanceCount * 3),
          3,
          1
        );
        var mcol2 = new THREE.InstancedBufferAttribute(
          new Float32Array(instanceCount * 3),
          3,
          1
        );
        var mcol3 = new THREE.InstancedBufferAttribute(
          new Float32Array(instanceCount * 3),
          3,
          1
        );
        var matrix = new THREE.Matrix4();
        var me = matrix.elements;
        for (var i = 0, ul = mcol0.count; i < ul; i++) {
          randomizeMatrix(matrix);
          var object = new THREE.Object3D();
          objectCount++;
          object.applyMatrix(matrix);
          pickingData[i + 1] = object;
          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]);
        }
        igeo.addAttribute("mcol0", mcol0);
        igeo.addAttribute("mcol1", mcol1);
        igeo.addAttribute("mcol2", mcol2);
        igeo.addAttribute("mcol3", mcol3);
        var randCol = function () {
          return Math.random();
        };
        var colors = new THREE.InstancedBufferAttribute(
          new Float32Array(instanceCount * 3),
          3,
          1
        );
        for (var i = 0, ul = colors.count; i < ul; i++) {
          colors.setXYZ(i, randCol(), randCol(), randCol());
        }
        igeo.addAttribute("color", colors);
        var col = new THREE.Color();
        var pickingColors = new THREE.InstancedBufferAttribute(
          new Float32Array(instanceCount * 3),
          3,
          1
        );
        for (var i = 0, ul = pickingColors.count; i < ul; i++) {
          col.setHex(i + 1);
          pickingColors.setXYZ(i, col.r, col.g, col.b);
        }
        igeo.addAttribute("pickingColor", pickingColors);
        var mesh = new THREE.Mesh(igeo, material);
        scene.add(mesh);
        var pickingMesh = new THREE.Mesh(igeo, pickingMaterial);
        pickingScene.add(pickingMesh);
      }
      function init() {
        camera = new THREE.PerspectiveCamera(
          70,
          window.innerWidth / window.innerHeight,
          1,
          100
        );
        camera.position.z = 40;
        pickingRenderTarget = new THREE.WebGLRenderTarget(
          window.innerWidth,
          window.innerHeight
        );
        pickingRenderTarget.texture.generateMipmaps = false;
        pickingRenderTarget.texture.minFilter = THREE.NearestFilter;
        highlightBox = new THREE.Mesh(
          new THREE.BoxGeometry(1, 1, 1),
          new THREE.MeshLambertMaterial({
            emissive: 0xffff00,
            transparent: true,
            opacity: 0.5,
            side: THREE.FrontSide,
          })
        );
        container = document.getElementById("container");
        renderer = new THREE.WebGLRenderer({
          antialias: true,
          alpha: true,
        });
        if (renderer.extensions.get("ANGLE_instanced_arrays") === false) {
          document.getElementById("notSupported").style.display = "";
          return;
        }
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth, window.innerHeight);
        container.appendChild(renderer.domElement);
        if (renderer.extensions.get("ANGLE_instanced_arrays") === false) {
          throw "ANGLE_instanced_arrays not supported";
        }
        controls = new THREE.TrackballControls(camera, renderer.domElement);
        controls.staticMoving = true;
        stats = new Stats();
        container.appendChild(stats.dom);
        renderer.domElement.addEventListener("mousemove", onMouseMove);
        window.addEventListener("resize", onWindowResize, false);
      }
      //
      function onMouseMove(e) {
        mouse.x = e.clientX;
        mouse.y = e.clientY;
        controls.update();
        requestAnimationFrame(render);
      }
      function onWindowResize(event) {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
        pickingRenderTarget.setSize(window.innerWidth, window.innerHeight);
      }
      function animate() {
        if (doAnimate) {
          requestAnimationFrame(animate);
        }
        controls.update();
        stats.update();
        document.getElementById("materialCount").innerText =
          materialList.length;
        document.getElementById("objectCount").innerText = objectCount;
        document.getElementById("drawcalls").innerText =
          renderer.info.render.calls;
        render();
      }
      function pick() {
        highlightBox.visible = false;
        if (singlePickingMaterial) {
          scene.overrideMaterial = singlePickingMaterial;
          renderer.render(scene, camera, pickingRenderTarget);
          scene.overrideMaterial = null;
        } else {
          renderer.render(pickingScene, camera, pickingRenderTarget);
        }
        renderer.readRenderTargetPixels(
          pickingRenderTarget,
          mouse.x,
          pickingRenderTarget.height - mouse.y,
          1,
          1,
          pixelBuffer
        );
        var id =
          (pixelBuffer[0] << 16) | (pixelBuffer[1] << 8) | pixelBuffer[2];
        var object = pickingData[id];
        if (object) {
          if (object.position && object.rotation && object.scale) {
            highlightBox.position.copy(object.position);
            highlightBox.rotation.copy(object.rotation);
            highlightBox.scale
              .copy(object.scale)
              .multiply(geometrySize)
              .multiplyScalar(scale);
            highlightBox.visible = true;
          }
        } else {
          highlightBox.visible = false;
        }
      }
      function render() {
        pick();
        renderer.render(scene, camera);
      }
    </script>
  </body>
</html>

【问题讨论】:

    标签: three.js instance gltf


    【解决方案1】:

    您的问题似乎主要是,如何在 three.js 中进行实例化?一旦你加载了一个模型,你用什么格式来创建它并不重要。

    既然如此,您可能只想查看three.js instancing examples 或使用three-instanced-mesh 之类的助手之一。

    第二个链接显示了从模型中获取几何图形后如何继续:

    // Assumes your model only contains one mesh.
    var geometry;
    model.traverse(function (node) => {
      if (node.isMesh) {
        geometry = node.geometry;
      }
    });
    
    //material that the geometry will use 
    var material = new THREE.MeshPhongMaterial();
    
    //the instance group 
    var cluster = new THREE.InstancedMesh( 
      geometry,
      material, 
      10000, //instance count 
      false, //is it dynamic 
      false  //does it have color 
      true,  //uniform scale
    );
    
    var _v3 = new THREE.Vector3();
    var _q = new THREE.Quaternion();
    
    for ( var i ; i < 10000 ; i ++ ) {
    
      cluster.setQuaternionAt( i , _q );
      cluster.setPositionAt( i , v3.set( Math.random() , Math.random(), Math.random() ) );
      cluster.setScaleAt( i , v3.set(1,1,1) );
    
    }
    
    scene.add( cluster );
    

    【讨论】:

      【解决方案2】:

      经过一段时间的调查,我发现为什么使用 instancedbuffergeometries 不能与我的 GLTF 文件中找到的 buffergeometries 一起使用。

      问题在于 GLTF 格式使用 indexedbuffergeometries,解决方法很简单,只需使用 toNonIndexed() 方法转换即可。

      问题已解决。

      最好的问候

      【讨论】:

        猜你喜欢
        • 2021-04-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-16
        • 2015-10-08
        • 2011-10-30
        • 2012-08-28
        相关资源
        最近更新 更多