three.js 入门三:buffergeometry贴图属性(position、index和uvs)

2023-12-09 12:52

本文主要是介绍three.js 入门三:buffergeometry贴图属性(position、index和uvs),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

环境:

  • three.js 0.159.0

一、基础知识

  • geometry:决定物体的几何形状、轮廓;
  • material:决定物体呈现的色彩、光影特性、贴图皮肤;
  • mesh:场景中的物体,由geometrymateria组成;
  • texture:贴图,用于将一个jpg等格式的图片贴到material上面(当然,material也可以不贴texture);

另外,如果material上是定义的color,那么说明,物体是自发光的,不需要灯光就能看到,
materia如果整个是靠texture贴上去的,则需要光照才能看到它,最简单的是用环境光。

另外,对于一张图片,无论它有多大或多小,左下角是(0,0),右上角是(1,1),这就是uv,宽用u表示,高用v表示。

另外,无论一个物体形状有多复杂,其表面也可以分割成很多三角面。

下面使用的示例图片如下:

在这里插入图片描述

二、简单实例

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>* {margin: 0;padding: 0;box-sizing: border-box;}</style><script type="importmap">{"imports": {"three": "https://unpkg.com/three@0.159.0/build/three.module.js","three/addons/": "https://unpkg.com/three@0.159.0/examples/jsm/"}}</script>
</head><body><script type="module">import * as THREE from 'three';import { OrbitControls } from 'three/addons/controls/OrbitControls.js';let camera, scene, renderer;//基础对象camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);camera.position.set(50, 50, 50);camera.updateProjectionMatrix();renderer = new THREE.WebGLRenderer();renderer.setPixelRatio(window.devicePixelRatio);renderer.setSize(window.innerWidth, window.innerHeight);document.body.appendChild(renderer.domElement);const controls = new OrbitControls(camera, renderer.domElement);controls.minDistance = 5;controls.maxDistance = 300;controls.update()scene = new THREE.Scene();// 环境光const light = new THREE.AmbientLight(0x404040); // soft white lightscene.add(light);//坐标轴const axesHelper = new THREE.AxesHelper(5);scene.add(axesHelper);//准备geometry//点位var position = [10, 10, 0,10, 0, 0,0, 0, 0]//贴图var uvs = [1, 1,1, 0,0, 0,]        //构造geometrylet geometry = new THREE.BufferGeometry();geometry.setAttribute('position', new THREE.Float32BufferAttribute(position, 3));geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2));//加载贴图const texture = new THREE.TextureLoader().load('number.png');texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.repeat.set(1, 1);//准备materialconst material = new THREE.MeshBasicMaterial({side: THREE.DoubleSide,map: texture,transparent: true,opacity: 0.7,});//组成meshconst mesh = new THREE.Mesh(geometry, material);scene.add(mesh);function animate() {requestAnimationFrame(animate);renderer.render(scene, camera);}animate();</script>
</body></html>

效果如下:
在这里插入图片描述

三、探索贴图原理

先说上面示例:

  • position 表达了三个点位的坐标和顺序(看向-z轴,逆时针),此时面的法方向是 (0,0,-1);
  • uv 表达了position每个点位在贴图上的点;
  • 又因为,将material设为了透明和双面渲染,所以我们看向-z轴也是可以看到效果的(我们默认看到的效果其实是背面,可以将上面的 side: THREE.DoubleSide, 注释掉试试);

这里是否有一个疑问:怎么知道贴图的正面是朝向哪的呢?为什么这里是朝向+z轴,而不是-z轴呢?

其实,因为position和uv,webgl的插值计算只能将贴图的正面朝向+z轴,如下图示意:
在这里插入图片描述

四、考虑index作用

上面只是3个点位,所以仅用position和uv即可表达,但如果有很多点位,再这么写的话position会很多,而且很多都是重复的,
比如:立方体有8个点位,如果每个面分成两个三角面,那么总共需要24 = 6*2*3个点位坐标(每个3角面要3个点)。

此时使用index的写法:
position:8个点位
index: 列出每个三角面的点位序号, 共计 24 个元素
uv:和position一一对应

将上面示例中geometry部分改造如下:

//准备geometry
//点位
var position = [10, 10, 0,10, 0, 0,0, 0, 0,0, 10, 0,
]
//贴图
var uvs = [1, 1,1, 0,0, 0,0, 1,
]
//点位序号
var index = [0, 1, 2,0, 2, 3,
]        
//构造geometry
let geometry = new THREE.BufferGeometry();
geometry.setIndex(index);
geometry.setAttribute('position', new THREE.Float32BufferAttribute(position, 3));
geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2));

此时,我们看到的效果:
在这里插入图片描述

可以看到,我们仅用了4个点位,便描述了两个3角面。

五、看一个特殊的示例

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>* {margin: 0;padding: 0;box-sizing: border-box;}</style><script type="importmap">{"imports": {"three": "https://unpkg.com/three@0.159.0/build/three.module.js","three/addons/": "https://unpkg.com/three@0.159.0/examples/jsm/"}}</script>
</head><body><script type="module">import * as THREE from 'three';import { OrbitControls } from 'three/addons/controls/OrbitControls.js';let camera, scene, renderer;//基础对象camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);camera.position.set(50, 50, 50);camera.updateProjectionMatrix();renderer = new THREE.WebGLRenderer();renderer.setPixelRatio(window.devicePixelRatio);renderer.setSize(window.innerWidth, window.innerHeight);document.body.appendChild(renderer.domElement);const controls = new OrbitControls(camera, renderer.domElement);controls.minDistance = 5;controls.maxDistance = 300;controls.update()scene = new THREE.Scene();// 环境光const light = new THREE.AmbientLight(0x404040); // soft white lightscene.add(light);//坐标轴const axesHelper = new THREE.AxesHelper(5);scene.add(axesHelper);//准备geometry//点位var position = [10, 10, 0,10, 0, 0,0, 0, 0,]//贴图var uvs = [0, 1,1, 1,0, 0,]//点位序号var index = [0, 1, 2]//构造geometrylet geometry = new THREE.BufferGeometry();geometry.setIndex(index);geometry.setAttribute('position', new THREE.Float32BufferAttribute(position, 3));geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2));//加载贴图const texture = new THREE.TextureLoader().load('number.png');texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.repeat.set(1, 1);//准备materialconst material = new THREE.MeshBasicMaterial({side: THREE.DoubleSide,map: texture,transparent: true,opacity: 0.7,});//组成meshconst mesh = new THREE.Mesh(geometry, material);scene.add(mesh);function animate() {requestAnimationFrame(animate);renderer.render(scene, camera);}animate();</script>
</body></html>

效果如下:
在这里插入图片描述

六、最后看一个用立方体实现全景图预览的效果

效果图如下:
在这里插入图片描述

代码下载请看博文顶部。。。

这篇关于three.js 入门三:buffergeometry贴图属性(position、index和uvs)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/473802

相关文章

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

python删除xml中的w:ascii属性的步骤

《python删除xml中的w:ascii属性的步骤》使用xml.etree.ElementTree删除WordXML中w:ascii属性,需注册命名空间并定位rFonts元素,通过del操作删除属... 可以使用python的XML.etree.ElementTree模块通过以下步骤删除XML中的w:as

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

python3如何找到字典的下标index、获取list中指定元素的位置索引

《python3如何找到字典的下标index、获取list中指定元素的位置索引》:本文主要介绍python3如何找到字典的下标index、获取list中指定元素的位置索引问题,具有很好的参考价值,... 目录enumerate()找到字典的下标 index获取list中指定元素的位置索引总结enumerat

从入门到精通MySQL 数据库索引(实战案例)

《从入门到精通MySQL数据库索引(实战案例)》索引是数据库的目录,提升查询速度,主要类型包括BTree、Hash、全文、空间索引,需根据场景选择,建议用于高频查询、关联字段、排序等,避免重复率高或... 目录一、索引是什么?能干嘛?核心作用:二、索引的 4 种主要类型(附通俗例子)1. BTree 索引(

Redis 配置文件使用建议redis.conf 从入门到实战

《Redis配置文件使用建议redis.conf从入门到实战》Redis配置方式包括配置文件、命令行参数、运行时CONFIG命令,支持动态修改参数及持久化,常用项涉及端口、绑定、内存策略等,版本8... 目录一、Redis.conf 是什么?二、命令行方式传参(适用于测试)三、运行时动态修改配置(不重启服务

MySQL DQL从入门到精通

《MySQLDQL从入门到精通》通过DQL,我们可以从数据库中检索出所需的数据,进行各种复杂的数据分析和处理,本文将深入探讨MySQLDQL的各个方面,帮助你全面掌握这一重要技能,感兴趣的朋友跟随小... 目录一、DQL 基础:SELECT 语句入门二、数据过滤:WHERE 子句的使用三、结果排序:ORDE

Python打印对象所有属性和值的方法小结

《Python打印对象所有属性和值的方法小结》在Python开发过程中,调试代码时经常需要查看对象的当前状态,也就是对象的所有属性和对应的值,然而,Python并没有像PHP的print_r那样直接提... 目录python中打印对象所有属性和值的方法实现步骤1. 使用vars()和pprint()2. 使

CSS3中的字体及相关属性详解

《CSS3中的字体及相关属性详解》:本文主要介绍了CSS3中的字体及相关属性,详细内容请阅读本文,希望能对你有所帮助... 字体网页字体的三个来源:用户机器上安装的字体,放心使用。保存在第三方网站上的字体,例如Typekit和Google,可以link标签链接到你的页面上。保存在你自己Web服务器上的字