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: 法向量的颜色。

书洞笔记

相关推荐
candyTong1 天前
一觉醒来,大模型就帮我排查完页面性能问题
前端·javascript·架构
魔术师Grace1 天前
我给 AI 做了场入职培训
前端·程序员
玩嵌入式的菜鸡1 天前
网页访问单片机设备---基于mqtt
前端·javascript·css
前端一小卒1 天前
我用 Claude Code 的 Superpowers 技能链写了个服务,部署前差点把服务器搞炸
前端·javascript·后端
滑雪的企鹅.1 天前
HTML头部元信息避坑指南大纲
前端·html
一拳不是超人1 天前
老婆天天吵吵要买塔罗牌,我直接用 AI 2 小时写了个在线塔罗牌
前端·ai编程
excel1 天前
如何解决 Nuxt DevTools 中关于 unstorage 包的报错
前端
Rust研习社1 天前
使用 Axum 构建高性能异步 Web 服务
开发语言·前端·网络·后端·http·rust
C澒1 天前
AI 生码 - API2Code:接口智能匹配与 API 自动化生码全链路设计
前端·低代码·ai编程
浔川python社1 天前
HTML头部元信息避坑指南技术文章大纲
前端·html