【发布时间】:2017-08-17 10:46:28
【问题描述】:
编辑:我现在已将问题分离到这个小gist 和这个jsfiddle。
我想在基于 three.js 的实时 3D 游戏中使用 Redux 进行状态管理。我为测试目的创建了一个小型原型,但即使是这个非常简单的玩具应用程序也显示出一些严重的性能问题。
我的想法是构建一个渲染循环,使用 requestAnimationFrame() 回调在每一帧调度一个 UPDATE 动作:
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' }));
最后一行中的事件侦听器调度了一个事件,该事件更改了为测试目的而呈现的立方体的材质。当然在游戏中还会有更多的监听器来处理键盘和鼠标事件。
我的减速器是这样的:
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 场景并移动立方体都可以正常工作。但是,每次我触发点击事件来更改材质时,帧率都会下降一点并保持这样。所以在随机点击几秒钟后,它从 60 FPS 下降到大约 20 FPS 并且不再上升,尽管动作已经完成。查看 Chrome 性能配置文件,每次触发 click 事件时 CPU 使用率都会显着增加。事件发生后 CPU 使用率也保持在此较高水平。
我还使用ReactDOM.render() 来渲染起始页、加载屏幕等内容,但我想将three.js 渲染循环保留在React 部分之外,以分隔事物并避免不必要的DOM 更新。 three.js 部分和 React 之间的唯一联系是,three.js 渲染器的容器 DIV 位于其中一个 React 组件中。
完整的代码上传到this repository,我还创建了一个小的gist,展示了我的redux渲染循环应该如何工作。
这是我第一次使用 Redux 和 React,所以我可能只是忽略了一些东西。还是将这种架构用于 3D 游戏是一个相当糟糕的想法?任何帮助将不胜感激!
【问题讨论】:
-
这是
newState.scene.getObjectByName('box').material.wireframe = !newState.scene.getObjectByName('box').material.wireframe是个好东西吗?我知道 redux 喜欢差异化的东西等等,但是在这个比较的两边搜索整个场景图,每一帧看起来都很紧张? -
是的,我想通过 reducer 传递整个场景图并不是最有效和最类似于 Redux 的处理方式。最好只在状态树中存储一些信息,如
wireframe: true或wireframe: false,然后在每次更新时将状态或状态更改应用于场景图。我正在考虑 react-redux 中的mapStateToProps()之类的东西,我只是不确定如何解决这个问题......
标签: javascript reactjs three.js redux react-redux