ThreeJS: Как заменить кубическую сетку на автомобильную сетку?

#javascript #html #three.js #mesh

Вопрос:

Я разработал 3D-куб, который движется по одной оси, имитируя датчик акселерометра. В настоящее время у меня есть .obj и .mtl игрушечного автомобиля, который я собираюсь добавить в сцену(), но когда я удаляю 3D-куб BoxGeometry и заменяю его сеткой автомобиля, я все время получаю эти ошибки:

ошибка

Я также получаю эту ошибку, говоря, что obj не определен, даже если я определил его глобально, у меня все равно та же проблема:

ошибка 2

Я проверил библиотеки, которые существуют локально, и другие функции, но я не вижу, в чем проблема.

Ниже показано, как я загружаю модель автомобиля:

 const scene = new THREE.Scene();

    var loader = new THREE.OBJMTLLoader();
    loader.load('https://jyunming-chen.github.io/tutsplus/models/toycar.obj', 'https://jyunming-chen.github.io/tutsplus/models/toycar.mtl',
      function (vehicle) {
        toycar = vehicle;
        toycar.rotateY(-10.99);
        scene.add(toycar);
      });
 

и это мое полное .HTML-код с реализацией js:

Это хок выглядит так, как сейчас: 3D кубическая сетка

и это то, чего я стремлюсь достичь:

окончательная модель автомобиля

Это мой текущий код:

 <html>

<head>
  <meta charset="UTF-8">
  <script src="./three.min.js"></script>
  <script src="./require.js" type="text/javascript"></script>
  <script src="./OrbitControls.js"></script>
    <script src="./KeyboardState.js"></script>
    <script src="./MTLLoader.js"></script>
    <script src="./OBJMTLLoader.js"></script>
  <script type="module"> import * as THREE from "./three.module.js"</script>
</head>

<body>
  <canvas id="canvas" width="1000" height="600" style="border:1px solid #000000;"></canvas>

</body>
<script>

  let sensorValue = 0;
  let sensorAddr = 0;
  var toycar;
  StartRetrieveLiveData();

  function main() {
    const canvas = document.querySelector('#canvas');
    const accelPanel = document.querySelector('#accelPanel');
    const renderer = new THREE.WebGLRenderer({  alpha: true, canvas });
    renderer.setClearColor( 0x626d73, 1 ); 
    var context = canvas.getContext("2d");
    var width = window.innerWidth;
    var height = window.innerHeight;

    const fov = 70;
    const aspect = 2;
    const near = 20;
    const far = 500;
    const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);

    camera.position.set(0, 50, 1.5);
    camera.up.set(0, 0, 1);
    camera.lookAt(0, 0, 0);

    const scene = new THREE.Scene();

    // var loader = new THREE.OBJMTLLoader();
    // loader.load('https://jyunming-chen.github.io/tutsplus/models/toycar.obj', 'https://jyunming-chen.github.io/tutsplus/models/toycar.mtl',
    //   function (vehicle) {
    //     toycar = vehicle;
    //     toycar.rotateY(-10.99);
    //     scene.add(toycar);
    //   });

    // An array of objects who's rotation to update
    const objects = [];
    const radius = 3;
    const widthSegments = 3;
    const heightSegments = 3;
    const sphereGeometry = new THREE.BoxGeometry(radius, widthSegments, heightSegments);
    const sunMaterial = new THREE.MeshBasicMaterial({ color: "green", wireframe: false });
    const object = new THREE.Mesh(sphereGeometry, sunMaterial);

    var cubeAxis = new THREE.AxesHelper(10);
    object.add(cubeAxis);

    object.scale.set(2, 2, 2);
    scene.add(object);
    objects.push(object);

    function resizeRendererToDisplaySize(renderer) {
      const canvas = renderer.domElement;
      const width = canvas.clientWidth;
      const height = canvas.clientHeight;
      const needResize = canvas.width !== width || canvas.height !== height;
      if (needResize) {
        renderer.setSize(width, height, false);
      }
      return needResize;
    }

    function render() {

      if (resizeRendererToDisplaySize(renderer)) {
        const canvas = renderer.domElement;
        camera.aspect = canvas.clientWidth / canvas.clientHeight;
        camera.updateProjectionMatrix();
      }
 
      objects.forEach((obj) => {
        sensorValueIndex = ((sensorValue / 16384) * 10);
        obj.position.z = ((sensorValue / 16384) * 20);
        console.log("AccX: ",sensorValueIndex);

        // // Here I take accelerometerX and pass them to the 3D model
        // if (sensorAddr === 1) {
          
        // }
        
      });

      renderer.render(scene, camera);
      
      requestAnimationFrame(render);
    }
    requestAnimationFrame(render);
  }

  function onMsg(event) {
    // console.log(`[message] Data received from server: ${event.data}`);
    // console.log("event.data = "   JSON.parse(event.data));

    var received_msg = event.data;
    var obj = JSON.parse(JSON.parse(received_msg));

    if (obj !== null) {

      if (
        obj.hasOwnProperty("DataMapChangedObjectsAddressValue") amp;amp;
        obj["DataMapChangedObjectsAddressValue"][0]["DataMapAddress"] !==
        undefined
      ) {
        sensorAddr =
          obj["DataMapChangedObjectsAddressValue"][0]["DataMapAddress"];
        sensorValue =
          obj["DataMapChangedObjectsAddressValue"][0]["Value"];

        // if (sensorAddr === 1) {
        //   sensorValueIndex = (sensorValue / 16384) * 500;
        // }
      }
    }
  }

  function onOpen(e) {
    console.log("SSE connected");
  }

  function onError(e) {
    // console.log(`[error] ${error.message}`);
    if (e.eventPhase == EventSource.CLOSED) this.source.close();
    if (e.target.readyState == EventSource.CLOSED) {
      console.log("SSE Disconnected");
    } else if (e.target.readyState == EventSource.CONNECTING) {
      console.log("SSE Connecting ...");
    }
  }

  function StartRetrieveLiveData() {
    if (!!window.EventSource) {
      this.source = new EventSource("/sse");
    } else {
      console.log("Your browser doesn't support SSE");
    }

    this.source.addEventListener("message", e => this.onMsg(e));

    this.source.addEventListener("open", e => this.onOpen(e), false);

    this.source.addEventListener("error", e => this.onError(e), false);

    // Add here (only mozilla)
    main();
    // Add here

  }

</script>

</html>
 

Обратите внимание, что когда я использовал общедоступный сервер, все работает просто отлично, но я использовал удаленный сервер (фактический сервер), я получаю эти ошибки, и все работает не так, как ожидалось.

Был бы признателен за решение этой проблемы.

Ответ №1:

Я решил проблему, поэтому я собираюсь ответить на этот вопрос.

Во-первых, документ.querySelector(‘#canvas’) следует удалить, чтобы избежать создания двух canvas, потому что я вызываю библиотеки в . Это была глупая ошибка, но в конце концов я ее обнаружил.

Во-вторых, положение камеры было выключено, и она на самом деле не была направлена на автомобиль, поэтому на экране ничего не отображалось. Я изменил положение камеры по осям X, Y и Z, чтобы сделать это правильно.

Было множество других глупых ошибок, которые я обнаружил при тщательной отладке кода, я еще не специалист по языку, поэтому эти ошибки служат для меня опытом обучения.

Окончательный рабочий код приведен ниже:

   let sensorValue = 0;
  var toycar;
  StartRetrieveLiveData();
  var scene, renderer, camera;
  var controls, keyboard = new KeyboardState();
  var toycar;

  function init() {
    var width = window.innerWidth;
    var height = window.innerHeight;

    renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
    renderer.setClearColor(0x626d73, 1);
    renderer.setSize(width, height);
    document.body.appendChild(renderer.domElement);

    scene = new THREE.Scene();

    camera = new THREE.PerspectiveCamera(10, width / height, 1, 10000);
    camera.position.y = -150;
    camera.lookAt(new THREE.Vector3(0, 0, 0));

    var loader = new THREE.OBJMTLLoader();
    loader.load('./toycar.obj', './toycar.mtl',
      function (object) {
        toycar = object;
        toycar.rotateZ(10.99); //toycar.rotateZ(-10.99);
        scene.add(toycar);
      });

    var gridXZ = new THREE.GridHelper(350000, 10000);
    gridXZ.setColors(new THREE.Color(0xff0000), new THREE.Color(0xffffff));
    scene.add(gridXZ);

    var pointLight = new THREE.PointLight(0xffffff);
    pointLight.position.set(350, 20, 5);
    scene.add(pointLight);

    var ambientLight = new THREE.AmbientLight(0x111111);
    scene.add(ambientLight);
  }

  function animate() {
    var angle = 0;
    var speed = 0;
    var pos   = new THREE.Vector3(0, 0, 0);
    var clock = new THREE.Clock();
    var dt = clock.getDelta();
    var dir = new THREE.Vector3(1, 0, 0);
    dir.multiplyScalar(dt * speed);
    dir.applyAxisAngle(new THREE.Vector3(0, 0, 0), 10);
    pos.add(dir);

    if (toycar != undefined) {
      sensorValueIndex = ((sensorValue / 16384) * 50);
      toycar.scale.set(0.1, 0.1, 0.1);
      toycar.position.x = sensorValueIndex;
      toycar.position.y = 0;
      toycar.position.z = 0;
      toycar.rotation.x = (angle   Math.PI);
    }

    requestAnimationFrame(animate);
    renderer.render(scene, camera);
  }

  function onMsg(event) {    
    var received_msg = event.data;
    var obj = JSON.parse(JSON.parse(received_msg));

    if (obj !== null) {

      if (
        obj.hasOwnProperty("DataMapChangedObjectsAddressValue") amp;amp;
        obj["DataMapChangedObjectsAddressValue"][0]["DataMapAddress"] !==
        undefined
      ) {
        let sensorAddr =
          obj["DataMapChangedObjectsAddressValue"][0]["DataMapAddress"];
        sensorValue =
          obj["DataMapChangedObjectsAddressValue"][0]["Value"];

        if (sensorAddr === 1) {
          sensorValueIndex = (sensorValue / 16384) * 10;
          console.log(sensorValueIndex);
        }
      }
    }
  }