编辑:我现在已将问题分离到这个小gist和此jsfiddle。
我想在基于three.js的实时3D游戏中使用Redux进行状态管理。我已经为测试目的创建了一个小型原型,但即便是这个非常简单的玩具应用也会出现一些严重的性能问题。
我的想法是构建一个渲染循环,使用UPDATE
回调每帧调度requestAnimationFrame()
个动作:
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' }));
最后一行中的事件侦听器调度一个事件,该事件更改为testig目的而呈现的多维数据集的材质。当然在游戏中会有更多的听众用于处理键盘和鼠标事件。
我的减速机看起来像这样:
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;
顶部的两个函数用于更改渲染立方体的材质和位置。
每帧更新three.js场景并移动立方体的效果非常好。但是,每次我触发click事件来更改材质时,帧速率会下降一点并保持这样。因此,在随机点击几秒后,它从60 FPS下降到大约20 FPS并且不再上升,尽管操作已经完成。查看Chrome性能配置文件,每次点击事件被触发时,CPU使用率都会显着增加。事件发生后,CPU使用率也会保持在较高水平。
我还使用ReactDOM.render()
来渲染诸如起始页面,加载屏幕之类的东西。但是我想在React部分之外保留three.js渲染循环以分离事物并避免不必要的DOM更新。 three.js-part和React之间的唯一连接是three.js渲染器的容器DIV位于其中一个React组件中。
完整的代码已上传到this repository,我还创建了一个小gist,展示了我的redux渲染循环应该如何工作。
这是我第一次使用Redux和React,所以我可能只是忽略了一些东西。或者将这种架构用于3D游戏是一个相当糟糕的想法?任何帮助将非常感谢!
答案 0 :(得分:1)
已解决:好像在requestAnimationFrame()
和UPDATE
这两个操作上调用CHANGE_MATERIAL
都会导致问题。将lastAction
属性添加到状态对象并仅在等于UPDATE
时呈现才能解决问题。请参阅此gist。