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

书洞笔记

相关推荐
java_nnnn2 分钟前
JavaEE进阶-CSS初识
java·前端·css·java-ee·html
good_ideal4 分钟前
从零实现一个自动提交 PR 的 MCP 工具:用 Skill 串起 Git 与 Azure DevOps
前端
喜欢吃豆6 分钟前
Agent 前端协议正在分层:彻底讲清 MCP Apps、AG-UI 与 A2UI
前端·大模型
赵锦川7 分钟前
css代替表格
前端·css
其实防守也摸鱼24 分钟前
内网安全防护实践:从攻击视角理解防御要点
java·前端·安全·架构·自动化·nps
JavaGuide1 小时前
DeepSeek Harness 官方桌面端终于有了!
前端·后端
wshzd1 小时前
LLM之Agent(104)|DeepSeek-Harness(十三)ReactLoopAgent 总览:kick → turn → step
开发语言·前端·javascript
茉莉玫瑰花茶1 小时前
OpenGL [ 基础概念 ]
java·前端·数据库
随性而行3601 小时前
企业微信二次开发如何接入大模型工具?API接口实现智能任务调用的技术思路
java·前端·人工智能·python·微信·机器人·企业微信
IMPYLH1 小时前
HTML 的 <td> 元素
前端·html