问题描述
我正在使用服务器生成图表的 base64 字符串表示形式。然后通过使用 POST 请求获取数据来加载它以响应组件。数据加载到反应状态,但场景在加载纹理之前渲染。我读过 Is there a way to wait for THREE.TextureLoader.load() to finish? ,我还应该使用 promise
吗?我想使用反应状态进行通信,因为在下面的示例中,最终的通信将更加复杂。
const Comp= () => {
const [state,setState] = useState(null)
// basic three.js scene setting
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(28,1,1000);
camera.position.set(75,25,50);
camera.lookAt(scene.position);
scene.add(camera);
camera.add(new THREE.PointLight(0xffffff,Infinity));
var cubeGeo = new THREE.BoxBufferGeometry(3,3,0.0001);
// fetching data
const getFile = (event) => {
fetch('http://127.0.0.1:5000/getFile',{
headers: {
'Accept': 'application/json','Content-Type': 'application/json'
},method: 'POST'
})
.then(response => response.json())
.then(response => setState(response.state))
}
// fetch data when loading
useEffect(
() => getFile(),[]
)
// use effect when change of state happens
// (it depends on [state])
useEffect(
() => {
// state contains image data as string representation of base64
var texture = new THREE.TextureLoader().load("data:image/jpeg;base64," + state);
var mat = new THREE.MeshBasicMaterial({ map: texture });
var cubes = []
const n = 100;
const V = 111;
// rest is irrelevant
for (var i = 0; i < n; i++) {
var mesh = new THREE.Mesh(cubeGeo,mat);
cubes[i] = mesh
var x = V * (Math.random() - .5);
var y = V * (Math.random() - .5);
var z = V * (Math.random() - .5);
var r = Math.sqrt(x ** 2 + y ** 2 + z ** 2) / 20
x /= r
y /= r
z /= r
// console.log(r,x,y,z)
cubes[i].position.x = x;
cubes[i].position.y = y;
cubes[i].position.z = z;
scene.add(cubes[i]);
}
},[state])
return (
<p ref={() => animate()} />
)
}
export default Comp;
解决方法
TextureLoader.load
对 onLoad
、onError
和 onProgress
使用回调。
因此,如果您想让场景等到纹理加载完毕,请在调用 onLoad
或 onError
之前不要开始渲染。
示例:
let url = "...";
let loader = new THREE.TextureLoader();
function onLoad(tex){
// start rendering now
}
function onError(){
// start rendering now?
}
function onProgress(xhr){
//...
}
loader.load(url,onLoad,onError,onProgress);
在three.js 的最新版本中,还有一个loadAsync
函数,它返回一个Promise
。有了这个,您可以构建您的应用程序以利用 async
/await
等待纹理完成加载。
伪代码:
// set up your scene,etc.,then...
async function run(){
let url = "...";
let loader = new THREE.TextureLoader();
function onProgress(xhr){
//...
}
await loader.loadAsync(url,onProgress); // or use .then/.catch
// start rendering now
}
run();
三.js r127
,我知道这不是正确的答案,但您应该看看 R3F React-three-fiber
https://github.com/pmndrs/react-three-fiber
并且它的 api 上有 useLoader:
https://github.com/pmndrs/react-three-fiber/blob/master/markdown/api.md#useloader
您可以在哪里:
useLoader(loader: THREE.Loader,url: string,extensions?,xhr?)