javascript - React、Redux 和 three.js 的性能问题

标签 javascript reactjs three.js redux react-redux

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

最佳答案

已解决:似乎在 UPDATECHANGE_MATERIAL 这两个操作上调用 requestAnimationFrame() 导致了问题。将 lastAction 属性添加到状态对象并仅在它等于 UPDATE 时渲染解决了这个问题。看这个gist .

关于javascript - React、Redux 和 three.js 的性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45733058/

相关文章:

javascript - 如果我在之前的选择中选择了一个选项,则删除输入字段

reactjs - BrowseSEO 无法读取 Next.js React App 中的 META 标签

javascript - three.js 控制台错误 "scene.getObjectByName(...) is undefined"但一切似乎都很好?

3d - 在 Three.Js 中使物体完全适合相机视锥

javascript - 使用 moment.Js 将字符串转换为 24 小时时间格式

javascript - 如果模型中不存在数据,则使用 django 保存数据,如果数据存在则更新

javascript - meteor 不会更新 mongodb 中的数据

reactjs - 我如何默认检查 react 中的单选按钮?

javascript - 如何用 Jest 模拟/替换对象的 getter 函数?

javascript - 如何设置控件的第一个 lookAt/target