ThreeJS 几何体顶点position、法向量normal及uv坐标 | UV映射 - 法向量 - 包围盒

文章目录

  • 几何体的顶点position、法向量normal及uv坐标
    • UV映射
      • UV坐标系
      • UV坐标与顶点坐标
      • 设置UV坐标
        • 案例1:使用PlaneGeometry创建平面缓存几何体
        • 案例2:使用BufferGeometry创建平面缓存几何体
    • 法向量 - 顶点法向量光照计算
      • 案例1:不设置顶点法向量平面几何体与自带顶点法向量的平面几何体对比
      • 案例2:设置法向量
        • 方式1 computeVertexNormals方法
        • 方式2:自定义normal属性值
        • 引入顶点法向量辅助器VertexNormalsHelper
    • 几何体的移动、旋转和缩放
      • 移动几何体的顶点 bufferGeometry.translate
        • 几何体平移与物体平移
      • 几何体旋转与模型旋转(缩放同理)

几何体的顶点position、法向量normal及uv坐标

UV映射

UV映射是一种将二维纹理映射到三维模型表面的技术。
在这个过程中,3D模型上的每个顶点都会被赋予一个二维坐标(U, V)
这些坐标用于将纹理图像上的像素与模型表面上的点进行对应。

UV坐标系

U和V分别表示纹理坐标的水平和垂直方向,使用UV来表达纹理的坐标系。
UV坐标的取值范围是0~1,纹理贴图左下角对应的UV坐标是(0,0),右上角对应的坐标(1,1)。
在这里插入图片描述

UV坐标与顶点坐标

类型含义属性
UV坐标该顶点在纹理上的二维坐标(U, V)geometry.attributes.uv
顶点坐标3D/2D模型中每个顶点的空间坐标(x, y, z)geometry.attributes.position
  • 位置关系是一一对应的,每一个顶点位置对应一个纹理贴图的位置
  • 顶点位置用于确定模型在场景中的形状,而UV坐标用于确定纹理在模型上的分布。

设置UV坐标

案例1:使用PlaneGeometry创建平面缓存几何体
// 图片路径public/assets/panda.png
let uvTexture = new THREE.TextureLoader().load("/assets/panda.png");

// 创建平面几何体
const planeGeometry = new THREE.PlaneGeometry(100, 100);
console.log("planeGeometry.attributes.position",planeGeometry.attributes.position.array);
console.log("planeGeometry.attributes.uv",planeGeometry.attributes.uv.array);
console.log("planeGeometry.index",planeGeometry.index.array);

// 创建材质
const planeMaterial = new THREE.MeshBasicMaterial({
  map: uvTexture,
});
// 创建平面
const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);
// 添加到场景
scene.add(planeMesh);
planeMesh.position.x = -3;

在这里插入图片描述
贴图正确显示,查看positionuv发现设置贴图时已自动计算出uv坐标
在这里插入图片描述

案例2:使用BufferGeometry创建平面缓存几何体

1.使用BufferGeometry创建平面缓存几何体,通过map设置贴图。

let uvTexture = new THREE.TextureLoader().load("/assets/panda.png");
// 创建平面几何体
const geometry = new THREE.BufferGeometry();
// 使用索引绘制
const vertices = new Float32Array([
  -50, 50, 0, 
  50, 50, 0, 
  -50, -50, 0,
  50, -50,0
]);
// 创建顶点属性
geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
// 创建索引
const indices = new Uint16Array([0, 2, 1, 2, 3, 1]);
// 创建索引属性
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
// 创建材质
const material = new THREE.MeshBasicMaterial({
  map: uvTexture,
});
const plane = new THREE.Mesh(geometry, material);
scene.add(plane);
plane.position.x = 3;
console.log("geometry.attributes.position",geometry.attributes.position.array);
console.log("geometry.attributes.uv",geometry.attributes.uv);
console.log("geometry.index",geometry.index.array);

贴图并没有生效,通过打印发现BufferGeometry没有uv坐标,需要自定义uv坐标
在这里插入图片描述

2.根据纹理坐标将纹理贴图的对应位置裁剪映射到几何体的表面上


let uvTexture = new THREE.TextureLoader().load("/assets/panda.png");
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
  -50, 50, 0, 
  50, 50, 0, 
  -50, -50, 0,
  50, -50,0
]);
geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
const indices= new Uint16Array([0, 2, 1, 2, 3, 1]);
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
const material = new THREE.MeshBasicMaterial({
  map: uvTexture,
});
const plane = new THREE.Mesh(geometry, material);
scene.add(plane);
plane.position.x = 3;
const uv = new Float32Array([
	0,1,
	1,1,
	0,0,
	1,0
]);
geometry.attributes.uv = new THREE.BufferAttribute(uv, 2);

法向量 - 顶点法向量光照计算

太阳光照在一个物体表面,物体表面与光线夹角位置不同的区域明暗程度不同。

法向量 用于根据光线与物体表面入射角,计算得到反射角(光从哪个角度反射出去)。光照和法向量的夹角决定了平面反射出的光照强度。
在这里插入图片描述

在Threejs中表示物体的网格模型Mesh的曲面是由一个一个三角形构成,所以为了表示物体表面各个位置的法线方向,可以给几何体的每个顶点定义一个方向向量,通过属性geometry.attributes.normal设置。

一个三角面只会有一个法向量。一个顶点会属于不同的三角面,因此一个顶点会有多个法向量。红色短线表示顶点法向量,绿色短线表示面法向量

在这里插入图片描述

案例1:不设置顶点法向量平面几何体与自带顶点法向量的平面几何体对比

1.准备两个平面几何,使用同一个材质。一个使用已经设置了法向量的PlaneGeometry创建,另一个使用默认没设置法向量的BufferGeometry创建

// 没设置法向量的BufferGeometry
const bufferGeometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
  -50, 50, 0, 
  50, 50, 0, 
  -50, -50, 0,
  50, -50,0
]);
bufferGeometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
const indices = new Uint16Array([0, 2, 1, 2, 3, 1]);
bufferGeometry.setIndex(new THREE.BufferAttribute(indices, 1));
const material = new THREE.MeshBasicMaterial({
  map: uvTexture,
});
const bufferPlane = new THREE.Mesh(bufferGeometry, material);
scene.add(bufferPlane);
bufferPlane.position.x = -100;
const uv = new Float32Array([
	0,1,
	1,1,
	0,0,
	1,0
]);
bufferGeometry.attributes.uv = new THREE.BufferAttribute(uv, 2);
// 自带法向量的PlaneGeometry
const planeGeometry = new THREE.PlaneGeometry(100, 100);
const planeMesh = new THREE.Mesh(planeGeometry, material);
scene.add(planeMesh);
planeMesh.position.x = 100;

2.给模型设置环境贴图后,可以将光反射的环境部分映射到模型上(类似镜子将人反射在镜子上面),法向量用于计算,光从哪里反射出去。

// 设置环境贴图
const loader = new THREE.TextureLoader();
loader.load("/assets/test.jpg",(envMap)=>{
  envMap.mapping = THREE.EquirectangularReflectionMapping;// 设置反射的方式
  material.envMap = envMap; // 设置环境贴图
  scene.background = envMap; // 将这幅图设置为环境(可选)
})

可以发现,没有法向量的平面几何体没有对光进行反射
在这里插入图片描述

案例2:设置法向量

方式1 computeVertexNormals方法

bufferGeometry.computeVertexNormals () 提供了计算顶点法向量的方法,所以只需要让BufferAttribute创建的平面几何体计算顶点法向量即可

const bufferGeometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
  -50, 50, 0, 
  50, 50, 0, 
  -50, -50, 0,
  50, -50,0
]);
bufferGeometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
const indices = new Uint16Array([0, 2, 1, 2, 3, 1]);
bufferGeometry.setIndex(new THREE.BufferAttribute(indices, 1));
const material = new THREE.MeshBasicMaterial({
  map: uvTexture,
});
const bufferPlane = new THREE.Mesh(bufferGeometry, material);
scene.add(bufferPlane);
bufferPlane.position.x = -100;
const uv = new Float32Array([
	0,1,
	1,1,
	0,0,
	1,0
]);
bufferGeometry.attributes.uv = new THREE.BufferAttribute(uv, 2);
bufferGeometry.computeVertexNormals(); // 增加

在这里插入图片描述

方式2:自定义normal属性值

本来矩形由2个三角形组成,也就是6个顶点。但有些顶点重复,为了复用我们也设置了顶点索引。所以这里的法向量也按照顶点索引来设置。

// 顶点索引 [0, 2, 1, 2, 3, 1]

const normals = new Float32Array([
  0, 0, 1,
  0, 0, 1,        
  0, 0, 1,
  0, 0, 1
])
bufferGeometry.setAttribute("normal", new THREE.BufferAttribute(normals, 3));
引入顶点法向量辅助器VertexNormalsHelper

语法:new VertexNormalsHelper( object : Object3D, size : Number, color : Hex, linewidth : Number )
object:要渲染顶点法线辅助的对象
size (可选的)箭头的长度,默认为 1
color 16进制颜色值. 默认为 0xff0000
linewidth (可选的) 箭头线段的宽度,默认为 1
继承链:Object3D → Line → VertexNormalsHelper

为了更方便调试,可以引入顶点法向量辅助器

import { VertexNormalsHelper } from 'three/addons/helpers/VertexNormalsHelper.js';

// 这里的参数是模型,不是几何体
const vertexNormalsHelper= new VertexNormalsHelper(bufferPlane, 8.2, 0xff0000);
scene.add(vertexNormalsHelper);

在这里插入图片描述

几何体的移动、旋转和缩放

BufferGeometry重写了Object3D的同名方法,几何变换的本质是改变几何体的顶点数据

在这里插入图片描述

方法描述
bufferGeometry.scale ( x : Float, y : Float, z : Float )从几何体原始位置开始缩放几何体
bufferGeometry.translate ( x : Float, y : Float, z : Float )从几何体原始位置开始移动几何体,本质改变的是顶点坐标
bufferGeometry.rotateX/rotateY/rotateZ( radians : Float )沿着对象坐标系(局部空间)的主轴旋转几何体,参数是弧度

移动几何体的顶点 bufferGeometry.translate

这里需要区分移动几何体的顶点和移动物体,一般情况下选择移动物体,当顶点本身就偏离需要将几何体中心移动到原点时选择移动几何体(消除中心点偏移)。

几何体的变换由于直接将最终计算结果设置为顶点坐标,所以很难追逐到是否发生了变换。

-使用描述
移动几何体的顶点bufferGeometry.translate ( x : Float, y : Float, z : Float )改变几何体的 ,geometry.attributes.position属性
移动物体object3D.position : Vector3移动对象的局部位置
  • 任何一个模型的本地坐标(局部坐标)就是模型的.position属性。
  • 一个模型的世界坐标,模型自身.position和所有父对象.position累加的坐标。

案例

const bufferGeometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
  -50, 50, 0, 
  50, 50, 0, 
  -50, -50, 0,
  50, -50,0
]);
bufferGeometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
const indices = new Uint16Array([0, 2, 1, 2, 3, 1]);
bufferGeometry.setIndex(new THREE.BufferAttribute(indices, 1));
const material = new THREE.MeshBasicMaterial();
const bufferPlane = new THREE.Mesh(bufferGeometry, material);
// 移动顶点
bufferGeometry.translate(50,0,0) 
scene.add(bufferPlane);
// 物体的局部坐标仍然在(0,0,0)  几何体的顶点坐标x轴都加了50
console.log(bufferPlane.position,bufferGeometry.attributes.position)

在这里插入图片描述

几何体平移与物体平移

几何体平移geometry.translate(50,0,0) 移动几何体
1.世界坐标没变化,还是(0,0,0)
2.本质是改变了顶点坐标
在这里插入图片描述

模型平移mesh.ttanslateX(50) 沿X轴移动50个单位
1.世界坐标变为(50,0,0)
2.对象坐标系(局部空间/几何对象坐标系)跟随,整体移动
在这里插入图片描述

几何体旋转与模型旋转(缩放同理)

-方法本质修改
几何体旋转bufferGeometry.rotateX( rad : Float)顶点坐标
物体旋转object3D…rotateX/.rotateY /.rotateZ ( rad : Float)rotation

几何体旋转

const bufferGeometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
  -50, 50, 0, 
  50, 50, 0, 
  -50, -50, 0,
  50, -50,0
]);
bufferGeometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
const indices = new Uint16Array([0, 2, 1, 2, 3, 1]);
bufferGeometry.setIndex(new THREE.BufferAttribute(indices, 1));
const material = new THREE.MeshBasicMaterial();
const bufferPlane = new THREE.Mesh(bufferGeometry, material);
// 几何体旋转
bufferGeometry.rotateX(Math.PI / 2);
scene.add(bufferPlane);
console.log(bufferPlane.rotation,bufferGeometry.attributes.position)

在这里插入图片描述
物体旋转

const bufferGeometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
  -50, 50, 0, 
  50, 50, 0, 
  -50, -50, 0,
  50, -50,0
]);
bufferGeometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
const indices = new Uint16Array([0, 2, 1, 2, 3, 1]);
bufferGeometry.setIndex(new THREE.BufferAttribute(indices, 1));
const material = new THREE.MeshBasicMaterial();
const bufferPlane = new THREE.Mesh(bufferGeometry, material);
// 物体旋转
bufferPlane.rotateX(Math.PI / 2) 
scene.add(bufferPlane);
console.log(bufferPlane.rotation,bufferGeometry.attributes.position)

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/405331.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第2讲:C语言数据类型和变量

第2讲:C语言数据类型和变量 目录1.数据类型介绍1.1字符型1.2整型1.3浮点型1.4 布尔类型1.5 各种数据类型的长度1.5.1 sizeof 操作符1.5.2 数据类型长度1.5.3 sizeof 中表达式不计算 2.signed 和 unsigned3.数据类型的取值范围4. 变量4.1 变量的创建4.2 变量的分类 5…

【前端素材】推荐优质后台管理系统Upcube平台模板(附源码)

一、需求分析 后台管理系统在多个层次上提供了丰富的功能和细致的管理手段,帮助管理员轻松管理和控制系统的各个方面。其灵活性和可扩展性使得后台管理系统成为各种网站、应用程序和系统不可或缺的管理工具。 当我们从多个层次来详细分析后台管理系统时&#xff0…

Conmi的正确答案——将JAVA中maven的.m2文件夹放到D盘

系统:WIN11 1、将.m2文件夹移动到D盘 移动后: 2、创建目录链接 mklink /j "C:\Users\Administrator\.m2" "D:\.m2"至此,maven默认的jar包会加载到D盘的.m2文件夹

C语言:数组的地址和数组首元素的地址的区别

数组的地址和数组首元素的地址在编译器上可能输出相同的地址 int main() {int arr[] { 1 };printf("%p\n", &arr);printf("%p\n", arr);return 0; }C和C等语言中,数组是一种复合数据类型,可以存储相同类型的多个元素。当我们谈…

重大更新:GPT-4 API 现全面向公众开放!

重大更新:GPT-4 API 现全面向公众开放! 在 AIGC(人工智能生成内容)领域内,我们一直致力于跟踪和分析如 OpenAI、百度文心一言等大型语言模型(LLM)的进展及其在实际应用中的落地情况。我们还专注…

类型转换(C++)

一、C语言中的类型转换 在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与 接收返回值类型不一致时,就需要发生类型转化,C语言中总共有两种形式的类型转换:隐式类型 …

Redis篇之缓存雪崩、击穿、穿透详解

学习材料:https://xiaolincoding.com/redis/cluster/cache_problem.html 缓存雪崩 什么是缓存雪崩 在面对业务量较大的查询场景时,会把数据库中的数据缓存至redis中,避免大量的读写请求同时访问mysql客户端导致系统崩溃。这种情况下&#x…

vite+ts+vue3项目配置

如何生成用户代码片段&#xff08;快捷生成代码&#xff09; 点击用户代码片段 新建全局代码片段&#xff0c;然后起个名字 {"vue": {"prefix": "vue","body": ["<template>"," <div class\"contai…

汽车大灯尾灯破裂修复用什么胶?

汽车大灯尾灯破裂可以使用硅酮玻璃胶或者环氧树脂胶进行修复。 硅酮玻璃胶的优点主要包括&#xff1a; 粘接力强&#xff1a;硅酮玻璃胶具有很强的粘接力&#xff0c;可以有效地将裂缝两侧的材料紧密粘合在一起。拉伸强度大&#xff1a;硅酮玻璃胶固化后形成的固体具有较高的…

2023最新盲盒交友脱单系统源码

源码获取方式 搜一搜&#xff1a;万能工具箱合集 点击资源库直接进去获取源码即可 如果没看到就是待更新&#xff0c;会陆续更新上 或 源码软件库 最新盲盒交友脱单系统源码&#xff0c;纸条广场&#xff0c;单独抽取/连抽/同城抽取/高质量盒子 新增功能包括心动推荐&#xff…

【深入理解设计模式】原型设计模式

原型设计模式 原型设计模式&#xff08;Prototype Pattern&#xff09;是一种创建型设计模式&#xff0c;它允许通过复制已有对象来创建新对象&#xff0c;而无需直接依赖它们的具体类。这种模式通常用于需要频繁创建相似对象的场景&#xff0c;以避免昂贵的创建操作或初始化过…

QT-串口工具

一、演示效果 二、关键程序 &#xff1a; #include "mainwindow.h" #include "ui_mainwindow.h"#include <QMessageBox>MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow),listPlugins(QList<TabPluginInt…

ESP8266智能家居(4)——开发APP基础篇

1.前期准备 安装好Android studio 开发环境 准备一台完好的安卓手机 手机要处于开发者模式 设置 --->关于手机---> 一直点击版本号 &#xff08;不同手机进入开发者模式的步骤可能不太一样&#xff09; 进入开发者模式后&#xff0c;找到辅助功能&#xff0c;打开开…

pytest结合Allure生成测试报告

文章目录 1.Allure配置安装2.使用基本命令报告美化1.**前置条件**2.**用例步骤****3.标题和描述****4.用例优先级**3.进阶用法allure+parametrize参数化parametrize+idsparametrize+@allure.title()4.动态化参数5.环境信息**方式一****方式二**6.用例失败截图1.Allure配置安装 …

ffmpeg深度学习滤镜

环境搭建 安装显卡驱动 当前所用显卡为NVIDIA的P6000,在英伟达的官网上查看对应的驱动, 下载NVIDIA-Linux-x86_64-535.104.05.run并安装。 sudo ./NVIDIA-Linux-x86_64-535.104.05.run 安装成功后用nvidia-smi命令后查看 安装的cuda版本不能超过12.2,选择安装cuda11.8。…

【k8s资源调度-Deployment】

1、标签和选择器 1.1 标签Label 配置文件&#xff1a;在各类资源的sepc.metadata.label 中进行配置通过kubectl 命令行创建修改标签&#xff0c;语法如下 创建临时label&#xff1a;kubectl label po <资源名称> apphello -n <命令空间&#xff08;可不加&#xff0…

day41WEB 攻防-通用漏洞XMLXXE无回显DTD 实体伪协议代码审计

本章知识点&#xff1a; 1 、 XML&XXE- 原理 & 发现 & 利用 & 修复等 2 、 XML&XXE- 黑盒模式下的发现与利用 3 、 XML&XXE- 白盒模式下的审计与利用 4 、 XML&XXE- 无回显 & 伪协议 & 产生层面 配套资源&#xff08;百度网盘&#x…

k8s-heml联动harbor 18

将打包的heml包上传到harbor仓库进行管理 创建一个公开的项目来接收传送的heml包 安装helm-push插件&#xff1a; helm plugin install https://github.com/chartmuseum/helm-push &#xff08;在线安装&#xff0c;要求网速要快或者提供科学上网&#xff09; 离线安装&…

【算法与数据结构】684、685、LeetCode冗余连接I II

文章目录 一、684、冗余连接 I二、685、冗余连接 II三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、684、冗余连接 I 思路分析&#xff1a;题目给出一个无向有环图&#xff0c;要求去掉一个边以后构成一个树&#xf…

ESP8266智能家居(5)——开发APP深入篇

1.代码解析 接下来重点介绍一下逻辑代码 这里面主要是设置mqtt服务器的IP地址和端口号&#xff0c;设置服务器的用户名和登录密码 绑定好订阅主题和发布主题&#xff08;和8266上的订阅、发布交叉就行&#xff09; 绑定界面&#xff0c;设置界面标题 绑定6个文本控件 将从mq…