Избегайте нулевой проверки загруженных .obj-моделей в Three. js - PullRequest
1 голос
/ 25 мая 2020

Я использую три. js в проекте Angular. Я хочу загрузить простой файл .obj и переместить его на холст.

Код работает нормально; однако я должен явно выполнить нулевую проверку в моей функции animate (), чтобы увидеть, загружена ли модель еще или нет. Без проверки на null консоль будет регистрировать следующее:

TypeError: невозможно прочитать свойство 'position', равное null, в 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);
  }
}

Is есть ли лучший способ манипулировать объектом в моей анимации-l oop без необходимости каждый раз выполнять нулевую проверку?

Ответы [ 2 ]

2 голосов
/ 25 мая 2020

Одно из решений - начать анимацию сразу после загрузки модели. Это означает, что вы вызываете animate() в обратном вызове onLoad() сразу после добавления модели в сцену.

0 голосов
/ 26 мая 2020

Другой подход, если вам нужно, чтобы анимация l oop запускалась перед загрузкой чего-либо, заключается в замене ваших ссылок на фиктивный объект:

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

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

Таким образом, вы можете ожидать, что у вас будет все методы и члены существуют, но они будут noops.

...