1

我是 Threejs 的新手,我正在尝试使用axesHelper来可视化场景中所有对象的三轴。早些时候我使用的是简单的网格,所有的助手都工作正常。最近我已经将一些对象移动到实例化网格中,并且助手已经停止为它们工作。我已经通过尝试使用两个助手来确认这一点。(箭头和轴助手)

我正在使用react-three-fiber编写 JSX 风格的threejs。这是曾经为我工作的代码。

<mesh
      position={[geometry.position.x, geometry.position.y, geometry.position.z]}
      rotation={angle}
      geometry={geometry}>
      <meshLambertMaterial color={'red'} />
      <axesHelper />
</mesh>

这是新的不起作用。

<instancedMesh
      ref={ref}
      args={[(null as unknown) as BufferGeometry, (null as unknown) as Material, objects.length]}>
      <coneBufferGeometry args={[0.1, 0.1]}>
        <instancedBufferAttribute attachObject={['attributes', 'color']} args={[colorArray, 3]}/>
      </coneBufferGeometry>
      <meshLambertMaterial vertexColors />
      <axesHelper />
</instancedMesh>

所以现在我想确认我们是否可以将这些助手用于实例化网格?我尝试查看三个文档,但找不到与此问题相关的任何答案。我在 Threejs r127 上。

4

1 回答 1

2

InstancedBufferGeometry作为一种选择,您可以分解实例的矩阵,并根据 的几何形状将这些值传递给 的属性AxesHelper

这只是一个例子,而不是最终的解决方案。

body{
  overflow: hidden;
  margin: 0;
}
<script type="module">
console.clear();

import * as THREE from "https://threejs.org/build/three.module.js";
import {OrbitControls} from "https://threejs.org/examples/jsm/controls/OrbitControls.js";

let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(0, 8, 13);
let renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);

let controls = new OrbitControls(camera, renderer.domElement);

let light = new THREE.DirectionalLight(0xffffff, 1.5);
light.position.setScalar(10);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 1));

let cylGeom = new THREE.CylinderBufferGeometry(0.5, 1, 2, 8);
let cylMat = new THREE.MeshStandardMaterial({color: "red", roughness: 0.25, metalness: 0.75,  polygonOffset: true, polygonOffsetFactor: 1});
let cylinder = new THREE.InstancedMesh(cylGeom, cylMat, 100);
let dummy = new THREE.Object3D();
let mat4 = new THREE.Matrix4();
let counter = 0;
let pos = [];
let rot = [];
let scl = [];
for(let z = 0; z < 10; z++){
  for(let x = 0; x < 10; x++){
    dummy.position.set(-4.5 + x, 0, -4.5 + z).multiplyScalar(4);
    dummy.rotation.set(
      Math.random() * Math.PI * 2,
      Math.random() * Math.PI * 2,
      Math.random() * Math.PI * 2
    );
    dummy.updateMatrix();
    cylinder.setMatrixAt(counter, dummy.matrix);
    pos.push(dummy.position.x, dummy.position.y, dummy.position.z);
    rot.push(dummy.quaternion.x, dummy.quaternion.y, dummy.quaternion.z, dummy.quaternion.w);
    scl.push(dummy.scale.x, dummy.scale.y, dummy.scale.z);
    counter++;
  }
}
cylinder.instanceMatrix.needsUpdate = true;
console.log(cylinder);
scene.add(cylinder);

let axesHelper = new THREE.AxesHelper(2);
console.log(axesHelper);
let lineGeom = new THREE.InstancedBufferGeometry().copy(axesHelper.geometry);
lineGeom.instanceCount = Infinity;
lineGeom.setAttribute("instT", new THREE.InstancedBufferAttribute(new Float32Array(pos), 3));
lineGeom.setAttribute("instR", new THREE.InstancedBufferAttribute(new Float32Array(rot), 4));
lineGeom.setAttribute("instS", new THREE.InstancedBufferAttribute(new Float32Array(scl), 3));
let lineMat = new THREE.LineBasicMaterial({
  vertexColors: true,
  onBeforeCompile: shader => {
    shader.vertexShader = `
    attribute vec3 instT;
    attribute vec4 instR;
    attribute vec3 instS;
    
    // http://barradeau.com/blog/?p=1109
    vec3 trs( inout vec3 position, vec3 T, vec4 R, vec3 S ) {
        position *= S;
        position += 2.0 * cross( R.xyz, cross( R.xyz, position ) + R.w * position );
        position += T;
        return position;
    }
    ${shader.vertexShader}
`.replace(
      `#include <begin_vertex>`,
      `#include <begin_vertex>
      transformed = trs(transformed, instT, instR, instS);
`
    );
    console.log(shader.vertexShader);
  }
});
let lines = new THREE.LineSegments(lineGeom, lineMat);
scene.add(lines);

window.addEventListener( 'resize', onWindowResize );

let clock = new THREE.Clock();

renderer.setAnimationLoop(()=>{
  let t = clock.getDelta();
  
  for(let i = 0; i < counter; i++){
    cylinder.getMatrixAt(i, mat4);
    mat4.decompose(dummy.position, dummy.quaternion, dummy.scale);
    dummy.rotation.x += t;
    dummy.rotation.z += t*.5;
    dummy.updateMatrix();
    cylinder.setMatrixAt(i, dummy.matrix);
    cylinder.instanceMatrix.needsUpdate = true;
    linesTRS(i, dummy);
  }
  
  renderer.render(scene, camera);
})

function linesTRS(index, o){
  lineGeom.attributes.instT.setXYZ(index, o.position.x, o.position.y, o.position.z);
  lineGeom.attributes.instT.needsUpdate = true;
  lineGeom.attributes.instR.setXYZW(index, o.quaternion.x, o.quaternion.y, o.quaternion.z, o.quaternion.w);
  lineGeom.attributes.instR.needsUpdate = true;
  lineGeom.attributes.instS.setXYZ(index, o.scale.x, o.scale.y, o.scale.z);
  lineGeom.attributes.instS.needsUpdate = true;
}

function onWindowResize() {

  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize( innerWidth, innerHeight );

}
</script>

于 2021-05-12T22:27:40.307 回答