我正在尝试从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, 1.6, 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,
window.innerWidth / window.innerHeight,
0.1,
10
);
camera.current.position.set(0, 1.6, 3);
controls.current = new OrbitControls(
camera.current,
renderer.current.domElement
);
controls.current.target.set(0, 1.6, 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,
roughness: 1.0,
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, 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.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", handleResize, 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"));
答案 0 :(得分:0)
似乎是我处理渲染的罪魁祸首。
在两个场景中同时使用renderer.setAnimationLoop()将正常启动WebXR。
useEffect(() => {
const animate = () => {
renderer.current.render(scene.current, camera.current);
};
renderer.current.setAnimationLoop(animate);
return () => {
renderer.current.setAnimationLoop(null);
};
}, []);