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

R3F中用GSAP修改GLTF模型材质颜色,归一化RGB后颜色异常

问题原因与解决方案

核心问题

你遇到的颜色偏差,本质是颜色空间的转换问题:

  • Three.js的material.color.setHex()方法会自动将输入的十六进制颜色(属于sRGB空间)转换为线性空间的颜色值,这是Three.js渲染管线要求的标准格式。
  • 而你手动将8位RGB值除以255得到的是sRGB空间的归一化值,直接赋值给color.r/g/b时,相当于把sRGB值当作线性值使用,必然导致颜色偏亮(因为线性空间的暗部值比sRGB的同比例值小很多)。

比如0x292929:

  • sRGB归一化值:41/255 ≈ 0.16
  • 转换为线性空间后的值:≈ 0.025
    你直接用0.16赋值,自然会显示成浅灰色。

解决方案

方案1:借助Three.js的Color对象自动处理转换

这是最省心的方式,直接用THREE.Color解析十六进制颜色,它会自动完成sRGB到线性空间的转换,和setHex()的逻辑完全一致:

import { Color } from 'three';

// ...

if (modelModifier.color !== undefined) {
  const targetColor = new Color(modelModifier.color);
  gsap.to(material.color, {
    r: targetColor.r,
    g: targetColor.g,
    b: targetColor.b,
    duration: 1,
    immediateRender: false
  })
} else {
  material.color.setHex(0x292929)
}

方案2:手动实现sRGB到线性空间的转换

如果不想额外创建Color实例,可以用标准的转换公式手动计算:

function srgbToLinear(srgbNorm) {
  return srgbNorm <= 0.04045 
    ? srgbNorm / 12.92 
    : Math.pow((srgbNorm + 0.055) / 1.055, 2.2);
}

// ...

if (modelModifier.color !== undefined) {
  gsap.to(material.color, {
    r: srgbToLinear(((modelModifier.color >> 16) & 255) / 255),
    g: srgbToLinear(((modelModifier.color >> 8) & 255) / 255),
    b: srgbToLinear((modelModifier.color & 255) / 255),
    duration: 1,
    immediateRender: false
  })
} else {
  material.color.setHex(0x292929)
}

关于GSAP直接动画十六进制颜色

其实GSAP可以直接动画material.color的hex属性,不需要拆分RGB,写法更简洁:

if (modelModifier.color !== undefined) {
  gsap.to(material.color, {
    hex: modelModifier.color,
    duration: 1,
    immediateRender: false
  })
} else {
  material.color.setHex(0x292929)
}

这个方式本质上还是借助Three.js内部的颜色空间转换,效果和setHex()完全一致,不需要自己处理任何转换逻辑。

内容的提问来源于stack exchange,提问作者Alexis-Parisy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 12:53:15