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

news2025/1/18 15:01:06

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

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

我们上文写的这个代码

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.coloradmin.cn/o/1357896.html

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

相关文章

自定义页面,落地页面自由搭配

自定义页面 路径 应用 >> 新增自定义页面 功能简介 应用内新增「自定义页面」。 自定义页面是一个可以自由配置的落地页面,支持通过不同的入口设置连接到不同的链接地址,使得不同的应用资源可以根据业务场景化的展示。 使用场景: 一…

基于OpenCV的图像缩放

基础概念 缩放是将图像的尺寸变小或变大的过程,即减少或增加原图像数据的像素个数,或者说通过增加或删除像素点来改变图像的尺寸; 基本原理:将分辨率(图片尺寸)为(w,h)的图像,缩放后其图像分辨…

Windows PowerShell的安全目标——安全警报

Windows PowerShell的安全目标——安全警报 1. 保证Shell安全 ​ 自从2006年年底PowerShell发布以来,微软在安全和脚本方面并没有取得很好的名声。毕竟那个时候,**VBScript和Windows Script Host(WSH)**是两个最流行的病毒和恶意软件的载体&#xff0c…

Hex2Bin转换工具文档、Bootloader 、OTA 、STM32等MCU适用

说明:这个工具可以将 Hex 文件 转换为 Bin 格式文件,软件是按自己开发 STM32 OAT 功能需求开发的一款辅助 上位机软件。 有兴趣的朋友可留言探讨。 附加功能: 1.另外可以生成指定大小的bin 格式文件,文件多余的空余位置填充随机…

word2019保存后的图片变模糊了怎么办?Word 2019 默认保存后压缩变模糊的问题,解决方案

Word 2019 默认保存后压缩变模糊的问题,解决方案 1,新建word 文件,插入一张原始图片,1080*1920,如下图: 2,保存时,word 2019默认选项,导致word 保存后,图片…

G1为什么更适合亿级流量系统以及YGC优化策略screenflow

大白话: 1.ParNew执行回收的时候,STW会比较长,CMS存在碎片化的问题,当物理机的内存变大,这套组合存在的问题会更大,加大物理内存,反而让垃圾回收更慢。 大白话: 之前讲过&#xff0c…

企业招聘信息查询API:招聘市场情报站,一键了解就业机会

前言 在当今这个信息爆炸的时代,快速、准确地获取企业招聘信息对于求职者来说至关重要。为了满足这一需求,企业招聘信息查询API应运而生,它为求职者提供了一个便捷、高效的平台,帮助用户快速了解企业的招聘动态。本文将详细介绍企…

箱体透明屏的原理

箱体透明屏的原理主要是通过特殊的结构设计,使得屏幕具有透光性,从而实现在显示内容的同时保持箱体的透明效果。具体来说,箱体透明屏采用镂空结构的设计,将灯条一根根的排列成透明状,使得屏幕整体看起来具有透明感。在…

【LeetCode】150. 逆波兰表达式求值(ASCII码)

今日学习的文章链接和视频链接 leetcode题目地址:150. 逆波兰表达式求值 代码随想录题解地址:代码随想录 题目简介 即将后缀表达式转换成中缀表达式并计算。 给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。 …

使用pnnx将Torch模型转换为ncnn

1. 引言 以往我们将Torch模型转换为ncnn模型,通常需经过Torch–>onnx,onnx–>ncnn两个过程。但经常会出现某些算子不支持的问题。 ncnn作者针对该问题,直接开发一个Torch直接转换ncnn模型的工具 (PNNX),以下为相关介绍及使…

【网络编程】——基于TCP协议实现回显服务器及客户端

个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【网络编程】【Java系列】 本专栏旨在分享学习网络编程的一点学习心得,欢迎大家在评论区交流讨论💌 目录 一、TCP实…

Spring——Spring基于注解的IOC配置

基于注解的IOC配置 学习基于注解的IOC配置&#xff0c;大家脑海里首先得有一个认知&#xff0c;即注解配置和xml配置要实现的功能都是一样的&#xff0c;都是要降低程序间的耦合。只是配置的形式不一样。 1.创建工程 1.1 pom.xml <?xml version"1.0" encoding…

卷积神经网络|导入图片

在学习卷积神经网络时&#xff0c;我们通常使用的就是公开的数据集&#xff0c;这里&#xff0c;我们不使用公开数据集&#xff0c;直接导入自己的图片数据&#xff0c;下面&#xff0c;就简单写个程序实现批量图片的导入。 import osfrom PIL import Imageimport numpy as np…

UI5与后端的文件交互(四)

文章目录 前言一、后端开发1. 新建管理模板表格2. 新建Function&#xff0c;动态创建文档 二、修改UI5项目1.Table里添加下载证明列2. 实现onClickDown事件 三、测试四、附 前言 这系列文章详细记录在Fiori应用中如何在前端和后端之间使用文件进行交互。 这篇的主要内容有&…

KNN 分类(选择最佳的 K 值,并可视化模型精度与 n_neighbors 的关系)

import matplotlib.pyplot as plt from sklearn.datasets import load_breast_cancer from sklearn.model_selection import train_test_split from sklearn.neighbors import KNeighborsClassifier# 导入乳腺癌数据集 cancer load_breast_cancer()# 划分训练集和测试集 X_tra…

CodeWave智能开发平台--03--目标:应用创建--02数据模型设计

摘要 本文是网易数帆CodeWave智能开发平台系列的第05篇&#xff0c;主要介绍了基于CodeWave平台文档的新手入门进行学习&#xff0c;实现一个完整的应用&#xff0c;本文主要完成数据模型设计 CodeWave智能开发平台的05次接触 CodeWave参考资源 网易数帆CodeWave开发者社区…

原版俄罗斯方块通关为啥这么难?

俄罗斯方块这款游戏相信很多人都玩过&#xff0c;其难易程度我们也见识过&#xff0c;近日看到一则新闻《美国13岁少年通关原版俄罗斯方块&#xff0c;此前只有AI做到过》&#xff0c;感叹世界之大&#xff0c;牛人太多。这款游戏诞生于上世纪八十年代&#xff0c;由苏联程序员…

嵌入式-stm32-基于HAL库的感应开关盖垃圾桶项目(开源)

网盘资料&#xff1a; 《嵌入式-stm32-基于HAL库的感应开关盖垃圾桶项目&#xff08;开源&#xff09;》 链接&#xff1a;https://pan.baidu.com/s/1kFk09nMKPDvLwIUqMT9q3w 提取码&#xff1a;og66 –来自百度网盘超级会员V6的分享 目录 一&#xff1a;项目概述 二&#xf…

PPT自带录屏大揭秘,一键提升演示文稿效果

在现代演示文稿制作中&#xff0c;屏幕录制是一种非常实用的功能&#xff0c;尤其是对于ppt演示而言。ppt提供了自带的屏幕录制功能&#xff0c;使用户能够直接在ppt中录制屏幕操作。本文将详细介绍ppt自带录屏的使用方法&#xff0c;帮助你在制作ppt演示时轻松实现屏幕录制。 …

速卖通商品详情 API(aliexpress.item_get):限制和要求

速卖通商品详情 API&#xff08;aliexpress.item_get&#xff09;的限制和要求主要包括以下几个方面&#xff1a; API调用频率限制&#xff1a;速卖通平台对商品详情 API 的调用频率有一定的限制&#xff0c;例如&#xff0c;每个账号每天最多可以调用多少次 API。如果超过了这…