
门模型使用标准网格材质(MeshStandardMaterial),一种基于物理的渲染。使用PBR方式渲染。
思路:
(1) 建立立方体模
(2)设置基本颜色.map属性添加颜色贴图 color.png (贴图效果与颜色是叠加的)一个简单的带有纹理的立方体的们就成形了
.map : Texture
颜色贴图。可以选择包括一个alpha通道,通常与.transparent 或.alphaTest。默认为null。 纹理贴图颜色由漫反射颜色.color调节。
因此可以选择添加一个alpha贴图去除纹理门框边缘的位置,下面是文档给出的解释:
.alphaMap : Texture
alpha贴图是一张灰度纹理,用于控制整个表面的不透明度。(黑色:完全透明;白色:完全不透明)。 默认值为null。
(3)此时的门的边缘线并不明显,可以添加aoMap属性环境遮挡贴图。细化效果。
.aoMap : Texture
该纹理的红色通道用作环境遮挡贴图。默认值为null。aoMap需要第二组UV。设置第二组uv下面代码中有体现。
.aoMapIntensity : Float
环境遮挡效果的强度。默认值为1。零是不遮挡效果。
(4)此时的呈像给人还是二维的感觉,使用.displacementMap属性,添加位移贴图达到三位的校效果。
.displacementMap : Texture
位移贴图会影响网格顶点的位置,与仅影响材质的光照和阴影的其他贴图不同,移位的顶点可以投射阴影,阻挡其他对象, 以及充当真实的几何体。位移纹理是指:网格的所有顶点被映射为图像中每个像素的值(白色是最高的),并且被重定位。
.displacementScale : Float
位移贴图对网格的影响程度(黑色是无位移,白色是最大位移)。如果没有设置位移贴图,则不会应用此值。默认值为1。
注:应当设立立方体的段数.***Segments(设置长/宽/高应该划分为几段,默认为1),此处设置为了增加顶点的个数,因为位移贴图是通过影响网格顶点的位置来实现的,段数越多模型越精细。
(5)此处已经使用了四张贴图。我们看后面的贴图的使用。
为了让门的金属部分效果更逼真,.metalnessMap设置金属贴图(图片中越倾向白色越靠近金属)
.metalness : Float
材质与金属的相似度。非金属材质,如木材或石材,使用0.0,金属使用1.0,通常没有中间值。 默认值为0.0。0.0到1.0之间的值可用于生锈金属的外观。如果还提供了metalnessMap,则两个值相乘。
.metalnessMap : Texture
该纹理的蓝色通道用于改变材质的金属度。
(6)为了让门更加贴切与生活。可以添加roughnessMap属性,导入粗糙度贴图,设置粗糙度(黑色粗糙,白色光滑)
.roughness : Float
材质的粗糙程度。0.0表示平滑的镜面反射,1.0表示完全漫反射。默认值为1.0。如果还提供roughnessMap,则两个值相乘。
.roughnessMap : Texture
该纹理的绿色通道用于改变材质的粗糙度。
(7)因为日常光照下,门的面是漫反射反光强度不同,所以最后在添加一个法线贴图拉。
.normalMap : Texture
用于创建法线贴图的纹理。RGB值会影响每个像素片段的曲面法线,并更改颜色照亮的方式。法线贴图不会改变曲面的实际形状,只会改变光照。
现在这个门的模型就创建完成了。贴图放在了代码后面。需要的朋友可以自己粘贴。
import * as THREE from "three";
import {Clock, TextureLoader, WebGLRenderer} from "three";
import {fromHalfFloat} from "three/src/extras/DataUtils";
// 导入轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
// 1. 创建场景
const scene = new THREE.Scene();
// 2. 创建相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth/window.innerHeight,
0.1,
1000);
camera.position.set(0,0,10);
scene.add(camera);
const loader = new TextureLoader();
const load1 = loader.load("./textures/door/color.jpg");
const load2 = loader.load("./textures/door/ambientOcclusion.jpg");
const load3 = loader.load("./textures/door/alpha.jpg");
// 导入金属贴图
const metalnessTexture = loader.load("./textures/door/metalness.jpg");
// 导入粗糙度贴图
const roughnessTexture = loader.load("./textures/door/roughness.jpg");
//导入置换贴图 作位移使用
const doorHeightTexture = loader.load("./textures/door/height.jpg");
// 导入法线贴图
const normalTexture = loader.load("./textures/door/normal.jpg");
// 添加我物体创建物体
let geometry = new THREE.BoxGeometry(2,2,2,100,100,100);
let material = new THREE.MeshStandardMaterial({
color : 0xffff00,
map : load1, // 颜色贴图
aoMapIntensity :0.7,
alphaMap : load3, // alpha贴图是一张灰度纹理,用于控制整个表面的不透明度
transparent :true,
aoMap : load2, // 该纹理的红色通道用作环境遮挡贴图。默认值为null。aoMap需要第二组UV
side : THREE.DoubleSide,
metalness: 1,
metalnessMap: metalnessTexture,
roughness: 1,
roughnessMap: roughnessTexture, // 黑色粗糙,白色光滑
displacementMap: doorHeightTexture,
displacementScale: 0.1,
normalMap: normalTexture,
});
let mesh = new THREE.Mesh(geometry,material);
scene.add(mesh);
/** 设置第二组uv */
geometry.setAttribute(
"uv2",
new THREE.BufferAttribute(geometry.attributes.uv.array,2)
);
// 灯光
// 环境光
const light = new THREE.AmbientLight(0xffffff, 0.5); // soft white light
scene.add(light);
//直线光源
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(10, 10, 10);
scene.add(directionalLight);
// 初始化渲染器
var renderer = new WebGLRenderer();
renderer.setSize(window.innerWidth,window.innerHeight);
// 将webgl渲染的canvas 内容添加进入 body
document.body.appendChild(renderer.domElement);
// 创建轨道控制器
const controls = new OrbitControls(camera,renderer.domElement);
controls.enableDamping = true; // 设置阻尼
var helper = new THREE.AxesHelper(5);
scene.add(helper);
function render(){
controls.update();
renderer.render(scene,camera);
// 渲染下一帧就会调用render 函数
requestAnimationFrame(render); // 请求动画帧
}
render();
// 监听页面变化,更新渲染画面
window.addEventListener("resize",()=>{
// 1. 更新摄像头
camera.aspect = window.innerWidth / window.innerHeight;
// 2. 更新摄像机的投影矩阵
camera.updateProjectionMatrix();
// 3. 更新渲染器
renderer.setSize(window.innerWidth,window.innerHeight);
// 4. 更新渲染器的像素比
renderer.setPixelRatio(window.devicePixelRatio);
})
window.addEventListener("dblclick",()=>{
const fullScreenElement = document.fullscreenElement; // 是否全屏
if (!fullScreenElement) {
renderer.domElement.requestFullscreen();
} else {
document.exitFullscreen();
}
});






