WEB 3D技术 three.js 法向量演示性讲解

本文 我们来说法向
法向 又叫 法向量

就是 我们一个三维物体 顶点垂直于面 的方向 向量
在这里插入图片描述
他的作用 用来做光反射
根据光照的方向 根据面进行反射

我们上文写的这个代码

import './style.css'
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

//创建相机
const camera = new THREE.PerspectiveCamera(
    45, //视角 视角越大  能看到的范围就越大
    window.innerWidth / window.innerHeight,//相机的宽高比  一般和画布一样大最好
    0.1,  //近平面  相机能看到最近的距离
    1000  //远平面  相机能看到最远的距离
);
const scene = new THREE.Scene();
let uvTexture = new THREE.TextureLoader().load("/textUv.jpg");


const planeGeometry = new THREE .PlaneGeometry(1, 1);
console.log(planeGeometry);
const planeMaterial = new THREE.MeshBasicMaterial({
  map: uvTexture
})
const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);
scene.add(planeMesh);

const geometry  = new THREE.BufferGeometry();
console.log(geometry);
// 创建顶点数据
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, 0, 3, 2]);
const material = new THREE.MeshBasicMaterial({
    map: uvTexture,
    side: THREE.DoubleSide
})
const uv = new Float32Array([
    0, 0, 1, 0, 1, 1, 0, 1
])
geometry.setAttribute("uv", new THREE.BufferAttribute(uv, 2));
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
const cube = new THREE.Mesh(geometry, material);
cube.position.x = - 3
scene.add(cube)

//c创建一个canvas容器  并追加到 body上
const renderer = new THREE.WebGLRenderer(0);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

//设置相机位置   这里 我们设置Z轴  大家可以试试  S Y 和 Z  都是可以的
camera.position.z = 5;
//设置相机默认看向哪里   三个 0  代表 默认看向原点
camera.lookAt(0, 0, 0);
//将内容渲染到元素上
renderer.render(scene, camera);
const controls = new OrbitControls(camera, renderer.domElement);

function animate() {
    controls.update();
    requestAnimationFrame(animate);
    /*cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;*/
    renderer.render(scene, camera);
}
animate();

运行起来 然后打开控制台
会发现 我们通过 PlaneGeometry 创建的几何体 它是自带法向量的
在这里插入图片描述
但我们自己创建的这个平面 它是没有的
在这里插入图片描述
我们将代码更改如下

import './style.css'
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";

//创建相机
const camera = new THREE.PerspectiveCamera(
    45, //视角 视角越大  能看到的范围就越大
    window.innerWidth / window.innerHeight,//相机的宽高比  一般和画布一样大最好
    0.1,  //近平面  相机能看到最近的距离
    1000  //远平面  相机能看到最远的距离
);
const scene = new THREE.Scene();
let uvTexture = new THREE.TextureLoader().load("/textUv.jpg");


const planeGeometry = new THREE .PlaneGeometry(1, 1);
console.log(planeGeometry);
const planeMaterial = new THREE.MeshBasicMaterial({
  map: uvTexture,
  side: THREE.DoubleSide
})
const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);
scene.add(planeMesh);

const geometry  = new THREE.BufferGeometry();
console.log(geometry);
// 创建顶点数据
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, 0, 3, 2]);
const material = new THREE.MeshBasicMaterial({
    map: uvTexture,
    side: THREE.DoubleSide
})
const uv = new Float32Array([
    0, 0, 1, 0, 1, 1, 0, 1
])
geometry.setAttribute("uv", new THREE.BufferAttribute(uv, 2));
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
const cube = new THREE.Mesh(geometry, material);
cube.position.x = - 3
scene.add(cube)

//c创建一个canvas容器  并追加到 body上
const renderer = new THREE.WebGLRenderer(0);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

//设置相机位置   这里 我们设置Z轴  大家可以试试  S Y 和 Z  都是可以的
camera.position.z = 5;
//设置相机默认看向哪里   三个 0  代表 默认看向原点
camera.lookAt(0, 0, 0);
//将内容渲染到元素上
renderer.render(scene, camera);
const controls = new OrbitControls(camera, renderer.domElement);

let rgbeloader = new RGBELoader();
rgbeloader.load("/xhdr/Alex_Hart-Snow_Pano_2k.hdr",(texture) =>{
    scene.background = texture;
    texture.mapping = THREE.EquirectangularReflectionMapping;
    planeMaterial.envMap = texture;
    material.envMap = texture;
})

function animate() {
    controls.update();
    requestAnimationFrame(animate);
    /*cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;*/
    renderer.render(scene, camera);
}
animate();

这里 我们 RGBELoader引入环境贴图
然后 将我们两个材质都设置 envMap 为当前场景贴图

但明显 我们用PlaneGeometry创建的 有法向的几何体就可以反光
但我们自己写的这个几何体 并没有反射的一个效果
在这里插入图片描述
这边 问题就出在 我们自己创建的没有法向向量

这里 我们将代码改成这样

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, 0, 3, 2]);
const material = new THREE.MeshBasicMaterial({
    map: uvTexture,
    side: THREE.DoubleSide
})
const uv = new Float32Array([
    0, 0, 1, 0, 1, 1, 0, 1
])
geometry.setAttribute("uv", new THREE.BufferAttribute(uv, 2));
geometry.computeVertexNormals();
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
console.log(geometry);
const cube = new THREE.Mesh(geometry, material);
cube.position.x = - 3
scene.add(cube)

因为执行顺序的问题 换了一些代码的位置 主要还是 用几何体对象执行了 computeVertexNormals
这样 我们在运行代码
我们自己创建的这个几何体 它就有法向向量了
在这里插入图片描述
我们两个板就都有效果了
在这里插入图片描述
但好像只出来了一半 没事 除了computeVertexNormals 我们还可以自己去定义 normal的值
参考代码如下

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, 0, 3, 2]);
const material = new THREE.MeshBasicMaterial({
    map: uvTexture,
    side: THREE.DoubleSide
})
const uv = new Float32Array([
    0, 0, 1, 0, 1, 1, 0, 1
])
geometry.setAttribute("uv", new THREE.BufferAttribute(uv, 2));
const normals = new Float32Array([
    0, 0, 1,
    0, 0, 1,
    0, 0, 1,
    0, 0, 1
])
geometry.setAttribute("normal", new THREE.BufferAttribute(normals, 3));
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
console.log(geometry);
const cube = new THREE.Mesh(geometry, material);
cube.position.x = - 3
scene.add(cube)

这里 我们定义了一个数组
normals 对应四个角 我们都是 x和y都不管 面对x y的两个方向 反射不需要
就设置 z 就可以了 因为z是面对我们的方向 只要我们相机看得到这个反射效果就好了
然后将数组写入 normal 属性
运行结果如下
在这里插入图片描述
然后 为了我们能够更方便的调试 法向量 我们可以这样做

首先 我们需要在代码中导入

//导入顶点法向量辅助器
import { VertexNormalsHelper } from "three/examples/jsm/helpers/VertexNormalsHelper.js";

在这里插入图片描述
然后 我们可以随便找个地方这样写

const helper = new VertexNormalsHelper(cube, 8.2, 0xff0000);
scene.add(helper);

在这里插入图片描述
接受三个参数 第一个 你要看哪个几何体的法向量就给他传进去 第二个 辅助线的长度 第三个 辅助线的颜色
在这里插入图片描述
运行之后 我们的效果就出来了 x y 都没有 只有y轴一条真线

它能够帮助我们更直观的看到法向量效果

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

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

相关文章

数仓可视化5--superset的部署安装

1、superset简介 Apache Superset 是一个现代的数据探索和可视化平台。它功能强大且十分易用,可对接各种数据源,包括很多现代的大数据分析引擎,拥有丰富的图表展示形式,并且支持自定义仪表盘。 2、安装步骤 2.1、安装Miniconda3 …

GBASE南大通用 ADO.NET EntityFramework 实体框架支持

GBASE南大通用 ADO.NET 驱动支持 EntityFramework 实体框架。 实体框架,可以理解成微软的一个 ORM 产品,用于支持开发人员通过对概 念性应用程序模型编程(而不是直接对关系存储架构编程)来创建数据访问应 用程序,目…

RedHat8、Centos8无法启动网卡解决方案,网卡未加入托管

只针对部分情况,网卡未加入托管导致 虚拟机开启 ifconfig 没有ens33网卡,无法上网 手动启动网卡提示 Connection ens33 is not available on device ens33 because device is strictly unmanaged使用nmtui配置IP信息,无法启动’ens160’网卡…

LCR 174. 寻找二叉搜索树中的目标节点

解题思路: 二叉搜索树一般采用中序遍历(从小到大排列)。 class Solution {int res, cnt;public int findTargetNode(TreeNode root, int cnt) {this.cnt cnt;dfs(root);return res;}void dfs(TreeNode root) {if(root null) return;dfs(ro…

jmeter断言-三种

1.响应断言 substring是指包含就行 不用完全相等 2.json断言 3.持续时间断言

基于深度学习的PCB板缺陷检测系统(含UI界面、yolov8、Python代码、数据集)

项目介绍 项目中所用到的算法模型和数据集等信息如下: 算法模型:     yolov8 yolov8主要包含以下几种创新:         1. 添加注意力机制(SE、CBAM等)         2. 修改可变形卷积(DySnake-主干c…

Linux:apache优化(3)—— 页面缓存时间

作用:通过 mod_expires 模块配置 Apache,使网页能在客户端浏览器缓存一段时间,以避免重复请求,减轻服务端工作压力。启用 mod_expires 模块后,会自动生成页面头部信息中的 Expires 标签和 CacheControl 标签&#xff0…

AIGC年度回顾!2024向量数据库是否还是AI发展方向之一?

引言 2023 年,是 AI 技术大爆发的一年,从年初到年末,全球关心技术发展的人们见证了一次次的 AI 技术升级,也逐步加深着对 AGI 发展的畅想。而伴随着生成式人工智能的飞速发展,向量数据库以其独特的技术优势逐渐崭露头角…

char 和 varChar 的区别是什么?

大家好,我是伯约,这篇对大家有帮助的话求一个赞,另外文章末尾放了我从月入7k到现在3W的学习资料,大家可以去领一下(无偿)。 CHAR 和 VARCHAR 是最常用到的字符串类型,两者的主要区别在于&#x…

案例073:基于微信小程序的智慧旅游平台开发

文末获取源码 开发语言:Java 框架:SSM JDK版本:JDK1.8 数据库:mysql 5.7 开发软件:eclipse/myeclipse/idea Maven包:Maven3.5.4 小程序框架:uniapp 小程序开发软件:HBuilder X 小程序…

大文件快速传输解决办法汇总

在数据传输普及的当今时代,文件体量也在不断的突破它”大“的上线,很多企业也在面临着这类大文件快速传输的烦恼,而且这里面的“大”可不是一般意义的几M,几G的文件,它有可能上T级甚至是PB级别、TB级别的大文件,或者是…

LINUX加固之命令审计

一、前言 在LINUX安全范畴中,安全溯源也是很重要的一个环节。对主机上所有曾操作过的命令详细信息需要有一份记录保存,当系统遭受破坏或者入侵,拿出这份记录,可以帮助定位一些可疑动作。 很多系统通常都会配置安全堡垒机&#xff…

二、串行FLASH文件系统FatFs移植

经过上一节的分析,我们对文件系统有一定的理解了,这一节给大家介绍怎么把FatFs文件系统的这些代码移植到STM32S上,然后STM32利用这一些代码或者函数,以文件的格式对FLASH进行读写数据。 实则对diskio.c提供一些函数接口。 首先将…

企业内训系统源码开发实战:搭建实践与经验分享

本篇文章中,小编将带领读者深入探讨企业内训系统的源码开发实战,分享在搭建过程中遇到的挑战与解决方案。 一、项目规划与需求分析 通过对企业内训需求的深入了解,我们可以更好地定义系统架构和数据库设计。 二、技术栈选择 在内训系统开发…

2024年MySQL学习指南(三),探索MySQL数据库,掌握未来数据管理趋势

文章目录 前言7. DML- 增删改数据7.1 添加数据7.2 修改数据7.3 删除数据 8. DQL- 数据的查询操作8.1 基础查询1. 基础查询语法2. 基础查询练习 8.2 条件查询1. 条件查询语法2. 条件查询练习 8.3 排序查询1. 排序查询语法2. 排序查询练习 8.4 聚合函数1. 聚合函数语法2.聚合函数…

部署node.js+express+mongodb(更新中)

1-Linux服务器部署MongoDB 1.升级 yum -y update 2.下载MongoDB安装包 3.上传安装包 上传目录 : /usr/local/ 2-配置MongoDB环境变量并启动 1.配置环境变量全局启动 vi ~/.bash_profile 使用i命令进入编辑模式 添加: export PATH/usr/local/mongodb/bin:$P…

centos 8.0 安装sysbench 1.0.17

序号步骤说明执行命令执行结果备注1 下载并解压sysbench-1.0.17.zip sysbench-1.0.17.zip2安装依赖文件 yum install automake libtool -y yum install /usr/include/libpq-fe.h 3安装sysbench cd sysbench-1.0.17 ./autogen.sh ./configure \ --prefix/sysbench \ --with-pgsq…

Javaweb之Mybatis的基础操作之删除的详细解析

1.3 删除 1.3.1 功能实现 页面原型: 当我们点击后面的"删除"按钮时,前端页面会给服务端传递一个参数,也就是该行数据的ID。 我们接收到ID后,根据ID删除数据即可。 功能:根据主键删除数据 SQL语句 -- 删除…

C语言中关于strcpy函数的理解

strcpy的功能是将源指向的字符串复制到另外一个字符串中 目标指向的数组的大小应该要足够长&#xff0c;避免让源字符串中的数据溢出 关于这个函数的具体用法&#xff0c;我们可以看看下面这个程序 注意&#xff1a;strcpy函数的头文件是<string.h>&#xff0c;我们在用…

【科研绘图】Origin科研绘图超快速上手指南

Origin教程 Part 1:Origin界面介绍项目管理器graph文件工具栏文字工具箭头工具&#xff0c;直线工具 菜单栏文件新建导出 图图表绘制 Part 2:绘图实例讲解1.创建工程2.导入数据到book3.创建空Graph&#xff0c;设置画布尺寸4. 添加坐标系&#xff0c;设置坐标系的位置与尺寸5.添…