UV 法向量实验室:Threejs 纹理与光照炼金术

UV

UV 坐标是二维坐标,用于描述三维模型上的纹理坐标。UV 坐标通常用于将纹理映射到三维模型的表面,从而实现纹理贴图的效果。

在 Three.js 中,每个模型都有一个 geometry 属性,该属性包含模型的顶点坐标、法向量、纹理坐标等信息。纹理坐标通常存储在 geometry.attributes.uv 属性中,该属性是一个 THREE. BufferAttribute 对象,其中包含了每个顶点的 UV 坐标。

如图,左边的贴图杂乱无章,右边的贴图是按照模型顶点的 UV 坐标进行映射的。

js 复制代码
//第一个平面,贴图可以正常显示
const planeGeometry = new THREE.PlaneGeometry(2, 2);
const planeMaterial = new THREE.MeshBasicMaterial({ map: texture });
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.position.x = -2;
scene.add(plane);
console.log(plane);

//第二个不带UV平面,所以贴图无法定位则无法显示
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([-1.0, -1.0, 0.0, 1.0, -1.0, 0.0, 1.0, 1.0, 0.0, -1.0, 1.0, 0.0]);
geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
const indices = new Uint16Array([0, 1, 2, 2, 3, 0]);
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
const material = new THREE.MeshBasicMaterial({ map: texture });
const mesh = new THREE.Mesh(geometry, material);
mesh.position.x = 2;
scene.add(mesh);
console.log(mesh);

设置 UV 坐标,使贴图可以正常显示,UV 坐标的值范围是 0 到 1,表示贴图的左下角和右上角。两个为一组,表示一个顶点的 UV 坐标。

js 复制代码
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([-1.0, -1.0, 0.0, 1.0, -1.0, 0.0, 1.0, 1.0, 0.0, -1.0, 1.0, 0.0]);
geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
const indices = new Uint16Array([0, 1, 2, 2, 3, 0]);
geometry.setIndex(new THREE.BufferAttribute(indices, 1));

//设置UV坐标
const uv = new Float32Array([0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0]);
geometry.setAttribute("uv", new THREE.BufferAttribute(uv, 2));

const material = new THREE.MeshBasicMaterial({ map: texture });
const mesh = new THREE.Mesh(geometry, material);
mesh.position.x = 2;
scene.add(mesh);
console.log(mesh);

对应关系:

(-1.0, -1.0, 0.0) -> (0.0, 0.0)、(1.0, -1.0, 0.0) -> (1.0, 0.0)、(1.0, 1.0, 0.0) -> (1.0, 1.0)、(-1.0, 1.0, 0.0) -> (0.0, 1.0)

法向量

法向量(Normal Vector)是指垂直于一个平面或曲面的向量,用于描述平面的方向或曲面的切线方向。

在三维图形学中,法向量通常用于计算光照、阴影、反射等效果。法向量通常与顶点坐标一起存储,用于计算每个顶点的光照效果。

  • 法向量与顶点坐标的关系

每个顶点都有一个法向量,用于描述该顶点所在平面的方向。法向量通常与顶点坐标一起存储,用于计算每个顶点的光照效果。

  • 法向量与面片的关系

每个面片通常由三个顶点组成,每个顶点都有一个法向量。面片的法向量可以通过计算三个顶点的法向量来得到。

  • 法向量与光照的关系

在计算光照效果时,需要计算光线与面片的法向量之间的夹角,从而得到光照强度。法向量与光照方向之间的夹角越小,光照强度越大。

设置法向

js 复制代码
//创建正常平面
const planeGeometry = new THREE.PlaneGeometry(2, 2);
const planeMaterial = new THREE.MeshBasicMaterial({ map: texture });
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.position.x = -2;
scene.add(plane);
console.log(plane);

//不带法向平面
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([-1.0, -1.0, 0.0, 1.0, -1.0, 0.0, 1.0, 1.0, 0.0, -1.0, 1.0, 0.0]);
geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
const indices = new Uint16Array([0, 1, 2, 2, 3, 0]);
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
//设置UV坐标
const uv = new Float32Array([0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0]);
geometry.setAttribute("uv", new THREE.BufferAttribute(uv, 2));
// const material = new THREE.MeshBasicMaterial({ map: texture });
//这里设置跟第一个平面一样的材质便于观察
const mesh = new THREE.Mesh(geometry, planeMaterial);
mesh.position.x = 2;
scene.add(mesh);
console.log(mesh);

//添加环境贴图
let rgbeLoader = new RGBELoader();
rgbeLoader.load("./texture/st_fagans_interior_1k.hdr", (envMap) => {
  envMap.mapping = THREE.EquirectangularReflectionMapping;
  scene.environment = envMap;
  scene.background = envMap;
  planeMaterial.envMap = envMap;
});

可以看出左边有反射效果,右边因为没有法向量,所以没有反射效果。

js 复制代码
//自动设置法向量
geometry.computeVertexNormals();

//手动设置法向量
const normals = new Float32Array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0]);
geometry.setAttribute("normal", new THREE.BufferAttribute(normals, 3));

设置规则:

法向是垂直于平面的向量,三个坐标为一组,表示一个顶点的法向量。所以平面有四个顶点,那么四个点的法向量都是(0.0, 0.0, 1.0)。

法向量辅助器

法向量辅助器(NormalHelper)是一个用于可视化法向量的工具,可以用于调试和查看法向量的方向和长度。

js 复制代码
//导入顶点法向量辅助器
import { VertexNormalsHelper } from "three/examples/jsm/helpers/VertexNormalsHelper.js";
//创建法向量辅助器
const normalHelper = new THREE.VertexNormalsHelper(mesh, 0.1, 0x00ff00);
scene.add(normalHelper);

VertexNormalsHelper 构造函数接受三个参数:

  • object: 要显示法向量的对象。

  • size: 法向量的长度。

  • color: 法向量的颜色。

书洞笔记

相关推荐
福兮说38 分钟前
JSON 格式正确,数据就可靠吗?我用一份自编配置检查类型与空值
java·前端·json
程序员老赵2 小时前
Docker 部署青龙面板:轻松搭建定时任务管理平台
前端·docker·开源
Swot2 小时前
Asciidoctor 公式数字下标错位问题:原因分析与解决方案
前端
Swot2 小时前
leo-editor 中将 Markdown 内容转成 asciidoc 格式
前端
狒狒AI3 小时前
Remotion / GSAP+Three / HyperFrames / Skia 四栈实测:代码渲染知识视频的选栈方法(附开源技能)
前端·人工智能·aigc
修炼的dance3 小时前
浏览器里导出H.265,8.5秒和55.5秒差在硬件
前端
补码缩写3 小时前
WebCodecs选编码器,探测之后还要验解码和播放
前端
大文说跨境3 小时前
亚马逊多账号管理浏览器怎么选?云登/紫鸟/AdsPower 对比
java·前端·自动化
hunter_0763 小时前
iOS 首页复杂嵌套滚动技术方案:头部固定 + 网格滚动 + Tab 吸顶 + 每 Tab 独立下拉刷新
前端
CoderYanger3 小时前
Java EE 进阶:4.Spring Web MVC 入门(第一弹)
java·开发语言·前端·spring·面试·java-ee·mvc