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轴一条真线

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

R语言频率分布直方图绘制教程

本篇笔记分享R语言绘制直方图的方法,通过多种展示风格对数据进行可视化,主要用到ggplot、ggpubr等包。 什么是直方图? 直方图(Histogram),又称质量分布图,是一种统计报告图,由一系列高度不等的柱子表示数据…

【Java集合类篇】HashMap的数据结构是怎样的?

HashMap的数据结构是怎样的? ✔️HashMap的数据结构✔️ 数组✔️ 链表 ✔️HashMap的数据结构 在Java中,保存数据有两种比较简单的数据结构: 数组和链表(或红黑树)。 HashMap是 Java 中常用的数据结构,它实现了 Map 接口。Has…

STM32 CubeMX产生的程序架构

使用STM32CubeMX产生启动相关代码,配置各种外设。在后续程序开发过程中,有可能使用STM32CubeMX逐步产生使用的代码,为了将其产生的代码和我们程序隔离,一种可行的程序架构如下: 在此架构中,STM32CubeMX产生…

GraphQL和REST API的区别

我的新书《Android App开发入门与实战》已于2020年8月由人民邮电出版社出版,欢迎购买。点击进入详情 GraphQL(Graph Query Language)和REST(Representational State Transfer)是两种用于构建和设计API的不同方法。以下…

电脑屏幕一直闪烁怎么解决?三大妙招还你清晰视野

电脑屏幕闪烁一直是困扰用户的一个问题,它会影响到用户的使用体验,甚至可能导致眼睛疲劳和头痛。可是电脑屏幕一直闪烁怎么解决呢?在本文中,我们将介绍三个解决电脑屏幕闪烁的方法,从简单的软件调整到硬件检测&#xf…

亚马逊图片上传后变模糊怎么办?亚马逊图片优化指南—站斧浏览器

亚马逊图片上传后变模糊怎么办? 使用高分辨率图片:亚马逊建议卖家使用至少1000 x 1000像素的高分辨率图片。如果您上传的图片分辨率较低,亚马逊系统可能会将其自动调整为较小的尺寸,导致图片模糊。因此,确保您使用高质…

基于Java SSM框架实现宠物管理系统项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架实现宠物管理系统演示 摘要 随着我国经济的快速发展,人民生活水平的不断提高,宠物逐渐成为许多宠物爱好者的一种生活方式。 宠物的品种也越来越多样化,宠物不仅能给生活带来乐趣还可以成为空巢老人,独生子女很…

MongoDB批量写入操作

一、概述 MongoDB为客户端提供了批量执行写入操作的能力。批量写入操作影响单个集合。MongoDB允许应用程序确定批量写入操作所需的可接受确认级别。 db.collection.bulkWrite()方法提供了执行批量插入、更新和删除操作的能力。 MongoDB还支持通过db.col…

补码的乘法-布斯乘法

前言 本篇文章讲解如何通过逻辑门的形式来实现补码的乘法操作 布斯乘法 A.D.Booth提出了一种补码相乘算法,可以将符号位与数值位合在一起参与运算,直接得出用补码表示的乘积,且正数和负数同等对待。这种算法被称之为Booth (布斯)乘法 下面有两个变量值…

【量化金融】《证券投资学》吴晓求(第四版)(更新中)

这里写目录标题 第一篇 基本知识第1章 证券投资工具名词解释简答题 第2章 证券市场名词解释简答题 第二篇 基本分析第三篇 技术分析第四篇 组合管理第五篇 量化分析与交易策略 第一篇 基本知识 第1章 证券投资工具 名词解释 风险(risk) 未来结果的不…

【hcie-cloud】【16】业务上云迁移、Rainbow详述

文章目录 前言华为业务迁移解决方案概述业务上云背景概述业务迁移场景需求及挑战业务迁移的价值华为业务迁移解决方案 - 全景图华为业务迁移解决方案的优势 Rainbow迁移工具介绍Rainbow迁移原理介绍Rainbow迁移工具简介Rainbow迁移工具定位Rainbow迁移视图Rainbow迁移原理 - Wi…

JumpServer3.0版本-账号管理

账号列表 我这里已经创建好了所以有很多,可以点击资产树列表分类查看 点击创建按钮,添加账号 资产:如果多个设备的账号密码一致可以在资产同事选中 名称:方便辨识即可 用户名:登录设备的账户名 密码:按你登录需求自行选择 添加按钮旁边还有个“模版添加” 此功能便…

yolov8实战第五天——yolov8+ffmpg实时视频流检测并进行实时推流——(推流,保姆教学)

yolov8实战第一天——yolov8部署并训练自己的数据集(保姆式教程)_yolov8训练自己的数据集-CSDN博客 yolov8实战第三天——yolov8TensorRT部署(python推理)(保姆教学)-CSDN博客 今天,我们继续y…

Java TBA访问NetSuite Restlet时的403错误

本周有同学问为啥Java访问NetSuite Restlet时,按照知识会之前的文章分享,会一直报403 INVALID_LOGIN_ATTEMPT错误。 https://nk-community.blog.csdn.net/article/details/131399801https://nk-community.blog.csdn.net/article/details/131399801原因是…

线程同步之:QReadWriteLock

1、 使用互斥量QMutex时候存在一个问题 每次只能有一个线程获得互斥量的权限。如果在一个程序中有多个线程“读”取某个变量,使用互斥量时也必须排队! 然而,实际情况是允许:让多个线程同时“读”! 这样互斥量 就会降…

面试官:说说flexbox(弹性盒flex布局),以及适用场景?

面试官:说说flexbox(弹性盒布局模型),以及适用场景? 一、是什么 Flexible Box 简称 flex,意为”弹性布局”,可以简便、完整、响应式地实现各种页面布局 采用Flex布局的元素,称为flex容器conta…

面试官:线程池的7种创建方式,你都清楚吗?

文章目录 前言1. 固定数量的线程池a. 线程池返回结果b. ⾃定义线程池名称或优先级 2. 带缓存的线程池3. 执⾏定时任务a. 延迟执行(一次)b. 固定频率执行c. scheduleAtFixedRate VS scheduleWithFixedDelay 4. 定时任务单线程5. 单线程线程池6. 根据当前CPU⽣成线程池 前言 线程…

CRM管理系统八大特性,如何帮助企业提升业务效能?

CRM管理系统的使用率逐年上升,这离不开企业对客户的依赖——管理好客户关系是企业发展你的重要因素,由此可见CRM对于任何成长中的企业都是必不可少的。以前我们写过很多关于CRM功能的文章,这篇文章换个思路,想一想CRM管理系统主要…

Pytorch从零开始实战15

Pytorch从零开始实战——ResNeXt-50算法实战 本系列来源于365天深度学习训练营 原作者K同学 文章目录 Pytorch从零开始实战——ResNeXt-50算法实战环境准备数据集模型选择开始训练可视化总结 环境准备 本文基于Jupyter notebook,使用Python3.8,Pytor…

Unity中Shader序列图动画(UV流动的通用起始点)

文章目录 前言一、一般序列帧动画是按照序列图如下顺序读取的二、在Shader找到UV流动的起始点1、先实现纹理采样2、得到 uv 走格的单位格子大小3、定位到左上角为起始单位格 三、使UV流动的起始点通用化1、在属性面板接收 行 和 列的属性2、看图片可以总结出第一个单元格的公式…