threejs之贴图原理

// 导入threejs
import * as THREE from "three";
// 导入轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

// 创建场景
const scene = new THREE.Scene();

// 创建相机
const camera = new THREE.PerspectiveCamera(
  45, // 视角
  window.innerWidth / window.innerHeight, // 宽高比
  0.1, // 近平面
  1000 // 远平面
);

// 创建渲染器
const renderer = new THREE.WebGLRenderer({
  antialias: true, // 抗锯齿
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 设置相机位置
camera.position.z = 15;
camera.position.y = 12;
camera.position.x = 12;
camera.lookAt(0, 0, 0);

// 添加世界坐标辅助器
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);

// 添加轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 设置带阻尼的惯性
controls.enableDamping = true;
// 设置阻尼系数
controls.dampingFactor = 0.05;
// 设置旋转速度
// controls.autoRotate = true;

// 渲染函数
function animate() {
  controls.update();
  requestAnimationFrame(animate);
  // 渲染
  renderer.render(scene, camera);
}
animate();

// 监听窗口变化
window.addEventListener("resize", () => {
  // 重置渲染器宽高比
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 重置相机宽高比
  camera.aspect = window.innerWidth / window.innerHeight;
  // 更新相机投影矩阵
  camera.updateProjectionMatrix();
});

// 创建纹理加载器
let textureLoader = new THREE.TextureLoader();
// 加载纹理
let texture = textureLoader.load("./texture/uv_grid_opengl.jpg");
texture.colorSpace = THREE.SRGBColorSpace;
texture.minFilter = THREE.LinearMipMapLinearFilter;

// 设置纹理包裹方式为 ClampToEdgeWrapping
texture.wrapS = THREE.ClampToEdgeWrapping;
texture.wrapT = THREE.ClampToEdgeWrapping;

const geometry = new THREE.BufferGeometry();
const plane = new THREE.Mesh(
  geometry,
  new THREE.MeshBasicMaterial({
    map: texture,
  })
);

let uv = new THREE.Float32BufferAttribute(
  [
    0,
    0, // 左下角顶点的UV坐标

    1,
    0, // 右下角顶点的UV坐标

    1,
    1, // 右上角顶点的UV坐标

    0,
    1, // 左上角顶点的UV坐标
  ],
  2
);
let position = new THREE.Float32BufferAttribute(
  [
    -5,
    -5, // 左下角顶点的UV坐标
    0,

    5, // 右下角顶点的UV坐标
    -5,
    0, 

    5,
    5, // 右上角顶点的UV坐标
    0,

    -5, // 左上角顶点的UV坐标
    5,
    0,
  ],
  3
);
const index = new THREE.Uint16BufferAttribute(
  [
    0,
    1,
    2, // 第一个三角形
    0,
    2,
    3, // 第二个三角形
  ],
  1
);

geometry.setIndex(index);
geometry.setAttribute('uv',uv)
geometry.setAttribute('position',position)
scene.add(plane);

uv的取值范围是从0到1的,uv的设置和position的设置顺序有关。在上述例子中position的设置是逆时针设置的,所以uv的设置也要逆时针设置才能正确取样。
在这里插入图片描述

在这里插入图片描述
接下来我们再把BufferGeometry替换成PlaneGeometry

// 导入threejs
import * as THREE from "three";
// 导入轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

// 创建场景
const scene = new THREE.Scene();

// 创建相机
const camera = new THREE.PerspectiveCamera(
  45, // 视角
  window.innerWidth / window.innerHeight, // 宽高比
  0.1, // 近平面
  1000 // 远平面
);

// 创建渲染器
const renderer = new THREE.WebGLRenderer({
  antialias: true, // 抗锯齿
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 设置相机位置
camera.position.z = 15;
camera.position.y = 12;
camera.position.x = 12;
camera.lookAt(0, 0, 0);

// 添加世界坐标辅助器
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);

// 添加轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 设置带阻尼的惯性
controls.enableDamping = true;
// 设置阻尼系数
controls.dampingFactor = 0.05;
// 设置旋转速度
// controls.autoRotate = true;

// 渲染函数
function animate() {
  controls.update();
  requestAnimationFrame(animate);
  // 渲染
  renderer.render(scene, camera);
}
animate();

// 监听窗口变化
window.addEventListener("resize", () => {
  // 重置渲染器宽高比
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 重置相机宽高比
  camera.aspect = window.innerWidth / window.innerHeight;
  // 更新相机投影矩阵
  camera.updateProjectionMatrix();
});

// 创建纹理加载器
let textureLoader = new THREE.TextureLoader();
// 加载纹理
let texture = textureLoader.load("./texture/uv_grid_opengl.jpg");
texture.colorSpace = THREE.SRGBColorSpace;
texture.minFilter = THREE.LinearMipMapLinearFilter;

// 设置纹理包裹方式为 ClampToEdgeWrapping
texture.wrapS = THREE.ClampToEdgeWrapping;
texture.wrapT = THREE.ClampToEdgeWrapping;

const geometry = new THREE.PlaneGeometry(10,10);
const plane = new THREE.Mesh(
  geometry,
  new THREE.MeshBasicMaterial({
    map: texture,
  })
);

scene.add(plane);

我们再来看看此时的position、uv、index设置:

position的取值如下:
{
    "itemSize": 3,
    "type": "Float32Array",
    "array": [
        -5,
        5,
        0,
        5,
        5,
        0,
        -5,
        -5,
        0,
        5,
        -5,
        0
    ],
    "normalized": false
}
uv取值如下:
{
    "itemSize": 2,
    "type": "Float32Array",
    "array": [
        0,
        1,
        1,
        1,
        0,
        0,
        1,
        0
    ],
    "normalized": false
}
index的取值如下:
{
    "itemSize": 1,
    "type": "Uint16Array",
    "array": [
        0,
        2,
        1,
        2,
        3,
        1
    ],
    "normalized": false
}

uv的值的顺序取决于position的设置顺序。比如position的设置顺序是从[-5,5,0]->[5,5,0]->[-5,-5,0]->[5,-5,0],所以uv的设置顺序是左上角->右上角->左下角->右下角

对于index的设置如果你按照逆时针的顺序定义顶点索引,渲染引擎会认为这是一个正面的三角形,会正确计算法线和光照效果。如果你按照顺时针的顺序定义顶点索引,渲染引擎会认为这是一个背面的三角形,可能会导致不正确的光照效果。但是texture会默认flipY为true,所以我们看到的是逆时针的,其实本来是顺时针。

在这里插入图片描述
如果我们设置为顺时针,看到正面其实是没有图像的,因为图像在反面。
在这里插入图片描述
可以看出z轴是背向我们的。
在这里插入图片描述
geometry.setIndex(new THREE.Uint16BufferAttribute([0,1,2,2,3,1],1)),如果我们设置index的值为一半顺时针,一半逆时针那么就会出现正面有一半反面有一半,我们始终只能看到一半。
z轴朝向我们是正面。
在这里插入图片描述
z轴背对我们是反面。
在这里插入图片描述

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

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

相关文章

ATFX汇市:日本央行终于启动加息,负利率政策宣告终结

ATFX汇市:3月19日,日本央行利率决议宣布,将基准利率从-0.1%提高至0~0.1%,这是日本央行2007年3月份以来的首次加息,结束了2016年以来的负利率政策。日本央行还宣布,在保持长期国债月购买额基本不变的前提下&…

神经网络介绍

神经网络是由若干神经元相互连接而成,如下图所示: 以数学公式的形式将神经元串联起来, 串联的神经元似乎只有传递的作用,那么 一根和多根似乎没有区别。𝑧1 _𝑏1 _𝑤11(𝑏1 &…

Java-SpringAop 编程式事物实现

SpringAop 编程式事物实现 1. 数据库事物特性 原子性 多个数据库操作是不可分割的,只有所有的操作都执行成功,事物才能被提交;只要有一个操作执行失败,那么所有的操作都要回滚,数据库状态必须回复到操作之前的状态 …

力扣1. 两数之和

思路:用一个map存放 已遍历过的元素和下标; 若当前元素是nums[i], 且该元素的另一半 target-nums[i] 在已遍历过的map里面,则返回两个元素的下标; class Solution {public int[] twoSum(int[] nums, int target) {int[] ans new…

C++ 离散与组合数学之多重集合

1. 前言 数论是计算机学科的基础,将以一系列文章讨论组合数学中的一些概念,包括多重集合、等价类、多重集上的排列、错排列、圆排列、鸽巢原理、二项式定理、容斥原理、卡特兰数。 本文主要是讨论集合以及多重集合的概念以及多重集合上的排列问题。集合…

开发微信小程序被鹅厂背刺

最近在开发微信小程序,没来得及更文。等开发完成后,给大家写保姆帖系列。刚刚看到一张动图,忍不住分享给大家。属实反映了鹅厂风格了。

文件上传基础篇

文件上传基础篇 文件上传漏洞原理 ​ 目标网站存在文件上传接口,但是对用户上传的文件没有做仔细甄别,导致黑客可以根据此功能点直接上传木马到网站服务器,造成危害 文件上传存在点 ​ 通常有头像上传,pdf上传 文件上传防护 …

Word为图表设置图注并在图表清单中自动生成

1如果需要自动插入题注,请不要自己为文件增加新的标题样式或删除自带的标题1样式 2章节大标题最好是标题1,2,3而不要设置标题一、二、三,否则图例在自动生成时会显示 图一 -1,调整起来会非常不方便 若实在要使用大写中文标题&…

【隐私计算实训营-001数据可信流通,从运维信任到技术信任】

1. 数据可信流通体系 信任的基石: 身份的可确认利益可依赖能力有预期行为有后果 2.内循环——>外循环 内循环:数据持有方在自己的运维安全域内队自己的数据使用和安全拥有全责。 外循环:数据要素在离开持有方安全域后,持有方…

FX-数组的使用

1一维数组 1.1一维数组的创建和初始化 1.1.1数组的创建 //代码1 int arr1[10]; char arr2[10]; float arr3[1]; double arr4[20]; //代码2 //用宏定义的方式 #define X 3 int arr5[X]; //代码3 //错误使用 int count 10; int arr6[count];//数组时候可以正常创建&#xff1…

【Linux】进程排队的理解进程状态的表述僵尸进程和孤儿进程的理解

一、进程排队的理解 进程不是一直运行的,进程可能会在等待某种软硬件资源。即使把进程加载到CPU中,也不是一直会运行的。而进程排队,一定是在等待某种软硬件资源(可以是CPU,键盘,磁盘,网卡等等设…

Android Studio实现内容丰富的安卓图书馆座位图书预约系统

获取源码请点击文章末尾QQ名片联系,源码不免费,尊重创作,尊重劳动 项目编号109 1.开发环境android stuido jdk1.8 eclipse mysql tomcat 2.功能介绍 安卓端: 1.注册登录 2.查看公告 3.查看图书馆座位 4.查看图书馆图书&#xff0c…

k8s详细教程

Kubernetes详细教程 1. Kubernetes介绍 1.1 应用部署方式演变 在部署应用程序的方式上,主要经历了三个时代: 传统部署:互联网早期,会直接将应用程序部署在物理机上 优点:简单,不需要其它技术的参与 缺点…

《1w实盘and大盘基金预测 day7》

昨日预测有点差劲,最低点也相差五个点。 打分C 公众号:JavaHelmet 昨天预测: 3052-3062-3076-3115 3067是趋势线,有回踩需求 5-30-60分钟级别顶钝 大盘冲到标红的点位3115或者3100就需注意。不要随意追高(最高309…

第四百一十一回

文章目录 1. 概念介绍2. 思路与方法2.1 实现思路2.2 实现方法 3. 示例代码4. 内容总结 我们在上一章回中介绍了"给geolocator插件提交问题的结果"相关的内容,本章回中将介绍自定义标题栏.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我…

蓝桥杯备赛_python_DFS搜索算法_刷题学习笔记

1.是什么 沿着一条路径一直搜索下去,在无法搜索时,回退到刚刚访问过的节点。并且每个节点只能访问一次。本质上是持续搜索,遍历了所有可能的情况,必然能得到解。 流程是一个树的形式,每次一条路走到黑。 目的主要是达到…

哈尔滨工业大学 《材料物理》 笔记-3

原内容请参考哈尔滨工业大学何飞教授:https://www.bilibili.com/video/BV18b4y1Y7wd/?p12&spm_id_frompageDriver&vd_source61654d4a6e8d7941436149dd99026962 或《材料物理性能及其在材料研究中的应用》(哈尔滨工业大学出版社) 量…

杨氏矩阵的查找(复杂度<O(N))

题目: 解释:时间复杂度小于O(N)即不要一个一个的去遍历查找。 思路: 一个33的二维数组如图所示: 一:先找到一个最关键的数字,3(下标为0,2) 关键数的关键之处在于(处于…

【Unity】从0到1的横版2d制作笔记-DAY1

写在前面: 感谢旻子提供的Unity2d课程捏,红豆泥阿里嘎多 创建项目 测试Visual Studio的使用 右键选择【create】,右键创建C# Script,待文件创建完毕后双击查看能否正确跳转。 正确跳转的结果是能看见代码中注释标注有:…

15届蓝桥杯第二期模拟赛所有题目解析

文章目录 🧡🧡t1_求余🧡🧡思路代码 🧡🧡t2_灌水🧡🧡思路代码 🧡🧡t3_字符显示🧡🧡思路代码 🧡🧡t4_区间最大和…