3.2 纹理底料:加载、色彩空间与米普链 本节摘要:贴图从硬盘到显存要过两道关卡:色彩空间决定颜色对不对,米普链决定远处糊不糊、显存省不省。本节承接材质选型,把纹理的加载、配色、采样配置一次讲透,并给出"材质发黑发灰"与"远处闪烁"两类事故的标准排障流程。 一张贴图的旅程 你在绘图软件里看到的木纹,与显卡最终采到的木纹,中间隔着一次运输与两道安检。运输是异步加载:贴图文件从网络或本地读入内存,解码成像素数组,再上传到显卡显存——全程不阻塞主线程,这就是"纹理没到位就渲染"会成为事故的原因。第一道安检是色彩空间:颜色类贴图(木纹、漆色)按 sRGB 解码,数据类贴图(法线、粗糙度)按线性处理,标错方向,亮度曲线整体错位。
本节摘要:贴图从硬盘到显存要过两道关卡:色彩空间决定颜色对不对,米普链决定远处糊不糊、显存省不省。本节承接材质选型,把纹理的加载、配色、采样配置一次讲透,并给出"材质发黑发灰"与"远处闪烁"两类事故的标准排障流程。
你在绘图软件里看到的木纹,与显卡最终采到的木纹,中间隔着一次运输与两道安检。运输是异步加载:贴图文件从网络或本地读入内存,解码成像素数组,再上传到显卡显存——全程不阻塞主线程,这就是"纹理没到位就渲染"会成为事故的原因。第一道安检是色彩空间:颜色类贴图(木纹、漆色)按 sRGB 解码,数据类贴图(法线、粗糙度)按线性处理,标错方向,亮度曲线整体错位。第二道安检是米普链:显卡为贴图预生成一串逐级缩小的副本,远处用小的副本采样,既防闪烁又省带宽。
两道安检都发生在 Texture 对象的属性里,各一个布尔或枚举值——但正是这两个不起眼的赋值,撑起了贴图工序九成的画质下限。

背景:纸箱升级为木箱,拿到三张图:木纹颜色图、法线凸凹图、粗糙度磨损图。要求近看有木纹细节、远看不闪、颜色不发灰。
操作:加载三张贴图,按"颜色图标 sRGB、数据图留线性"的口诀分配色彩空间,其余采样配置走标准件。
const loader = new THREE.TextureLoader(); // 颜色贴图:人眼看的颜色,标 sRGB const woodColor = loader.load('wood_diffuse.jpg'); woodColor.colorSpace = THREE.SRGBColorSpace; // 法线与粗糙度是数据:喂给光照模型的数字,保持默认线性,千万别标 sRGB const woodNormal = loader.load('wood_normal.jpg'); const woodRough = loader.load('wood_rough.jpg'); // 三张图共用一组包裹与米普配置 [woodColor, woodNormal, woodRough].forEach((t) => { t.wrapS = t.wrapT = THREE.RepeatWrapping; // 平铺包裹,接缝处循环 t.repeat.set(2, 2); // 纹理密度:2 乘 2 平铺 t.anisotropy = stage.renderer.capabilities.getMaxAnisotropy(); // 斜视角不发糊 }); const woodMat = new THREE.MeshStandardMaterial({ map: woodColor, // 基色 normalMap: woodNormal, // 凸凹细节,光照层面"骗"出立体感 roughnessMap: woodRough, // 逐像素粗糙度:磨亮处反光、磨毛处哑光 roughness: 1.0 // 与粗糙度贴图相乘,作整体系数保留 });
结果:木箱近看有清晰的木纹与凸凹起伏,转到侧面斜视角纹理依旧锐利,拉远后地面与箱体纹路平稳不闪。若故意把 woodNormal 的 colorSpace 也设成 SRGBColorSpace,凸凹会变得油腻发腻、阴影方向怪异——这是数据图被错误解码的直接症状。
解读:为什么数据图绝不能标 sRGB?sRGB 编码是为"人眼看的颜色"设计的非线性曲线,解码时会把数值"提亮";颜色贴图走这条曲线是对的,但法线贴图的每个通道是方向向量的分量(-1 到 1 映射到 0 到 255),被提亮一次,向量就全部偏斜,光照计算跟着错。记忆方式:map 槽位(人眼消费)标 sRGB,其余槽位(光照模型消费)保持线性。anisotropy 那行也值得单独记:地面、桌面这类大平面被斜视角掠过时,各向异性过滤决定纹理是"糊成一片"还是"根根分明",取设备上限值一行搞定,几乎无代价。
变式:贴图未到位时的兜底——先用一张纯色材质渲染,加载完成的回调里再替换成纹理版本,用户看到的是"素坯渐显"而不是"黑块等待";进一步用 LoadingManager 汇总全部资源进度,做统一的加载条。这两个手法在第 5 章加载器一节会合并成完整的"进场仪式"。
Standard 材质的贴图槽位远不止颜色一张,按"管什么"分类记:map 管基色(人眼消费,标 sRGB);normalMap 管凸凹细节(数据);roughnessMap 管逐像素反光强度(数据);metalnessMap 管逐像素金属度(数据,常与粗糙度图共用一张通道图);aoMap 管环境光遮蔽,把角落压暗、立体感立刻扎实(数据,需要给几何体配第二套 UV);emissiveMap 管自发光图案(颜色消费,标 sRGB)。理解槽位的消费方,色彩空间规则就不再是死记:人眼看的图是 sRGB,光照模型吃的图留线性。槽位越喂越多,显存与采样开销同步上涨——先喂主线槽位(基色、法线、粗糙度),效果不达标再考虑补充,是上漆备料的加料顺序。
备料工序还要为"料没到"和"料太贵"各备一条预案。料没到:纹理加载失败时加载器会走错误回调,此时材质的 map 槽位是空——画面上呈现纯色底,这正是"素坯兜底"的自然形态,只要在回调里记录失败清单并允许用户重试即可;切忌用同步的方式假设纹理已在显存,九成"贴图时有时无"的灵异现象都是竞态。料太贵:一张 4096 见方的原图解压后占显存 64 MB 级别,四张就是一台手机的显存红线;导出环节把贴图压到实际显示需要的尺寸(近景 2048、远景 512 足够),配合 KTX2 压缩格式,显存账立刻可控。体积纪律一句话:贴图是显存里的住客,按"实际像素需求"供房,不按"原图多大"供房。
料已备好,还差"贴到哪"。下一节进 UV 映射与贴面工艺:展开地图怎么读、包裹方式怎么选、三张贴图怎么打出组合拳。