这个小节主要学习纹理,Texture
纹理是覆盖几何形状表面的图像,不同类型的纹理具有多种不同的效果。
这些纹理(尤其是金属性和粗糙度)遵循PBR
原则
- 基于物理的渲染
- 许多技术往往遵循现实生活中的方向以获得现实的结果
- 成为现实渲染的标准
- 许多软件、引擎和库都在使用它
如何加载纹理?
首先引入一张图片,图片确保在public
目录下,以便被正确解析
const wukong = new Image();
wukong.onload = () => {console.log("图片已加载");
};
wukong.src = "/assets/wukong.png";
然后将这张图片转化为Texture
const wukong = new Image();
const texture = new THREE.Texture(wukong);
wukong.onload = () => {texture.needsUpdate = true;
};
wukong.src = "/assets/wukong.png";
const material = new THREE.MeshBasicMaterial({// color: 0xff0000,map: texture,
});
渲染结果
或者使用textureLoader
为什么会有白色默认颜色和我的材质相叠加?
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load("/assets/wukong.png");
在textureLoader.load()
函数中,除了第一个路径参数,还有其它三个参数,准确的说是三个回调函数
- 加载成功-当图像加载成功时
- 进行时-加载进行时
- 加载错误-如果出现问题
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load("/assets/rustyLake.png",() => {console.log("加载成功");},() => {console.log("正在运行");},() => {console.log("加载失败");}
);
同时,我们可以使用LoadingManager
来看见所有的loading progress
它们loading
的进度
const loadingManager = new THREE.LoadingManager();
const textureLoader = new THREE.TextureLoader(loadingManager);
const loadingManager = new THREE.LoadingManager();
//通过不同的回调函数,来看见加载的过程,处理加载失败
loadingManager.onStart = () => {console.log("加载开始");
};
loadingManager.onLoad = () => {console.log("加载完成");
};
loadingManager.onProgress = () => {console.log("正在加载");
};
纹理以不同的方式被拉伸或挤压以覆盖在几何上,这被称为UV unwrapping
.
每个点在平面(通常是正方形)上都有一个2D坐标,就是在这个几何模型的展开图上有一个屏幕的坐标。
这些UV
坐标由 Three.js
生成。
如果我们创建自己的几何体,则必须指定 UV 坐标
如果我们使用 3D 软件制作几何体,您还自己做
UV
展开。
我们可以在geography.attribution.uv
中看到这些UV unwrapping
const geometry = new THREE.BoxGeometry(1, 1, 1);
console.log(geometry.attributes.uv);
我们可以通过使用repeat
属性来重复纹理
它是具有x
和y
属性的Vector 2
默认情况下,纹理不会重复,最后一个像素会被拉伸。我们可以用THREE.RepeatWrapping
中的来改变这一点。改变wrapS
和wrapT
texture.repeat.x = 2;
texture.wrapT = THREE.RepeatWrapping;
texture.wrapS = THREE.RepeatWrapping;
//或者对称重复
texture.wrapT = THREE.MirroredRepeatWrapping;
texture.wrapS = THREE.MirroredRepeatWrapping;
同时,也可以将材质偏移,旋转
texture.offset.x = 0.5;
texture.offset.y = 0.5;
//现在的旋转中心是(0,0)这个坐标
texture.rotation = Math.PI * 0.25;
//我们同时也可以修改旋转中心的坐标
texture.center.x = 0.5;
texture.center.y = 0.5;
FILTERING AND MIPMAPPING
有些时候,当我们看向顶面或缩小方块时,会看到模糊的材质。这是因为Mipmapping
会一次又一次地创建半个较小版本的材质(上一材质的四分之一大小),直到我们得到1x1
像素的材质,所有这些材质都会被发送到GPU,当我们没有显示一整个面,GPU
就会选择一些较小的材质来填充剩余的部分,达到当前模型位置下最合适的材质纹理。
所有这些都已经由Three.js
和GPU
处理,但我们可以选择不同的算法,有两种类型的过滤算法。
Minification Filters
- THREE.NearestFilter
- THREE.NearestMipmapNearestFilter
- THREE.NearestMipmapLinearFilter
- THREE.LinearFilter
- THREE.LinearMipmapNearestFilter
- THREE.LinearMipmapLinearFilter(default)
这些常量用于纹理的minFilter属性,它们定义了当被纹理化的像素映射到大于1纹理元素(texel)的区域时,将要使用的纹理缩小函数。
//NearestFilter会得到一种尖锐缩小的结果
texture.minFilter = THREE.NearestFilter;
texture.magFilter = THREE.NearestMipmapNearestFilter;
如果说我们的材质贴图很小,但是材质方块很大,以至于材质贴上去就变得模糊时,可以使用NearestFilter
来将材质变得清晰而尖锐,同时,使用NearestFilter
也会让性能变得更好。
如果我们使用 THREE.NearestFilter 在 minFilter 上,我们不需要Mipmapping
我们可以使用texture.generateMipmaps = false
来关闭它。
texture.minFilter = THREE.NearestFilter;
texture.generateMipmaps = false;
TEXTURE FORMAT AND OPTIMISATION
材质的格式和优化,当我们在创建材质时,要考虑三个参数- The weight
- The size (or the resolution)
- The data
有些时候,用户们会下载材质,我们可以选择不同文件类型的材质和确认用户使用体验的文件大小
.jpg
——会压缩画质,通常文件更小.png
——会较少的压缩画质,通常文件更大
材质纹理的每个像素都会存储在GPU
上,而不管图像的到底有多大。但是GPU
有存储限制,同时mipmapping
又增加了要存储的像素的数量,所以作为开发人员要尝试尽可能减小图像的大小。
因为mipmapping
会持续细分到1*1像素大小的材质,所以我们找的原材质大小的宽高都应该是2的n次方
同时材质纹理是支持透明度的,但我们不能在.jpg
中使用透明度,如果我们想有一个结合了color
和alpha
的纹理,我们最好使用.png
文件。
有些时候我们也可以在同一个材质中使用不同通道的值,像红,绿,蓝和alpha
通道