开发者问题收集

避免在 Three.js 中对已加载的 .obj 模型进行空检查

2020-05-25
110

我在 Angular 项目中使用 three.js。 我想加载一个简单的 .obj 文件并将其移动到画布上。

代码运行良好;但是我必须在 animate() 函数中明确执行空检查,以查看模型是否已加载。 如果没有空检查,控制台将记录以下内容:

TypeError: Cannot read property 'position' of null at TestComponent.animate (test.component.ts:71)

我想那是因为尚未设置实例引用,因为此时 OBJLoader 仍在忙于加载资源。

最小可验证示例:

import * as THREE from 'three';
import { OBJLoader2 } from 'three/examples/jsm/loaders/OBJLoader2.js';
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader.js';
import { MtlObjBridge } from 'three/examples/jsm/loaders/obj2/bridge/MtlObjBridge.js';

@Component({
  selector: 'app-test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.css'],
})
export class TestComponent implements AfterViewInit {
  @ViewChild('rendererContainer') rendererContainer: ElementRef;

  renderer: THREE.WebGLRenderer;
  scene = null;
  camera = null;
  mesh = null;
  loader = null;
  female = null;

  constructor() {}

  ngAfterViewInit() {
    this.init();
    this.animate();
  }

  init() {
    this.renderer = new THREE.WebGLRenderer();
    this.renderer.setPixelRatio(window.devicePixelRatio);
    this.renderer.setSize(window.innerWidth, window.innerHeight);
    this.rendererContainer.nativeElement.appendChild(this.renderer.domElement);

    this.scene = new THREE.Scene();
    this.scene.add(new THREE.AmbientLight(0xffffff));

    this.camera = new THREE.PerspectiveCamera(
      75,
      window.innerWidth / window.innerHeight,
      1,
      10000
    );

    this.camera.position.z = 500;

    this.loader = new OBJLoader2();

    new MTLLoader().load('./../../assets/models/female02.mtl', (mtl) => {
      this.loader.setModelName('female02');
      this.loader.setLogging(true, true);
      this.loader.addMaterials(
        MtlObjBridge.addMaterialsFromMtlLoader(mtl),
        true
      );
      this.loader.load(
        './../../assets/models/female02.obj',
        (object3d) => {
          this.female = object3d;
          this.scene.add(object3d);
        },
        null,
        null,
        null
      );
    });
  }

  animate() {
    if (this.female != null) { //explicit null-Check necessary
      if (this.female.position.z < 250) {
        this.female.translateZ(1);
      }
    }

    window.requestAnimationFrame(() => this.animate());
    this.renderer.render(this.scene, this.camera);
  }
}

有没有更好的方法来操作动画循环中的对象,而不必每次都进行空检查?

2个回答

一种解决方案是在模型加载后立即开始动画。这意味着在将模型添加到场景后,立即在 onLoad() 回调中调用 animate()

Mugen87
2020-05-25

另一种方法是,如果您需要在加载任何内容之前触发动画循环,则用虚拟对象替换您的引用:

const nullObject= new Object3D()
let female = nullObject
let male = nullObject
let child = nullObject

//...
function onLoad( trueObject ) {
  female = trueObject
}

这样,您可以期望拥有所有现有的方法和成员,但它们将是无用的。

pailhead
2020-05-25