获取材质贴图(3d模型)
网站里提供了一些纹理图片和简单的模型
map 颜色贴图
基础网格材质(MeshBasicMaterial)
一个以简单着色(平面或线框)方式来绘制几何体的材质。这种材质不受光照的影响。 不受光照影响说明不需要添加光源就可以看见物体
<template>
<div class="container" id="container"></div>
</template>
<script setup lang="ts">
import {
onMounted } from 'vue';
import * as THREE from 'three';
// 导入轨道控制器,模块化开发导入的是jsm不是js
import {
OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
onMounted(() => {
// 添加一个场景
const scene = new THREE.Scene();
// 创建一个透视相机,摄像机的视野是一个圆锥,顶点就是摄像机的位置
const camera = new THREE.PerspectiveCamera(
75, // 摄像机视锥体垂直视野角度
window.innerWidth / window.innerHeight, // 摄像机视锥体长宽比
0.1, // 摄像机视锥体近端面
1000 // 摄像机视锥体远端面
);
// 设置相机的位置
camera.position.set(0, 0, 10); // x、y、z
// 把相机添加到场景中
scene.add(camera);
// 创建几何体
const geometry = new THREE.BoxGeometry(2, 2, 2);
// 设置材质
const basicMaterial = new THREE.MeshBasicMaterial(
{
color: '#3f7b9d',
}
);
// 创建物体
const cube = new THREE.Mesh(geometry, basicMaterial);
// 将立方体添加到场景中
scene.add(cube);
// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(800, 600);
// 将wbgl渲染的canvas内容添加到dom元素中
document.getElementById('container')?.appendChild(renderer.domElement);
// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼,让物体拥有惯性,必须在动画循环里调用update()
controls.enableDamping = true;
// 添加坐标轴辅助器
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
// 创建一个渲染函数,当场景发生变化后重新渲染
const render = () => {
controls.update();
renderer.render(scene, camera);
// 使用浏览器自带的请求动画帧函数不断的进行渲染
requestAnimationFrame(render);
};
render();
});
</script>
设置纹理
// 导入纹理
const textureLoader = new THREE.TextureLoader();
const door = textureLoader.load('../../../../public/color.jpg');
// 设置材质
const basicMaterial = new THREE.MeshBasicMaterial(
{
color: 'yellow',
map: door
}
);
材质的颜色对纹理的颜色是有影响的。
alphaMap 透明度贴图
alpha贴图是一张灰度纹理,用于控制整个表面的不透明度。(黑色:完全透明;白色:完全不透明)。 默认值为null。
透明度贴图可以用于场景空隙,比如铁栅栏。
// 导入纹理
const textureLoader = new THREE.TextureLoader();
// 颜色贴图
const door = textureLoader.load('../../../../public/color.jpg');
// 透明贴图
const alpha = textureLoader.load('../../../../public/alpha.jpg');
// 设置材质
const basicMaterial = new THREE.MeshBasicMaterial(
{
color: 'yellow',
map: door, // 颜色贴图
alphaMap: alpha, // 透明贴图
transparent: true // 必须要设置,否则透明贴图不会生效
}
);
环境遮挡贴图
aoMap,个人觉得用于遮挡物体表面的光照,使物体表面出现阴影
// 导入纹理
const textureLoader = new THREE.TextureLoader();
// 颜色贴图
const door = textureLoader.load('../../../../public/color.jpg');
// 透明贴图
const alpha = textureLoader.load('../../../../public/alpha.jpg');
// 环境遮挡贴图
const aoMap = textureLoader.load('../../../../public/ambientOcclusion.jpg');
// 创建几何体
const geometry = new THREE.BoxGeometry(2, 2, 2);
// 设置材质
const basicMaterial = new THREE.MeshBasicMaterial(
{
color: 'yellow',
map: door, // 颜色贴图
alphaMap: alpha, // 透明贴图
transparent: true, // 必须要设置,否则透明贴图不会生效
aoMap: aoMap // 环境遮挡贴图
}
);
// 创建物体
const cube = new THREE.Mesh(geometry, basicMaterial);
// 将立方体添加到场景中
scene.add(cube);
// 环境遮挡贴图需要第二组UV才能够生效,获取材质本身的UV
geometry.setAttribute('uv2', new THREE.BufferAttribute(geometry.attributes.uv.array, 2));
物料渲染
标准网格材质(MeshStandardMaterial)。一种基于物理的标准材质,使用Metallic-Roughness工作流程。
基于物理的渲染(PBR)最近已成为许多3D应用程序的标准,例如Unity, Unreal和 3D Studio Max。使用标准网格材质必须要添加光源
环境光
AmbientLight,环境光会均匀的照亮场景中的所有物体。环境光不能用来投射阴影,因为它没有方向。
// 设置材质
const meshMaterial = new THREE.MeshStandardMaterial(
{
color: 'yellow',
map: door, // 颜色贴图
alphaMap: alpha, // 透明贴图
transparent: true, // 必须要设置,否则透明贴图不会生效
aoMap: aoMap // 环境遮挡贴图
}
);
// 创建物体
const cube = new THREE.Mesh(geometry, meshMaterial);
// 将立方体添加到场景中
scene.add(cube);
// 环境遮挡贴图需要第二组UV才能够生效,获取材质本身的UV
geometry.setAttribute('uv2', new THREE.BufferAttribute(geometry.attributes.uv.array, 2));
// 添加灯光,环境光,
const light = new THREE.AmbientLight(0xffffff,0.6); // 设置环境光的颜色和亮度,亮度最大是1
scene.add(light);
平行光
DirectionalLight,平行光是沿着特定方向发射的光。这种光的表现像是无限远,从它发出的光线都是平行的。常常用平行光来模拟太阳光 的效果; 平行光可以投射阴影
// 添加灯光,环境光
const light = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(light);
// 添加平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(10, 0, 0); // 设置平行光是从x轴方向照射
scene.add(directionalLight);
位移贴图
displacementMap ,位移贴图会影响网格顶点的位置,与仅影响材质的光照和阴影的其他贴图不同,移位的顶点可以投射阴影,阻挡其他对象, 以及充当真实的几何体。根据贴图的颜色来进行凸显,颜色约白位置越高。
贴图材料
// 位移贴图
const displace = textureLoader.load('../../../../public/height.jpg');
// 创建几何体,增加顶点数
const geometry = new THREE.BoxGeometry(2, 2, 2, 100, 100, 100);
// 设置材质
const meshMaterial = new THREE.MeshStandardMaterial(
{
color: 'yellow',
map: door, // 颜色贴图
alphaMap: alpha, // 透明贴图
transparent: true, // 必须要设置,否则透明贴图不会生效
aoMap: aoMap, // 环境遮挡贴图
displacementMap: displace, // 位移贴图
displacementScale: 0.2 // 设置位移贴图对网格的影响
}
);
注意点:
1、必须给物体增加分段数,默认物体就是一整块,增加分段数后,就是由多块组合而成,这样位移贴图才能生效,使某些板块突出出来
2、设置displacementScale,设置位移贴图对网格的影响成都
粗糙度贴图
roughness
材质的粗糙程度。0.0表示平滑的镜面反射,1.0表示完全漫反射。默认值为1.0。如果还提供roughnessMap,则两个值相乘。
roughnessMap
该纹理的绿色通道用于改变材质的粗糙度。黑色代表光滑,白色代表不光滑
// 设置材质
const meshMaterial = new THREE.MeshStandardMaterial(
{
color: 'yellow',
map: door, // 颜色贴图
alphaMap: alpha, // 透明贴图
transparent: true, // 必须要设置,否则透明贴图不会生效
aoMap: aoMap, // 环境遮挡贴图
displacementMap: displace, // 位移贴图
displacementScale: 0.2, // 设置位移贴图对网格的影响
roughness: 0 // 粗糙度
}
);
很明显我们可以看见灯光
// 导入粗糙度贴图
const roughMap = textureLoader.load('../../../../public/roughness.jpg');
// 创建几何体,增加顶点数
const geometry = new THREE.BoxGeometry(2, 2, 2, 100, 100, 100);
// 设置材质
const meshMaterial = new THREE.MeshStandardMaterial(
{
color: 'yellow',
map: door, // 颜色贴图
alphaMap: alpha, // 透明贴图
transparent: true, // 必须要设置,否则透明贴图不会生效
aoMap: aoMap, // 环境遮挡贴图
displacementMap: displace, // 位移贴图
displacementScale: 0.2, // 设置位移贴图对网格的影响
roughness: 1, // 粗糙度
roughnessMap: roughMap // 粗糙度贴图
}
);
金属贴图
metalness
材质与金属的相似度。非金属材质,如木材或石材,使用0.0,金属使用1.0,通常没有中间值。 默认值为0.0。0.0到1.0之间的值可用于生锈金属的外观。如果还提供了metalnessMap,则两个值相乘。
metalnessMap
该纹理的蓝色通道用于改变材质的金属度。
// 设置材质
const meshMaterial = new THREE.MeshStandardMaterial(
{
color: 'yellow',
map: door, // 颜色贴图
alphaMap: alpha, // 透明贴图
transparent: true, // 必须要设置,否则透明贴图不会生效
aoMap: aoMap, // 环境遮挡贴图
displacementMap: displace, // 位移贴图
displacementScale: 0.2, // 设置位移贴图对网格的影响
roughness: 1, // 粗糙度
roughnessMap: roughMap, // 粗糙度贴图
metalness: 1 // 金属度
}
);
设置金属度后,门会变成金属材质,没有光照的部分会看不见。
使用金属贴图,只让金属的部分变成金属材质
// 金属贴图
const metaMap = textureLoader.load('../../../../public/metalness.jpg');
// 创建几何体,增加顶点数
const geometry = new THREE.BoxGeometry(2, 2, 2, 100, 100, 100);
// 设置材质
const meshMaterial = new THREE.MeshStandardMaterial(
{
color: 'yellow',
map: door, // 颜色贴图
alphaMap: alpha, // 透明贴图
transparent: true, // 必须要设置,否则透明贴图不会生效
aoMap: aoMap, // 环境遮挡贴图
displacementMap: displace, // 位移贴图
displacementScale: 0.2, // 设置位移贴图对网格的影响
roughness: 1, // 粗糙度
roughnessMap: roughMap, // 粗糙度贴图
metalness: 0, // 金属度
metalnessMap: metaMap // 金属贴图
}
);
法线贴图
normalMap
用于创建法线贴图的纹理。RGB值会影响每个像素片段的曲面法线,并更改颜色照亮的方式。法线贴图不会改变曲面的实际形状,只会改变光照
法线贴图的图片是有颜色的图
// 法线贴图
const normalMap = textureLoader.load('../../../../public/normal.jpg');
// 创建几何体,增加顶点数
const geometry = new THREE.BoxGeometry(2, 2, 2, 100, 100, 100);
// 设置材质
const meshMaterial = new THREE.MeshStandardMaterial(
{
color: 'yellow',
map: door, // 颜色贴图
alphaMap: alpha, // 透明贴图
transparent: true, // 必须要设置,否则透明贴图不会生效
aoMap: aoMap, // 环境遮挡贴图
displacementMap: displace, // 位移贴图
displacementScale: 0.2, // 设置位移贴图对网格的影响
roughness: 1, // 粗糙度
roughnessMap: roughMap, // 粗糙度贴图
metalness: 0, // 金属度
metalnessMap: metaMap, // 金属贴图
normalMap: normalMap // 法线贴图
}
);
对比之前的图可以看到,光并不是一个完整的圆圈了。
完整代码
<template>
<div class="container" id="container"></div>
</template>
<script setup lang="ts">
import {
onMounted } from 'vue';
import * as THREE from 'three';
// 导入轨道控制器,模块化开发导入的是jsm不是js
import {
OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
onMounted(() => {
// 添加一个场景
const scene = new THREE.Scene();
// 创建一个透视相机,摄像机的视野是一个圆锥,顶点就是摄像机的位置
const camera = new THREE.PerspectiveCamera(
75, // 摄像机视锥体垂直视野角度
window.innerWidth / window.innerHeight, // 摄像机视锥体长宽比
0.1, // 摄像机视锥体近端面
1000 // 摄像机视锥体远端面
);
// 设置相机的位置
camera.position.set(0, 0, 10); // x、y、z
// 把相机添加到场景中
scene.add(camera);
// 导入纹理
const textureLoader = new THREE.TextureLoader();
// 颜色贴图
const door = textureLoader.load('../../../../public/color.jpg', () => {
console.log('颜色贴图加载完成');
});
// 透明贴图
const alpha = textureLoader.load('../../../../public/alpha.jpg');
// 环境遮挡贴图
const aoMap = textureLoader.load('../../../../public/ambientOcclusion.jpg');
// 位移贴图
const displace = textureLoader.load('../../../../public/height.jpg');
// 导入粗糙度贴图
const roughMap = textureLoader.load('../../../../public/roughness.jpg');
// 金属贴图
const metaMap = textureLoader.load('../../../../public/metalness.jpg');
// 法线贴图
const normalMap = textureLoader.load('../../../../public/normal.jpg');
// 创建几何体,增加顶点数
const geometry = new THREE.BoxGeometry(2, 2, 2, 100, 100, 100);
// 设置材质
const meshMaterial = new THREE.MeshStandardMaterial(
{
color: 'yellow',
map: door, // 颜色贴图
alphaMap: alpha, // 透明贴图
transparent: true, // 必须要设置,否则透明贴图不会生效
aoMap: aoMap, // 环境遮挡贴图
displacementMap: displace, // 位移贴图
displacementScale: 0.2, // 设置位移贴图对网格的影响
roughness: 1, // 粗糙度
roughnessMap: roughMap, // 粗糙度贴图
metalness: 0, // 金属度
metalnessMap: metaMap, // 金属贴图
normalMap: normalMap // 法线贴图
}
);
// 创建物体
const cube = new THREE.Mesh(geometry, meshMaterial);
// 将立方体添加到场景中
scene.add(cube);
// 环境遮挡贴图需要第二组UV才能够生效,获取材质本身的UV
geometry.setAttribute('uv2', new THREE.BufferAttribute(geometry.attributes.uv.array, 2));
// 添加灯光,环境光
const light = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(light);
// 添加平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(10, 0, 0); // 设置平行光是从x轴方向照射
scene.add(directionalLight);
// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(800, 600);
// 将wbgl渲染的canvas内容添加到dom元素中
document.getElementById('container')?.appendChild(renderer.domElement);
// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼,让物体拥有惯性,必须在动画循环里调用update()
controls.enableDamping = true;
// 添加坐标轴辅助器
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
// 创建一个渲染函数,当场景发生变化后重新渲染
const render = () => {
controls.update();
renderer.render(scene, camera);
// 使用浏览器自带的请求动画帧函数不断的进行渲染
requestAnimationFrame(render);
};
render();
});
</script>
纹理加载进度
TextureLoader类提供了load方法,前面我们只是用来加载文件,下面看一下它的回调
单张纹理加载
// 导入纹理
const textureLoader = new THREE.TextureLoader();
// 颜色贴图
const door = textureLoader.load('../../../../public/color.jpg', () => {
console.log('颜色贴图加载完成');
});
LoadingManager
其功能是处理并跟踪已加载和待处理的数据。具体内容见官方文档
环境贴图
例如有一个光滑的金属小球,真实情况下,小球表面是可以显示出周围的环境的。这个效果可以通过环境贴图来实现
envMap
环境贴图,为了能够保证物理渲染准确,您应该添加由PMREMGenerator预处理过的环境贴图,默认为null。
envMapIntensity
通过乘以环境贴图的颜色来缩放环境贴图的效果。
<template>
<div class="container" id="container"></div>
</template>
<script setup lang="ts">
import {
onMounted } from 'vue';
import * as THREE from 'three';
// 导入轨道控制器,模块化开发导入的是jsm不是js
import {
OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
onMounted(() => {
// 添加一个场景
const scene = new THREE.Scene();
// 创建一个透视相机,摄像机的视野是一个圆锥,顶点就是摄像机的位置
const camera = new THREE.PerspectiveCamera(
75, // 摄像机视锥体垂直视野角度
window.innerWidth / window.innerHeight, // 摄像机视锥体长宽比
0.1, // 摄像机视锥体近端面
1000 // 摄像机视锥体远端面
);
// 设置相机的位置
camera.position.set(0, 0, 10); // x、y、z
// 把相机添加到场景中
scene.add(camera);
// 环境贴图
const envMap = new THREE.CubeTextureLoader()
.setPath('../../../../public/env/')
.load([
'px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg'
]);
// 创建球体,半径1,20是分段
const spherGeometry = new THREE.SphereGeometry(1, 20, 20);
const spherMaterial = new THREE.MeshStandardMaterial({
metalness: 0.7, // 金属度
roughness: 0.1, // 粗糙度
envMap: envMap // 环境贴图
});
// 创建物体
const cube = new THREE.Mesh(spherGeometry, spherMaterial);
// 将立方体添加到场景中
scene.add(cube);
// 添加灯光,环境光
const light = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(light);
// 添加平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(10, 0, 0); // 设置平行光是从x轴方向照射
scene.add(directionalLight);
// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(800, 600);
// 将wbgl渲染的canvas内容添加到dom元素中
document.getElementById('container')?.appendChild(renderer.domElement);
// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼,让物体拥有惯性,必须在动画循环里调用update()
controls.enableDamping = true;
// 添加坐标轴辅助器
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
// 创建一个渲染函数,当场景发生变化后重新渲染
const render = () => {
controls.update();
renderer.render(scene, camera);
// 使用浏览器自带的请求动画帧函数不断的进行渲染
requestAnimationFrame(render);
};
render();
});
</script>
1、环境贴图的加载必须按照顺序来,分别是px(正方向的x轴贴图)、nx(负方向的x轴贴图)、py(正方形的y轴贴图)、ny(负方向的y轴贴图)、pz(正方形的z轴贴图)、nz(负方向的轴贴图)
2、必须要给物体设置金属度和光滑度,只设置环境贴图是无用的
设置场景的背景
// 给场景设置背景
scene.background = envMap;
// 给场景内的所有问题添加默认的环境贴图,如果场景内的物体有环境贴图则使用自身的,没有则使用默认的
scene.environment = envMap;
HDR环境图的设置
对应HDR指令的文件需要使用DataTextureLoader加载器,用于加载二进制文件格式的(rgbe, hdr, …)的抽象类。 内部使用FileLoader来加载文件, 和创建一个新的 DataTexture.
import {
RGBELoader} from 'three/examples/jsm/loaders/RGBELoader'
const rgbeloader = new RGBELoader();
rgbeloader.loadAsync('../../../../public/002.hdr')
.then((texture) => {
// 设置纹理映射类型
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.background = texture;
});
灯光与阴影
常用光
平行光(DirectionalLight)、点光源(PointLight)、聚光灯(SpotLight)可以产生阴影。
平行光:平行光是沿着特定方向发射的光。
点光源:从一个点向各个方向发射的光源。
聚光灯:光线从一个点沿一个方向射出,随着光线照射的变远,光线圆锥体的尺寸也逐渐增大。比如手电筒
环境光(AmbientLight)、平面光(RectAreaLight)不可以产生阴影
环境光:环境光会均匀的照亮场景中的所有物体。环境光不能用来投射阴影,因为它没有方向。
平面光:平面光光源从一个矩形平面上均匀地发射光线。这种光源可以用来模拟像明亮的窗户或者条状灯光光源。
常用材质
基础网格材质(MeshBasicMaterial)不受光照的影响 ,标准网格材质(MeshStandardMaterial)受光照的影响。其他材质像我这种入门者应该也用不到就不介绍了。
灯光阴影
1、材质要满足对光照有反应
2、设置渲染器开启阴影的计算
3、设置光照投射阴影
4、设置物体投射阴影
5、设置物体接收阴影
6、要注意光照的角度
<template>
<div class="container" id="container"></div>
</template>
<script setup lang="ts">
import {
onMounted } from 'vue';
import * as THREE from 'three';
// 导入轨道控制器,模块化开发导入的是jsm不是js
import {
OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
onMounted(() => {
// 添加一个场景
const scene = new THREE.Scene();
// 创建一个透视相机,摄像机的视野是一个圆锥,顶点就是摄像机的位置
const camera = new THREE.PerspectiveCamera(
75, // 摄像机视锥体垂直视野角度
window.innerWidth / window.innerHeight, // 摄像机视锥体长宽比
0.1, // 摄像机视锥体近端面
1000 // 摄像机视锥体远端面
);
// 设置相机的位置
camera.position.set(0, 0, 10); // x、y、z
// 把相机添加到场景中
scene.add(camera);
// 创建球体,半径1,20是分段
const spherGeometry = new THREE.SphereGeometry(1, 20, 20);
const material = new THREE.MeshStandardMaterial();
const cube = new THREE.Mesh(spherGeometry, material); // 球体
cube.castShadow = true; // 设置球体可以投射阴影
// 将立方体添加到场景中
scene.add(cube);
// 创建平面并添加到场景中
const planeGeometry = new THREE.PlaneGeometry(10, 10, 10, 10); // 平面物体
const plane = new THREE.Mesh(planeGeometry, material); // 平面
plane.position.set(0, -1, 0);
plane.rotation.x = -Math.PI / 2;
// 设置平面可以接收来自球的阴影
plane.receiveShadow = true;
scene.add(plane);
// 添加灯光,环境光
const light = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(light);
// 添加平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(15, 10, 0); // 设置平行光是从x轴方向照射
directionalLight.castShadow = true; // 设置光照产生阴影
scene.add(directionalLight);
// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(800, 600);
// 开启场景阴影渲染
renderer.shadowMap.enabled = true;
// 将wbgl渲染的canvas内容添加到dom元素中
document.getElementById('container')?.appendChild(renderer.domElement);
// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼,让物体拥有惯性,必须在动画循环里调用update()
controls.enableDamping = true;
// 添加坐标轴辅助器
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
// 创建一个渲染函数,当场景发生变化后重新渲染
const render = () => {
controls.update();
renderer.render(scene, camera);
// 使用浏览器自带的请求动画帧函数不断的进行渲染
requestAnimationFrame(render);
};
render();
});
</script>