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

在React+@react-three/fiber中实现仅针对太阳的选择性Bloom效果,不影响场景背景及其他物体

在React+@react-three/fiber中实现仅针对太阳的选择性Bloom效果,不影响场景背景及其他物体

我之前也碰到过几乎一模一样的问题!折腾了好几天才搞明白核心问题出在哪,给你分享下我是怎么解决的:

核心思路

选择性Bloom的关键是把需要发光的物体(太阳)放到单独的图层,让Bloom效果只处理这个图层的内容,再把发光效果叠加到完整的主场景上。你之前的尝试方向是对的,但图层设置和后处理的结构没搭配好,导致要么全场景发光要么其他物体消失。

分步解决方案

1. 统一管理图层常量

先定义一个专用的Bloom图层,避免硬编码数字出错:

import * as THREE from 'three';

// 创建一个仅用于Bloom的图层
const BLOOM_LAYER = new THREE.Layers();
BLOOM_LAYER.set(1); // 用第1层,默认物体都在第0层

2. 修改太阳组件:标记为Bloom目标

把太阳放到专用图层,并用Selection组件标记它是后处理的目标物体,不要用Select直接包裹(那是给后处理效果用的):

function Sun() {
  const sunTexture = useTexture("/textures/2k_sun.jpg");
  sunTexture.colorSpace = THREE.SRGBColorSpace;
  const sunRef = useRef<THREE.Mesh>(null);

  useFrame((_, delta) => {
    sunRef.current?.rotation.y += 0.001;
  });

  return (
    <Selection> {/* 标记这个物体是后处理要选中的目标 */}
      <mesh ref={sunRef} scale={7} layers={BLOOM_LAYER}>
        <sphereGeometry args={[1, 32, 32]} />
        {/* 关闭色调映射,避免太阳的亮部被压暗 */}
        <meshBasicMaterial map={sunTexture} toneMapped={false} />
      </mesh>
    </Selection>
  );
}

3. 正确配置后处理流程

这是最关键的一步!要让后处理先渲染完整的主场景,再单独渲染太阳并应用Bloom,最后把发光效果叠加到主场景上:

import { EffectComposer, RenderPass, Select, BloomEffect } from '@react-three/postprocessing';
import { useThree } from '@react-three/fiber';

export default function SolarSystem() {
  const { gl, scene, camera } = useThree();

  return (
    <>
      {/* 先渲染所有场景元素:背景、太阳、行星 */}
      <Background />
      <Sun />
      {/* 这里放你的行星组件,比如<Planet name="Mercury" ... /> */}

      {/* 后处理核心流程 */}
      <EffectComposer gl={gl}>
        {/* 第一步:渲染完整的主场景(所有图层,包括背景、行星、太阳) */}
        <RenderPass scene={scene} camera={camera} />
        
        {/* 第二步:只渲染选中的太阳(BLOOM_LAYER),应用Bloom后叠加到主场景 */}
        <Select enabled>
          <BloomEffect 
            intensity={2.5} // 发光强度,按需调整
            threshold={0.2} // 过滤暗部,避免微弱反光也被发光
            blurPasses={4} // 模糊程度,值越高越柔和
          />
        </Select>
      </EffectComposer>
    </>
  );
}

4. 修复背景ShaderMaterial的渲染问题

确保背景不在Bloom图层上,并且设置正确的渲染属性,避免被后处理干扰:

function Background() {
  const meshRef = useRef<THREE.Mesh>(null);
  const { camera } = useThree();

  const material = useMemo(
    () => new THREE.ShaderMaterial({
      vertexShader,
      fragmentShader,
      uniforms: {
        iTime: { value: 0 },
        iResolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },
      },
      side: THREE.BackSide,
      depthWrite: false, // 不写入深度缓冲,避免遮挡其他物体
      toneMapped: false, // 星空背景不需要色调映射
    }),
    []
  );

  useFrame((state) => {
    material.uniforms.iTime.value = state.clock.getElapsedTime();
    meshRef.current?.position.copy(camera.position);
  });

  // 显式设置背景在默认图层,确保不会被Bloom处理
  return (
    <mesh ref={meshRef} renderOrder={-1} layers={new THREE.Layers().set(0)}>
      <sphereGeometry args={[1000, 32, 32]} />
      <primitive object={material} />
    </mesh>
  );
}

额外注意事项

  • 行星和其他物体默认在第0层,不需要额外设置,自然不会被Bloom处理
  • 调整BloomEffect的参数可以优化发光效果:threshold越高,只有太阳最亮的部分会发光;intensity控制发光的强弱
  • 太阳用meshBasicMaterial是对的,因为它是自发光体,不需要受场景光照影响,关掉toneMapped能保证它的亮度不会被引擎自动压暗

我用这套方法解决了和你完全一样的问题,现在只有太阳有柔和的发光效果,背景和行星都完全不受影响,性能也保持得很好。你可以根据自己的视觉需求调整Bloom的参数,直到达到满意的效果!

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 14:38:09