新闻详情

新闻详情

首页 / 资讯中心 / 详情

three.js LUT3dlLoader 指南:加载 .3dl 三维查找表(LUT)实现影视级调色

发布时间:2026/9/8 21:38:17来源:尧图网络
three.js LUT3dlLoader 指南:加载 .3dl 三维查找表(LUT)实现影视级调色
three.js LUT3dlLoader 指南加载 .3dl 三维查找表LUT实现影视级调色【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.jsthree.js 官方提供了LUT3dlLoader这个附加组件addon用于加载 Autodesk Lustre / 众多调色软件通用的.3dl三维查找表3D LUT格式并将 LUT 数据解析为可用于后期处理着色的Data3DTexture三维纹理。本文以 LUT3dlLoader.html.md 文档为骨架结合 examples/jsm/loaders/LUT3dlLoader.js 源码、仓库自带的真实.3dl样本文件Presetpro-Cinematic.3dl以及完整可运行的调色示例webgl_postprocessing_3dlut.html全面讲解 3DL 文件格式、加载器完整 API、底层解析算法并给出接入EffectComposer与LUTPass的实战方案。读完本文你将能独立把任意.3dlLUT 文件接入 three.js 渲染管线完成颜色分级、胶片风格模拟等实时后期调色。一、什么是 3DL 格式LUT3dlLoader 解决什么问题**3D LUT三维查找表**是影视调色领域最常见的色彩映射工具。它以三维网格的方式把输入 RGB 色彩空间映射到输出 RGB 色彩空间假设网格分辨率为 N³则表中存储 N×N×N 个(r, g, b)三元组每个像素的 RGB 值在网格中插值采样即可得到目标颜色。许多达芬奇、Lustre、Nuke、Photoshop 导出插件都支持.3dl格式例如仓库自带样本的头注释表明它由Adobe Photoshop Export Color Lookup Plugin导出。在 three.js 中把 LUT 应用到画面 本质上是采样一张sampler3D三维纹理因此需要一个专门的加载器把.3dl的纯文本数据解析成 GPU 可直接采样的Data3DTexture。这正是LUT3dlLoader的职责读取.3dl文本文件load/loadAsync解析其网格尺寸与颜色数据parse输出{ size, texture3D }——size为网格边长texture3D为可直接交给后期管线使用的三维数据纹理支持以UnsignedByteType默认或FloatType输出纹理数据setType。需要特别说明的是原文档与源码头注释中给出的格式参考均指向外部官网Autodesk Lustre 3D LUTs 说明与 Foundry 社区格式规格此处仅作背景说明不展开外部链接本仓库内即可找到真实的.3dl文件供研究与验证。二、3DL 文件内部结构要理解加载器先理解文件。以仓库真实样本 examples/luts/Presetpro-Cinematic.3dl 的开头为例#Created by: Adobe Photoshop Export Color Lookup Plugin #Copyright: (C) Copyright 2018 https://www.presetpro.com and Tim Martin #Description: Presetpro - Cinematic 0 33 66 99 132 165 ... 957 990 1023 418 385 434 418 385 435 418 369 484 ....3dl为纯文本格式其核心由两部分组成网格信息行一行只包含数字与空格的坐标轴刻度序列例如样本中的0 33 66 ... 1023。它描述 LUT 网格在各通道上取值的位置分布。行内刻度的个数即为网格边长size相邻刻度的差值称为gridStep。样本共有 32 个刻度0到1023步长33覆盖 10-bit 数值域因此会生成32×32×32的三维纹理。颜色数据行此后按序每行一个r g b三元组数字支持小数与科学计数法行的排列顺序按先 B、再 G、最后 R的通道最内层优先方式组织行总数应为size³。样本文件共 32772 行其中 3 行#注释 1 行网格信息正好对应 32768 32³行颜色数据。#开头的行是注释。理解数据按 B 通道最优先排列这一点是读懂下文parse()中坐标重映射代码的关键。三、安装与导入LUT3dlLoader是 three.js 的addon附加组件不包含在核心three.module.js包体内必须显式导入。官方推荐通过three/addons/映射路径引用import { LUT3dlLoader } from three/addons/loaders/LUT3dlLoader.js;在仓库本地示例如 webgl_postprocessing_3dlut.html中是通过 importmap 将three/addons/映射到./jsm/目录后使用的import { LUT3dlLoader } from three/addons/loaders/LUT3dlLoader.js;若使用打包工具则直接以node_modules中的对应相对路径或别名导入同一模块即可。该模块同样被导出在 examples/jsm/Addons.js 的聚合入口中。四、API 详解4.1 构造函数new LUT3dlLoader( manager )const loader new LUT3dlLoader(); // 或 new LUT3dlLoader( manager )manager可选LoadingManager加载管理器用于跟踪该加载器的全部加载过程。由源码 LUT3dlLoader.js 可见构造器内部调用super( manager )并初始化默认属性.type UnsignedByteType。继承自Loader因此同样拥有Loader提供的.path、.setPath()、.setRequestHeader()等能力。4.2 属性.type : UnsignedByteType | FloatType纹理数据类型决定解析出的三维纹理内部数据为 8-bit 无符号字节Uint8Array还是 32-bit 浮点Float32Array。默认值为UnsignedByteType对应 8-bit 精度内存占用更小、兼容性最好若希望保留更高的色彩精度例如配合浮点渲染目标或 HDR 管线可设为FloatType。4.3 方法.load( url, onLoad, onProgress, onError )从 URL 开始加载.3dl文件加载完成后把解析结果传给onLoad回调。参数类型说明urlstring要加载的文件路径/URL也支持 data URI。onLoadfunction({ size, texture3D })加载并解析完成时执行参数为parse()的返回对象。onProgressonProgressCallback加载进行中执行。onErroronErrorCallback加载/解析出错时执行。该方法覆写自Loader#load。由源码 LUT3dlLoader.js 可见其实现内部创建一个FileLoader继承当前加载器的manager与path并以text响应类型取回文本随后在try/catch中调用this.parse( text )——因此解析阶段抛出的错误如缺少网格信息、网格不一致也会经由onError回调或console.error报告并调用manager.itemError( url )。文档推荐的异步用法const loader new LUT3dlLoader(); const map loader.loadAsync( luts/Presetpro-Cinematic.3dl );loadAsync是Loader基类基于load封装出的 Promise 版本上面的map即{ size, texture3D }。4.4 方法.parse( input ) : Object解析给定的原始 3DL 文本字符串返回包含生成的三维数据纹理的对象。覆写自Loader#parse。inputstring3DL 数据的原始文本。返回{ size : number, texture3D : Data3DTexture }。该方法是整个加载器的大脑下一节深入剖析其实现细节。4.5 方法.setType( type ) : LUT3dlLoaderloader.setType( THREE.FloatType ); // 链式返回 this设置纹理数据类型并返回加载器自身引用便于链式调用。此方法需在真正开始load/loadAsync/parse之前设置才有效。五、源码级剖析parse() 如何把文本变成三维纹理解析的核心实现位于 LUT3dlLoader.js整个过程可分为六个关键步骤理解它们有助于你调试自定义.3dl文件。5.1 网格信息检测与尺寸推导const regExpGridInfo /^[\d ]$/m; let result regExpGridInfo.exec( input ); if ( result null ) throw new Error( THREE.LUT3dlLoader: Missing grid information ); const gridLines result[ 0 ].trim().split( /\s/g ).map( Number ); const gridStep gridLines[ 1 ] - gridLines[ 0 ]; const size gridLines.length;/^[\d ]$/m多行模式下会匹配整行只含数字与空格的首行内容通常即网格刻度行找不到时抛出Missing grid information。随后把该行按空白切分为数值数组size取元素个数例如 32gridStep取首两个刻度差。紧接着做网格一致性校验for ( let i 1; i gridLines.length; i ) { if ( gridStep ! ( gridLines[ i ] - gridLines[ i - 1 ] ) ) { throw new Error( THREE.LUT3dlLoader: Inconsistent grid size ); } }即刻度必须严格等差递增一旦出现间距不一致即抛出Inconsistent grid size防止数据错乱。5.2 逐行读取颜色数据并做通道重映射const regExpDataPoints /^([\d.e-]) ([\d.e-]) ([\d.e-]) *$/gm; const dataFloat new Float32Array( size ** 3 * 4 );数据行正则要求每行恰好三个以 1 个以上空格分隔的数值支持e-科学计数法。解析器先分配一块size³ × 4的Float32ArrayRGBA 交错布局再按文件行序循环匹配每行解析出r、g、b。文件内数据按B → G → R 通道顺序逐层排列B 变化最快而 three.js 需要的是标准 RGBA 顺序的 3D 纹理体素索引因此要做坐标换算const bLayer index % size; const gLayer Math.floor( index / size ) % size; const rLayer Math.floor( index / ( sizeSq ) ) % size; // b grows first, then g, then r. const d4 ( bLayer * sizeSq gLayer * size rLayer ) * 4; dataFloat[ d4 0 ] r; dataFloat[ d4 1 ] g; dataFloat[ d4 2 ] b;源码中的注释b grows first, then g, then r正是对上述行序的说明原始第index行数据的(r,g,b)在最终 RGBA 纹理中位于体素坐标(rLayer, gLayer, bLayer)。5.3 根据最大数值自动推断位深并归一化const bits Math.ceil( Math.log2( maxValue ) ); const maxBitValue Math.pow( 2, bits );解析过程中会记录所有通道的最大值maxValue。不同软件导出的.3dl数值域不同8-bit 为 0~255、10-bit 为 0~1023、16-bit 为 0~65535 等。加载器通过Math.log2(maxValue)向上取整自动推断文件位深并据此把全部数值缩放到[0, 1]区间const data this.type UnsignedByteType ? new Uint8Array( dataFloat.length ) : dataFloat; const scale this.type UnsignedByteType ? 255 : 1; for ( let i 0; i data.length; i 4 ) { data[ i ] dataFloat[ i ] / maxBitValue * scale; data[ i1 ] dataFloat[ i1 ] / maxBitValue * scale; data[ i2 ] dataFloat[ i2 ] / maxBitValue * scale; data[ i3 ] scale; // Alpha 恒为不透明 }可见type的选择既决定目标数组类型Uint8Arrayvs 复用Float32Array也决定缩放比例255 vs 1Alpha 通道被恒置为最大不透明值。这是文件格式自带位深、加载器自动适配的核心设计也是它能直接处理 10-bit 样本文件的原因。5.4 构造 Data3DTexture 并完成采样配置const texture3D new Data3DTexture(); texture3D.image.data data; texture3D.image.width size; texture3D.image.height size; texture3D.image.depth size; texture3D.format RGBAFormat; texture3D.type this.type; texture3D.magFilter LinearFilter; texture3D.minFilter LinearFilter; texture3D.wrapS wrapT wrapR ClampToEdgeWrapping; texture3D.generateMipmaps false; texture3D.needsUpdate true;生成的Data3DTexture为RGBA 格式的三维纹理长宽深均为size并且上下采样均用LinearFilter线性插值这是 LUT 采样获得平滑过渡的必要条件三个方向 wrap 均为ClampToEdgeWrapping防止采样越界产生环绕伪影关闭generateMipmapsLUT 不需要 mipmap最后needsUpdate true通知渲染器上传。最终返回{ size, texture3D }供调用方通常是后期调色 pass使用。六、实战把 .3dl LUT 接入 EffectComposer 进行实时调色6.1 加载阶段既可使用文档示例的loadAsync返回 Promiseimport { LUT3dlLoader } from three/addons/loaders/LUT3dlLoader.js; const loader new LUT3dlLoader(); // 可选使用更高精度的浮点纹理 loader.setType( THREE.FloatType ); const { size, texture3D } await loader.loadAsync( luts/Presetpro-Cinematic.3dl );也可使用回调式load正如官方演示 webgl_postprocessing_3dlut.html 中的写法new LUT3dlLoader() .load( luts/Presetpro-Cinematic.3dl, function ( result ) { lutMap[ name ] result; // result { size, texture3D } } );该示例把.CUBE、.3dl与 Hald 图像 LUT 三类加载器统一在同一个lutMap中切换加载完成后通过 GUI 实时切换其数据出口完全一致——都是{ texture3D }这正是 three.js LUT 生态统一接口的体现。6.2 使用 LUTPass 应用到渲染结果调色阶段使用 examples/jsm/postprocessing/LUTPass.js一个基于ShaderPass的后处理 pass。其片元着色器对画面颜色val.rgb换算采样坐标后在 3D 纹理中取色uniform sampler3D lut; uniform float lutSize; vec3 uvw vec3( halfPixelWidth ) val.rgb * ( 1.0 - pixelWidth ); lutVal vec4( texture( lut, uvw ).rgb, val.a ); gl_FragColor vec4( mix( val, lutVal, intensity ) );将解析得到的texture3D交给 pass 并控制强度即可import { EffectComposer } from three/addons/postprocessing/EffectComposer.js; import { RenderPass } from three/addons/postprocessing/RenderPass.js; import { LUTPass } from three/addons/postprocessing/LUTPass.js; const lutPass new LUTPass(); composer new EffectComposer( renderer ); composer.addPass( new RenderPass( scene, camera ) ); composer.addPass( lutPass ); composer.addPass( new OutputPass() ); // 每帧或切换 LUT 时 lutPass.lut parsedResult.texture3D; // LUTPass 内部会同步 lutSize size lutPass.intensity 1.0; // 混合强度 0~1注意两点LUTPass是后处理管线中的渲染链环节通常整个场景应经由EffectComposer渲染顺序为RenderPass → LUTPass → OutputPass示例中OutputPass承担色调映射与色彩空间转换。完整的对照实现可直接参考 examples/webgl_postprocessing_3dlut.html仓库还提供同一主题的 WebGPU 版本 examples/webgpu_postprocessing_3dlut.html。lut需要的是Data3DTexture因此一定要把parse/load返回对象中的.texture3D传给 pass而不是把整个result传过去。示例的运行效果可查看官方演示截图 webgl_postprocessing_3dlut.jpg画面通过不同 LUT 切换出各异的电影风格色调。七、使用建议与注意事项文件地址与 data URI.load()的url既可以是普通相对路径配合.setPath()也支持 data URI便于把 LUT 内联进页面。位深自适应加载器根据数据最大数值自动推断位深8/10/12/16-bit 的.3dl均可正确归一化若发现偏色优先检查源文件数值域是否混用。精度选择默认UnsignedByteType在多数 WebGL 场景已足够做 HDR 调色、浮点管线或追求更高精度时使用setType( THREE.FloatType )代价是四倍显存占用。网格一致性自定义.3dl必须保证网格刻度严格等差否则解析会抛出Inconsistent grid size数据行总数必须是size³行内必须恰好三个数值否则会静默截断或产生错误映射。错误处理parse抛出的异常Missing grid information等在load内部会被捕获并转发到onError回调务必为生产环境注册onError。与其他 LUT 加载器协同若需要同时支持.cube或 Hald PNG 格式可参考官方示例中LUTCubeLoader、LUTImageLoader与LUT3dlLoader并存的做法——它们最终都提供.texture3D使LUTPass层无需任何改动即可切换格式。八、仓库内延伸阅读关联 API 文档docs/pages/LUT3dlLoader.html.html.md的渲染版页面加载器源码examples/jsm/loaders/LUT3dlLoader.js调色 pass 实现examples/jsm/postprocessing/LUTPass.js完整 WebGL 演示含 GUI 实时切换各格式 LUTexamples/webgl_postprocessing_3dlut.htmlWebGPU 版本演示examples/webgpu_postprocessing_3dlut.html仓库自带真实.3dl样本examples/luts/Presetpro-Cinematic.3dladdon 聚合导出examples/jsm/Addons.js【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

btop GPU监控完整指南:3 步在终端看全 NVIDIA/AMD/Intel 显卡利用率 2026/9/8 22:17:27

btop GPU监控完整指南:3 步在终端看全 NVIDIA/AMD/Intel 显卡利用率

btop GPU监控完整指南:3 步在终端看全 NVIDIA/AMD/Intel 显卡利用率 【免费下载链接】btop A monitor of resources 项目地址: https://gitcode.com/GitHub_Trending/bt/btop 游戏画面一卡,先别急着猜——盯着 GPU 利用率、显存占用、温度 这三个…

阅读更多 →
three.js 中 SphericalHarmonics3 解析:用 9 个系数编码光照的球谐函数实现 2026/9/8 22:17:27

three.js 中 SphericalHarmonics3 解析:用 9 个系数编码光照的球谐函数实现

three.js 中 SphericalHarmonics3 解析:用 9 个系数编码光照的球谐函数实现 【免费下载链接】three.js JavaScript 3D Library. 项目地址: https://gitcode.com/GitHub_Trending/th/three.js SphericalHarmonics3 是 three.js 中用于表示三阶(L2&…

阅读更多 →
OpenCode 深度指南:终端 AI 编程代理的安装、配置与实战避坑 2026/9/8 22:17:27

OpenCode 深度指南:终端 AI 编程代理的安装、配置与实战避坑

用过 Claude Code 之后,我一度觉得终端里跑 AI 编程代理这事已经被玩明白了。直到我换到 OpenCode,才意识到之前的方案还是太“重”了:要么锁定某一家模型,要么只能在特定 IDE 里用,要么想接自己的私有模型得折腾半天。…

阅读更多 →
Cursor+Codex重构微信小游戏开发工作流 2026/9/8 22:17:27

Cursor+Codex重构微信小游戏开发工作流

1. 这不是“AI写代码”,而是用工具链重构开发节奏的真实记录 “一个人,4个岗位,20天:我用CursorCodex上线了一款微信小游戏”——这句话在技术圈刷屏时,我第一反应是:又一个标题党?直到点开评论…

阅读更多 →
2026微商城平台推荐:真正难的不是开店,是别把客户卖丢 2026/9/8 22:17:27

2026微商城平台推荐:真正难的不是开店,是别把客户卖丢

今天给大家带来2026微商城平台推荐:真正难的不是开店,是别把客户卖丢。腾讯公开信息显示,2025年微信小程序生态已覆盖100个国家和地区、108个行业,跨境交易金额同比增长超过70%;微信小程序目前拥有超过11亿月活跃用户。…

阅读更多 →
基于STM32F103的摄像头循迹小车:从图像处理到PID控制全解析 2026/9/8 22:14:27

基于STM32F103的摄像头循迹小车:从图像处理到PID控制全解析

简介:基于STM32F103的摄像头循迹智能小车系统,面向嵌入式开发学习者和智能车竞赛爱好者,融合OV7670图像采集、二值化道路识别和超声波避障等关键技术,可广泛应用于毕业设计、课程设计与机器人入门实践。压缩包共166个文件&#xf…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞