You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React-three-fiber模型性能优化咨询:FPS骤降问题

React-Three-Fiber 模型集成导航栏后的性能优化方案

问题背景

将Circle模型(压缩后5MB,未压缩50MB)及CirclesLight灯光组件集成到导航栏NavItem后,页面FPS从120骤降至30,核心性能瓶颈集中在模型重复渲染、灯光数量过载、不必要的渲染开销三个方面,以下是针对性优化方案:


一、模型资源与实例化优化

1. 用InstancedMesh复用多实例模型

当前id=3、4的NavItem中重复渲染多个Circle组件,每个组件都是独立Mesh,会产生大量Draw Call。改用InstancedMesh可将多个相同模型合并为一次渲染,大幅降低GPU负载:

修改Circle组件为支持实例化的版本:

import { useGLTF } from '@react-three/drei'
import React, { FC, useRef, useEffect } from 'react'
import * as THREE from 'three'
import { GLTF } from 'three-stdlib'

type GLTFResult = GLTF & {
    nodes: {
        Sphere002: THREE.Mesh
    }
    materials: {
        ['Material.004']: THREE.MeshStandardMaterial
    }
}

// 全局缓存几何体和材质,避免重复加载实例
const { nodes, materials } = useGLTF('/models/circle/circle.glb') as GLTFResult
const geometry = nodes.Sphere002.geometry
const material = materials['Material.004']

// 支持多实例渲染的Circle组件
const CircleInstance: FC<{ instances: Array<{ position: THREE.Vector3, rotation: THREE.Euler, scale: THREE.Vector3 }> }> = ({ instances }) => {
    const meshRef = useRef<THREE.InstancedMesh>(null)

    // 初始化实例矩阵
    useEffect(() => {
        if (!meshRef.current) return
        const mesh = meshRef.current
        mesh.count = instances.length
        instances.forEach((inst, index) => {
            const matrix = new THREE.Matrix4()
            matrix.compose(inst.position, inst.rotation, inst.scale)
            mesh.setMatrixAt(index, matrix)
        })
        mesh.instanceMatrix.needsUpdate = true
    }, [instances])

    return (
        <instancedMesh
            ref={meshRef}
            geometry={geometry}
            material={material}
            count={0}
            frustumCulling // 开启视锥体剔除
        />
    )
}

useGLTF.preload('/models/circle/circle.glb')
export default CircleInstance

在NavItem中替换使用:

// id=3的模型部分替换为
<CircleInstance
    instances={[
        { position: new THREE.Vector3(2.81, -3.92, 0.0), rotation: new THREE.Euler(0.0, 0, 0.0), scale: new THREE.Vector3(6.7, 6.7, 6.7) },
        { position: new THREE.Vector3(4.94, -4.86, 0.0), rotation: new THREE.Euler(0.0, 6.13, 0.0), scale: new THREE.Vector3(8.88, 8.88, 8.88) }
    ]}
/>

2. 进一步压缩与简化模型

  • 用Blender对模型做减面处理:保留视觉效果的前提下,用Decimate修改器降低多边形数量(比如减面50%)。
  • 使用Draco压缩:将模型转为带Draco压缩的glb格式,可将体积压缩至1MB以内,同时减少GPU加载压力。

二、灯光系统优化

1. 合并冗余灯光,减少数量

当前CirclesLight包含13个灯光,且NavItem中多次重复渲染该组件,灯光数量翻倍。合并同类型、同颜色的灯光,降低光照计算开销:

修改CirclesLight组件:

import { FC } from 'react'

const CirclesLight: FC = () => {
    return (
        <>
            {/* 合并4个橙色平行光,调整总强度保持视觉一致 */}
            <directionalLight
                intensity={160}
                position={[0, 1.5, 0]}
                color={'#FF5406'}
            />
            {/* 保留蓝色平行光 */}
            <directionalLight
                intensity={40}
                position={[1.568, 2.731, -4.679]}
                color='#2300ff'
            />
            {/* 合并4个蓝色点光 */}
            <pointLight
                intensity={160}
                decay={2}
                color='#2300ff'
                position={[0, 1, -1]}
            />
            {/* 合并5个浅白色点光 */}
            <pointLight
                intensity={200}
                decay={2}
                color='#fbffeb'
                position={[-0.5, 1.5, -1]}
            />
        </>
    )
}

export default CirclesLight

2. 仅在激活状态下渲染灯光

修改NavItem逻辑,仅当前激活的NavItem才渲染灯光:

// id=3的灯光部分修改为
{activeId === id && <CirclesLight />}

三、渲染可见性与生命周期优化

1. 非激活状态下停止渲染模型

当前非激活的NavItem中,模型仅位置偏移但仍在后台渲染,添加条件渲染逻辑:

// NavItem中模型区块的条件判断修改为
{(activeId === id) ? (
    <Suspense fallback={null}>
        {/* 模型和灯光 */}
    </Suspense>
) : null}

2. 缓存Three.js对象,避免重复创建

每次render时创建新的Euler和Vector3会导致react-three-fiber频繁更新组件,用useMemo缓存:

import { useMemo } from 'react'

// 在NavItem组件内添加
const id3Instances = useMemo(() => [
    { position: new THREE.Vector3(2.81, -3.92, 0.0), rotation: new THREE.Euler(0.0, 0, 0.0), scale: new THREE.Vector3(6.7, 6.7, 6.7) },
    { position: new THREE.Vector3(4.94, -4.86, 0.0), rotation: new THREE.Euler(0.0, 6.13, 0.0), scale: new THREE.Vector3(8.88, 8.88, 8.88) }
], [])

四、其他优化点

  • 替换材质类型:如果模型不需要PBR光照效果,改用MeshLambertMaterial或MeshBasicMaterial替代MeshStandardMaterial,减少光照计算开销。
  • 使用Simplify组件自动简化模型:
    import { Simplify } from '@react-three/drei'
    
    <Simplify amount={0.5}>
        <CircleInstance instances={id3Instances} />
    </Simplify>
    

内容的提问来源于stack exchange,提问作者Nik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 23:39:51