编辑:我现在已将问题隔离到这个小 gist 中还有这个jsfiddle .
我想在一个基于 three.js 的实时 3D 游戏中使用 Redux 进行状态管理。我创建了一个用于测试目的的小型原型(prototype),但即使是这个非常简单的玩具应用程序也显示出一些严重的性能问题。
我的想法是构建一个渲染循环,使用 requestAnimationFrame()
回调在每一帧调度一个 UPDATE
Action :
index.js
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import * as THREE from 'three'
import rootReducer from './reducers/rootReducer'
import App from './components/App'
import { getThreeInitialState, getThreeRenderer } from './threeApp/threeApp'
const threeInitialState = getThreeInitialState();
const initialState = {
running: false,
...threeInitialState
}
const store = createStore(rootReducer, initialState)
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
const threeRenderer = getThreeRenderer()
const updateThreeApp = () => {
threeRenderer.render(store.getState().scene, store.getState().camera)
const timestamp = Date.now()
requestAnimationFrame(() => store.dispatch({ type: 'UPDATE', timestamp: timestamp }))
}
store.subscribe(updateThreeApp)
store.dispatch({ type: 'UPDATE' })
document.addEventListener('click', () => store.dispatch({ type: 'CHANGE_MATERIAL' }));
最后一行中的事件监听器调度一个事件,该事件更改为测试目的而呈现的立方体的 Material 。当然在游戏中会多一些处理键盘鼠标事件的监听器。
我的 reducer 是这样的:
rootReducer.js
const changeMaterial = (state) => {
const newState = { ...state }
newState.scene.getObjectByName('box').material.wireframe = !newState.scene.getObjectByName('box').material.wireframe
return newState
}
const rotate = (state) => {
const newState = { ...state }
newState.scene.getObjectByName('box').position.y = 2 * Math.sin(Date.now() / 1000)
return newState
}
const rootReducer = (state, action) => {
switch (action.type) {
case 'CHANGE_MATERIAL':
return state.running ? changeMaterial(state) : state
case 'RUN':
return {
...state,
running: true,
}
case 'UPDATE':
return rotate(state)
default:
return state
}
}
export default rootReducer;
顶部的两个函数用于改变渲染立方体的 Material 和位置。
每帧更新 three.js 场景并移动立方体效果非常好。但是,每次我触发点击事件以更改 Material 时,帧率都会下降一点并保持这种状态。因此,在随机点击几秒钟后,它从 60 FPS 下降到大约 20 FPS 并且不再上升,尽管 Action 已经完成。查看 Chrome 性能配置文件,每次触发点击事件时 CPU 使用率都会显着增加。事件发生后,CPU 使用率也保持在这个较高水平。
我还使用 ReactDOM.render()
来渲染起始页、加载屏幕等内容,但我想将 three.js 渲染循环保留在 React 部分之外,以将它们分开并避免不必要的 DOM 更新。 three.js 部分和 React 之间的唯一联系是 three.js 渲染器的容器 DIV 位于 React 组件之一内。
完整代码上传于this repository我还创建了一个小的 gist显示我的 redux 渲染循环应该如何工作。
这是我第一次使用 Redux 和 React,所以我可能只是忽略了一些东西。还是将这种架构用于 3D 游戏是一个相当糟糕的想法?任何帮助将不胜感激!
最佳答案
已解决:似乎在 UPDATE
和 CHANGE_MATERIAL
这两个操作上调用 requestAnimationFrame()
导致了问题。将 lastAction
属性添加到状态对象并仅在它等于 UPDATE
时渲染解决了这个问题。看这个gist .
关于javascript - React、Redux 和 three.js 的性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45733058/