ThreeJS WebXR场景在React中显示为黑色,但在静态应用程序中则不显示

如何解决ThreeJS WebXR场景在React中显示为黑色,但在静态应用程序中则不显示

我正在尝试从React中的ThreeJS示例中重新创建WebXR dragging demo场景,但是在启动WebXR场景时发现了一个问题。

在我的React应用程序中,无论文档或场景颜色如何,它都会启动为黑色场景。当我退出VR场景时,渲染会暂停并且控件不会更新。

我有两个场景相同的演示:一个工作的静态演示和一个损坏的React演示。

静态工作演示(live via codesandbox

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>WebXR Test</title>
    <Meta charset="utf-8" />
    <Meta
      name="viewport"
      content="width=device-width,initial-scale=1.0,user-scalable=no"
    />
    <style>
      body {
        margin: 0;
        background-color: #000;
        overscroll-behavior: none;
      }

      canvas {
        bottom: 0;
        left: 0;
        position: absolute;
        right: 0;
        top: 0;
        width: 100vw;
      }
    </style>
  </head>
  <body>
    <script type="module">
      import * as THREE from "https://unpkg.com/three/build/three.module.js";
      import { OrbitControls } from "https://unpkg.com/three/examples/jsm/controls/OrbitControls.js";
      import { VRButton } from "https://unpkg.com/three/examples/jsm/webxr/VRButton.js";
      import { XRControllerModelFactory } from "https://unpkg.com/three/examples/jsm/webxr/XRControllerModelFactory.js";

      let container;
      let camera,scene,renderer;
      let controller1,controller2;
      let controllergrip1,controllergrip2;

      let controls;

      init();
      animate();

      function init() {
        container = document.createElement("div");
        document.body.appendChild(container);

        scene = new THREE.Scene();
        scene.background = new THREE.Color(0x808080);

        camera = new THREE.PerspectiveCamera(
          50,window.innerWidth / window.innerHeight,0.1,10
        );
        camera.position.set(0,1.6,3);

        controls = new OrbitControls(camera,container);
        controls.target.set(0,0);
        controls.update();

        const floorGeometry = new THREE.PlaneBufferGeometry(4,4);
        const floorMaterial = new THREE.MeshStandardMaterial({
          color: 0xeeeeee,roughness: 1.0,Metalness: 0.0
        });
        const floor = new THREE.Mesh(floorGeometry,floorMaterial);
        floor.rotation.x = -Math.PI / 2;
        floor.receiveShadow = true;
        scene.add(floor);

        scene.add(new THREE.HemisphereLight(0x808080,0x606060));

        const light = new THREE.DirectionalLight(0xffffff);
        light.position.set(0,6,0);
        light.castShadow = true;
        light.shadow.camera.top = 2;
        light.shadow.camera.bottom = -2;
        light.shadow.camera.right = 2;
        light.shadow.camera.left = -2;
        light.shadow.mapSize.set(4096,4096);
        scene.add(light);

        //

        renderer = new THREE.Webglrenderer({ antialias: true });
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth,window.innerHeight);
        renderer.outputEncoding = THREE.sRGBEncoding;
        renderer.shadowMap.enabled = true;
        renderer.xr.enabled = true;
        container.appendChild(renderer.domElement);

        document.body.appendChild(VRButton.createButton(renderer));

        // controllers

        controller1 = renderer.xr.getController(0);
        controller1.name = "left";
        scene.add(controller1);

        controller2 = renderer.xr.getController(1);
        controller2.name = "right";
        scene.add(controller2);

        const controllerModelFactory = new XRControllerModelFactory();

        controllergrip1 = renderer.xr.getControllergrip(0);
        controllergrip1.add(
          controllerModelFactory.createControllerModel(controllergrip1)
        );
        scene.add(controllergrip1);

        controllergrip2 = renderer.xr.getControllergrip(1);
        controllergrip2.add(
          controllerModelFactory.createControllerModel(controllergrip2)
        );
        scene.add(controllergrip2);

        //

        window.addEventListener("resize",onWindowResize,false);
      }

      function onWindowResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();

        renderer.setSize(window.innerWidth,window.innerHeight);
      }

      //

      function animate() {
        renderer.setAnimationLoop(render);
      }

      function render() {
        renderer.render(scene,camera);
      }
    </script>
  </body>
</html>

反应不灵的演示(live via codesandbox

body {
  margin: 0;
  background-color: #000;
  overscroll-behavior: none;
}

canvas {
  bottom: 0;
  left: 0;
  position: absolute;
  right: 0;
  top: 0;
  width: 100vw;
}
import React,{ useRef,useEffect } from "react";
import { render } from "react-dom";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { VRButton } from "three/examples/jsm/webxr/VRButton.js";
import { XRControllerModelFactory } from "three/examples/jsm/webxr/XRControllerModelFactory.js";
import "./styles.css"; // inlined above

const App = () => {
  const canvasRef = useRef();
  const camera = useRef();
  const scene = useRef();
  const renderer = useRef();
  const controller1 = useRef();
  const controller2 = useRef();
  const controllergrip1 = useRef();
  const controllergrip2 = useRef();
  const controls = useRef();

  useEffect(() => {
    renderer.current = new THREE.Webglrenderer({
      canvas: canvasRef.current,antialias: true
    });
    renderer.current.setPixelRatio(window.devicePixelRatio);
    renderer.current.setSize(window.innerWidth,window.innerHeight);
    renderer.current.outputEncoding = THREE.sRGBEncoding;
    renderer.current.shadowMap.enabled = true;
    renderer.current.xr.enabled = true;

    document.body.appendChild(VRButton.createButton(renderer));

    camera.current = new THREE.PerspectiveCamera(
      50,10
    );
    camera.current.position.set(0,3);

    controls.current = new OrbitControls(
      camera.current,renderer.current.domElement
    );
    controls.current.target.set(0,0);
    controls.current.update();

    scene.current = new THREE.Scene();
    scene.current.background = new THREE.Color(0x808080);

    const floorGeometry = new THREE.PlaneBufferGeometry(4,4);
    const floorMaterial = new THREE.MeshStandardMaterial({
      color: 0xeeeeee,Metalness: 0.0
    });
    const floor = new THREE.Mesh(floorGeometry,floorMaterial);
    floor.rotation.x = -Math.PI / 2;
    floor.receiveShadow = true;
    scene.current.add(floor);

    scene.current.add(new THREE.HemisphereLight(0x808080,0x606060));

    const light = new THREE.DirectionalLight(0xffffff);
    light.position.set(0,0);
    light.castShadow = true;
    light.shadow.camera.top = 2;
    light.shadow.camera.bottom = -2;
    light.shadow.camera.right = 2;
    light.shadow.camera.left = -2;
    light.shadow.mapSize.set(4096,4096);
    scene.current.add(light);

    // controllers

    controller1.current = renderer.current.xr.getController(0);
    controller1.current.name = "left";
    scene.current.add(controller1.current);

    controller2.current = renderer.current.xr.getController(1);
    controller2.current.name = "right";
    scene.current.add(controller2.current);

    const controllerModelFactory = new XRControllerModelFactory();

    controllergrip1.current = renderer.current.xr.getControllergrip(0);
    controllergrip1.current.add(
      controllerModelFactory.createControllerModel(controllergrip1.current)
    );
    scene.current.add(controllergrip1.current);

    controllergrip2.current = renderer.current.xr.getControllergrip(1);
    controllergrip2.current.add(
      controllerModelFactory.createControllerModel(controllergrip2.current)
    );
    scene.current.add(controllergrip2.current);
  },[]);

  useEffect(() => {
    const handleResize = () => {
      camera.current.aspect = window.innerWidth / window.innerHeight;
      camera.current.updateProjectionMatrix();

      renderer.current.setSize(window.innerWidth,window.innerHeight);
    };

    window.addEventListener("resize",handleResize,false);
    handleResize();

    return () => {
      window.removeEventListener("resize",false);
    };
  },[]);

  useEffect(() => {
    let animation;

    const animate = () => {
      animation = requestAnimationFrame(animate);

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

    animate();

    return () => {
      cancelAnimationFrame(animation);
    };
  },[]);

  return <canvas ref={canvasRef} />;
};

render(<App />,document.getElementById("root"));

解决方法

似乎是我处理渲染的罪魁祸首。

在两个场景中同时使用renderer.setAnimationLoop()将正常启动WebXR。

useEffect(() => {
  const animate = () => {
    renderer.current.render(scene.current,camera.current);
  };

  renderer.current.setAnimationLoop(animate);

  return () => {
    renderer.current.setAnimationLoop(null);
  };
},[]);

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?