概述
本文档将介绍Three.js中纹理材质的高级操作,包括纹理变换、过滤、加载不同格式纹理、色调映射、深度处理、混合模式、裁剪平面和模板渲染等重要概念。通过这些知识点,您将能够创建更加专业和富有表现力的3D场景。
第一部分:纹理变换 - 位移、旋转、缩放、重复
1. 纹理重复(Repeat)
纹理重复允许将纹理在UV坐标空间中重复铺设,可以创建无缝的图案效果。
// 设置纹理重复
texture.repeat.set(4, 4); // 水平和垂直方向各重复4次
// 设置水平重复
texture.wrapS = THREE.RepeatWrapping;
// 设置垂直重复
texture.wrapT = THREE.RepeatWrapping;
// 镜像重复
texture.wrapS = THREE.MirroredRepeatWrapping;
2. 纹理偏移(Offset)
纹理偏移允许移动纹理在模型表面上的起始位置。
// 设置纹理偏移
texture.offset.set(0.5, 0.5); // 水平和垂直方向偏移50%
3. 纹理旋转(Rotation)
纹理旋转允许围绕纹理中心点旋转纹理。
// 设置纹理旋转中心
texture.center.set(0.5, 0.5); // 中心点
texture.rotation = Math.PI / 4; // 旋转45度
第二部分:纹理纵向翻转与预乘Alpha
1. 纹理纵向翻转
某些纹理在加载时可能会出现上下颠倒的情况,可以通过flipY属性来修正。
// 翻转纹理Y轴
texture.flipY = false; // 默认为true,设为false可取消翻转
2. 预乘Alpha
预乘Alpha(Premultiply Alpha)处理纹理的透明通道,对透明效果的渲染质量有重要影响。
// 设置预乘Alpha
texture.premultiplyAlpha = true; // 或false
// 通过GUI控制预乘Alpha
gui
.add(texture, "premultiplyAlpha")
.name("premultiplyAlpha")
.onChange(() => {
texture.needsUpdate = true; // 需要更新纹理
});
第三部分:Mipmap技术
1. Mipmap概述
Mipmap是纹理的多个分辨率版本的集合,用于提高渲染质量和性能。当物体远离相机时,使用较低分辨率的纹理版本。
// 不同的过滤方式
// 直接取映射到的最近的像素
texture.magFilter = THREE.NearestFilter;
// 取映射到的最近的四个像素的平均值
texture.magFilter = THREE.LinearFilter;
// 最小化过滤器
texture.minFilter = THREE.LinearMipMapLinearFilter; // 推荐的高质量过滤器
texture.minFilter = THREE.LinearMipMapNearestFilter;
texture.minFilter = THREE.NearestMipMapLinearFilter;
texture.minFilter = THREE.NearestMipMapNearestFilter;
2. 生成Mipmap
// 控制是否生成Mipmap
texture.generateMipmaps = false; // 设为false可禁用Mipmap
第四部分:各项异性过滤解决倾斜模糊问题
1. 各项异性过滤(Anisotropic Filtering)
当纹理以倾斜角度显示时,普通过滤可能导致模糊,各项异性过滤可以改善这种情况。
// 获取硬件支持的最大各项异性级别
let maxAnisotropy = renderer.capabilities.getMaxAnisotropy();
console.log(maxAnisotropy);
// 设置各项异性级别
texture.anisotropy = 4; // 值越大质量越高,但性能开销也越大
第五部分:Three.js中使用KTX2、DDS、TGA纹理
1. KTX2格式
KTX2是一种现代纹理格式,支持多种压缩算法和高级功能。
import { KTX2Loader } from "three/examples/jsm/loaders/KTX2Loader.js";
// KTX2加载器
let ktx2Loader = new KTX2Loader()
.setTranscoderPath("basis/") // 设置解码器路径
.detectSupport(renderer); // 检测支持情况
let ktx2Texture = ktx2Loader.load(
"./texture/opt/ktx2/texture.ktx2",
(texture) => {
console.log("ktx2", texture);
texture.mapping = THREE.EquirectangularReflectionMapping;
texture.anisotropy = 16;
texture.needsUpdate = true;
scene.background = texture;
scene.environment = texture;
}
);
2. DDS格式
DDS是一种传统的压缩纹理格式,常用于游戏开发。
import { DDSLoader } from "three/examples/jsm/loaders/DDSLoader.js";
// DDS加载器
let ddsLoader = new DDSLoader();
let ddsTexture = ddsLoader.load(
"./texture/opt/env/texture.dds",
(texture) => {
console.log("dds", texture);
texture.mapping = THREE.EquirectangularReflectionMapping;
texture.flipY = true; // DDS纹理可能需要翻转
texture.needsUpdate = true;
scene.background = texture;
scene.environment = texture;
texture.magFilter = THREE.LinearFilter;
texture.minFilter = THREE.LinearMipMapLinearFilter;
texture.anisotropy = 16;
}
);
3. TGA格式
TGA是一种较老但仍广泛使用的纹理格式。
import { TGALoader } from "three/addons/loaders/TGALoader.js";
// TGA加载纹理
let tgaLoader = new TGALoader();
tgaLoader.load(
"./texture/opt/env/texture.tga",
(texture) => {
texture.mapping = THREE.EquirectangularReflectionMapping;
console.log("tga", texture);
scene.background = texture;
scene.environment = texture;
}
);
第六部分:背景色调映射
1. 色调映射概述
色调映射将高动态范围(HDR)的光照值转换为适合显示的低动态范围值。
// 设置色调映射
renderer.toneMapping = THREE.ACESFilmicToneMapping;
// 设置色调映射曝光度
renderer.toneMappingExposure = 1;
// 通过GUI控制色调映射
gui.add(renderer, "toneMapping", {
// 无色调映射
No: THREE.NoToneMapping,
// 线性色调映射
Linear: THREE.LinearToneMapping,
// Reinhard色调映射。这是一种更复杂的色调映射方式,可以更好地处理高亮度的区域。
Reinhard: THREE.ReinhardToneMapping,
// Cineon色调映射。这种方法起源于电影行业,尝试模仿电影胶片的颜色响应。
Cineon: THREE.CineonToneMapping,
// ACES Filmic色调映射。模仿电影行业中常用的色调映射算法。
ACESFilmic: THREE.ACESFilmicToneMapping,
});
// 控制曝光度
gui.add(renderer, "toneMappingExposure", 0, 3, 0.1);
2. 常用色调映射算法
NoToneMapping: 无色调映射LinearToneMapping: 线性色调映射ReinhardToneMapping: Reinhard色调映射CineonToneMapping: Cineon色调映射ACESFilmicToneMapping: ACES Filmic色调映射(推荐用于电影级渲染)
第七部分:EXR、TIF、PNG动态范围图片
1. EXR格式
EXR是一种专业的高动态范围图像格式,广泛用于电影和视觉特效行业。
import { EXRLoader } from "three/addons/loaders/EXRLoader.js";
// EXR加载器
let exrLoader = new EXRLoader();
exrLoader.load(
"./texture/opt/env/texture.exr",
(texture) => {
console.log("exr", texture);
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.background = texture;
scene.environment = texture;
}
);
2. 其他高动态范围格式
// TIF LogLuv格式
import { LogLuvLoader } from "three/addons/loaders/LogLuvLoader.js";
let logLuvLoader = new LogLuvLoader();
logLuvLoader.load("./texture/opt/env/texture.tif", (texture) => {
console.log("tif", texture);
scene.background = texture;
scene.environment = texture;
});
// RGBM格式
import { RGBMLoader } from "three/addons/loaders/RGBMLoader.js";
let rgbmLoader = new RGBMLoader();
rgbmLoader.load("./texture/opt/env/texture.png", (texture) => {
scene.background = texture;
scene.environment = texture;
});
第八部分:深度模式、深度写入、深度检测
1. 深度模式
深度模式决定像素是否会被渲染,常见的深度模式包括:
// 设置深度模式
plane.material.depthFunc = THREE.LessEqualDepth; // 小于等于时渲染
// 其他深度模式选项
THREE.NeverDepth // 永远不渲染
THREE.AlwaysDepth // 总是渲染
THREE.LessDepth // 小于时渲染
THREE.LessEqualDepth // 小于等于时渲染(常用)
THREE.GreaterEqualDepth // 大于等于时渲染
THREE.GreaterDepth // 大于时渲染
THREE.NotEqualDepth // 不等于时渲染
2. 深度写入和深度检测
// 深度写入 - 是否将深度信息写入深度缓冲
plane.material.depthWrite = true;
// 深度检测 - 是否进行深度测试
plane.material.depthTest = true;
// 渲染顺序 - 当深度测试相同时,决定渲染顺序
plane.renderOrder = 0; // 数值越大越后渲染
3. 透明物体的深度处理
对于透明物体,深度处理尤为重要:
// 设置透明材质
plane.material.transparent = true;
// 为透明物体设置合适的深度模式
plane.material.depthFunc = THREE.LessEqualDepth;
plane.material.depthWrite = true; // 通常设为false以避免深度冲突
plane.material.depthTest = true;
第九部分:混合模式
1. 混合模式概述
混合模式定义了当前像素颜色与帧缓冲中现有颜色的组合方式。
// 基本混合模式
material.blending = THREE.NormalBlending; // 标准混合
material.blending = THREE.AdditiveBlending; // 加法混合
material.blending = THREE.SubtractiveBlending; // 减法混合
material.blending = THREE.MultiplyBlending; // 乘法混合
material.blending = THREE.CustomBlending; // 自定义混合
2. 自定义混合参数
// 自定义混合
material.blending = THREE.CustomBlending;
material.blendEquation = THREE.AddEquation; // 混合方程式
material.blendSrc = THREE.SrcAlphaFactor; // 源因子
material.blendDst = THREE.OneMinusSrcAlphaFactor; // 目标因子
material.blendEquationAlpha = THREE.AddEquation; // Alpha混合方程式
material.blendSrcAlpha = THREE.OneFactor; // 源Alpha因子
material.blendDstAlpha = THREE.OneMinusSrcAlphaFactor; // 目标Alpha因子
3. 混合方程式
AddEquation: 源颜色 + 目标颜色SubtractEquation: 源颜色 - 目标颜色ReverseSubtractEquation: 目标颜色 - 源颜色MinEquation: min(源颜色, 目标颜色)MaxEquation: max(源颜色, 目标颜色)
4. 混合因子
ZeroFactor: 0OneFactor: 1SrcColorFactor: 源颜色OneMinusSrcColorFactor: 1 - 源颜色SrcAlphaFactor: 源AlphaOneMinusSrcAlphaFactor: 1 - 源AlphaDstColorFactor: 目标颜色OneMinusDstColorFactor: 1 - 目标颜色DstAlphaFactor: 目标AlphaOneMinusDstAlphaFactor: 1 - 目标Alpha
第十部分:裁剪平面
1. 裁剪平面概念
裁剪平面允许隐藏几何体的一部分,创建切片或剖面视图。
// 创建裁剪平面
const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0); // 法向量为Y轴正方向,距离为0
// 将裁剪平面应用到材质
material.clippingPlanes = [plane];
// 启用局部裁剪
renderer.localClippingEnabled = true;
// 或者将裁剪平面应用到整个渲染器
renderer.clippingPlanes = [plane, plane2]; // 支持多个裁剪平面
2. 裁剪平面参数控制
// 控制裁剪平面的位置
plane.constant = 5; // 距离原点的距离
// 控制裁剪平面的方向
plane.normal.set(0, 1, 0); // 设置法向量
// 通过GUI动态控制裁剪平面
const folder = gui.addFolder("裁剪平面");
folder.add(plane, "constant", -10, 10).name("位置");
folder.add(plane.normal, "x", -1, 1).name("法向量x");
folder.add(plane.normal, "y", -1, 1).name("法向量y");
folder.add(plane.normal, "z", -1, 1).name("法向量z");
第十一部分:剪裁场景(Scissor Test)
1. Scissor Test概念
Scissor Test允许在屏幕上定义一个矩形区域,在此区域外的像素将不会被渲染。
// 启用剪裁测试
renderer.setScissorTest(true);
// 定义剪裁区域 (x, y, width, height)
renderer.setScissor(0, 0, window.innerWidth/2, window.innerHeight);
// 渲染第一部分场景
renderer.render(scene, camera);
// 定义另一个剪裁区域
renderer.setScissor(
window.innerWidth/2,
0,
window.innerWidth - window.innerWidth/2,
window.innerHeight
);
// 渲染第二部分场景
renderer.render(newScene, camera);
// 关闭剪裁测试
renderer.setScissorTest(false);
2. 动态调整剪裁区域
let params = {
scissorWidth: window.innerWidth / 2,
};
// 在动画循环中使用动态剪裁
function animate() {
controls.update();
requestAnimationFrame(animate);
renderer.setScissorTest(true);
renderer.setScissor(0, 0, params.scissorWidth, window.innerHeight);
renderer.render(scene, camera);
renderer.setScissor(
params.scissorWidth,
0,
window.innerWidth - params.scissorWidth,
window.innerHeight
);
renderer.render(newScene, camera);
renderer.setScissorTest(false);
}
// 通过GUI控制剪裁宽度
gui.add(params, "scissorWidth", 0, window.innerWidth);
第十二部分:模板渲染
1. 模板缓冲概念
模板缓冲(Stencil Buffer)允许基于模板测试的结果来决定是否绘制像素,常用于创建特殊效果。
// 模板缓冲设置参数
const material = new THREE.MeshPhysicalMaterial({
stencilWrite: true, // 启用模板写入
stencilRef: 2, // 模板参考值
stencilWriteMask: 0xff, // 模板写入掩码
stencilFunc: THREE.EqualStencilFunc, // 模板比较函数
stencilZPass: THREE.ReplaceStencilOp, // 深度测试通过时的操作
depthTest: false, // 是否进行深度测试
});
2. 模板比较函数
THREE.NeverStencilFunc: 永远不通过THREE.LessStencilFunc: 小于时通过THREE.EqualStencilFunc: 等于时通过THREE.LessEqualStencilFunc: 小于等于时通过THREE.GreaterStencilFunc: 大于时通过THREE.NotEqualStencilFunc: 不等于时通过THREE.GreaterEqualStencilFunc: 大于等于时通过THREE.AlwaysStencilFunc: 总是通过
3. 模板操作
THREE.KeepStencilOp: 保持当前值THREE.ZeroStencilOp: 设置为0THREE.ReplaceStencilOp: 替换为参考值THREE.IncrementStencilOp: 增加1THREE.DecrementStencilOp: 减少1THREE.InvertStencilOp: 按位取反
4. 金属剖切面效果示例
// 前侧面材质
const frontMaterial = new THREE.MeshPhysicalMaterial({
side: THREE.FrontSide, // 只渲染前侧面
});
// 后侧面材质 - 使用模板缓冲
const backMaterial = new THREE.MeshBasicMaterial({
side: THREE.BackSide, // 只渲染后侧面
color: 0xffcccc,
stencilWrite: true, // 启用模板写入
stencilRef: 1, // 设置参考值
stencilWriteMask: 0xff, // 写入掩码
stencilZPass: THREE.ReplaceStencilOp, // 深度测试通过时替换
});
// 裁剪平面
const clipPlane = new THREE.Plane(new THREE.Vector3(0, -1, 0), 0);
frontMaterial.clippingPlanes = [clipPlane];
backMaterial.clippingPlanes = [clipPlane];
// 启用局部裁剪
renderer.localClippingEnabled = true;
// 剖切面材质 - 只在模板值匹配时渲染
const sectionMaterial = new THREE.MeshPhysicalMaterial({
color: 0xccccff,
metalness: 0.95,
roughness: 0.1,
stencilWrite: true,
stencilRef: 1, // 与后侧面相同的参考值
stencilFunc: THREE.EqualStencilFunc, // 等于参考值时通过
});
总结
通过本教程,我们学习了Three.js中纹理材质的高级操作:
- 纹理变换:掌握纹理的重复、偏移、旋转等变换操作
- 纹理格式:了解DDS、KTX2、TGA、EXR等高级纹理格式的使用
- Mipmap技术:理解Mipmap的工作原理和不同过滤器的选择
- 各项异性过滤:解决纹理倾斜时的模糊问题
- 色调映射:处理高动态范围图像的渲染
- 深度处理:控制物体的深度测试、写入和渲染顺序
- 混合模式:实现透明、叠加等视觉效果
- 裁剪平面:创建切片和剖面视图
- 模板渲染:利用模板缓冲实现高级渲染效果
这些高级技术可以帮助您创建更专业、更具视觉冲击力的3D场景。在实际应用中,这些技术往往需要结合使用,以达到最佳的视觉效果和性能平衡。