React,Redux和three.js的性能问题

时间:2017-08-17 10:46:29

标签: javascript reactjs three.js redux react-redux

编辑:我现在已将问题分离到这个小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游戏是一个相当糟糕的想法?任何帮助将非常感谢!

1 个答案:

答案 0 :(得分:1)

已解决:好像在requestAnimationFrame()UPDATE这两个操作上调用CHANGE_MATERIAL都会导致问题。将lastAction属性添加到状态对象并仅在等于UPDATE时呈现才能解决问题。请参阅此gist