WebGL模型视图投影矩阵

WebGL透视投影_山楂树の的博客-CSDN博客中的PerspectiveView代码一个问题是,我们用了一大段枯燥的代码来定义所有顶点和颜色的数据。示例中只有6个三角形,我们还可以手动管理这些数据,但是如果三角形的数量进一步增加的话,那可真就是一团糟了。幸运的是,对这个问题,确实还有更高效的方法。

仔细观察下图,你会发现左右两组三角形的大小、位置、颜色都是对应的。如果在虚线标识处也有这样3个三角形,那么将它们向X轴正方向平移0.75单位就可以得到右侧的三角形,向X轴负方向平移0.75单位就可以得到左侧的三角形。

利用这一点,我们只需按照下面的步骤,就能获得WebGL透视投影_山楂树の的博客-CSDN博客的效果了: 

1.在虚线处,即沿着Z轴准备3个三角形的顶点数据。

2.将其沿X轴正方向(以原始位置为基准)平移0.75单位,绘制这些三角形。

3.将其沿X轴负方向(以原始位置为基准)平移0.75单位,绘制这些三角形。

示例程序PerspectiveView_mvp就尝试这样做。 

PerspectiveView程序使用投影矩阵定义可视空间,使用视图矩阵定义观察者,而PerspectiveView_mvp程序又加入了模型矩阵,用来对三角形进行变换。

矩阵推导

我们有必要复习一下矩阵变换。请看之前编写的WebGL 视图矩阵、模型视图矩阵_山楂树の的博客-CSDN博客程序LookAtRotatedTriangles,该程序允许观察者从自定义的位置观察旋转后的三角形。等式1描述了三角形顶点的变换过程。

<视图矩阵>×<模型矩阵>×<顶点坐标>

后来的LookAtTriangles_ViewVolume程序(该程序修复了三角形的一个角被切掉的错误)使用等式2来计算最终的顶点坐标,其中投影矩阵有可能是正射投影矩阵或透视投影矩阵。 

<投影矩阵>×<视图矩阵>×<顶点坐标>

可以从上述两式推断出等式3

<投影矩阵>×<视图矩阵>×<模型矩阵>×<顶点坐标> 

等式3表示,在WebGL中,你可以使用投影矩阵、视图矩阵、模型矩阵这3种矩阵计算出最终的顶点坐标(即顶点在规范立方体中的坐标)。

如果投影矩阵为单位阵,那么等式3等式1就完全相同了;同样,如果模型矩阵为单位阵,那么等式3等式2就完全相同了。单位阵就像乘法中的1一样,它乘以任意一个矩阵,或者任意一个矩阵乘以它,得到的结果还是这个矩阵(程序中不设置投影矩阵所需的任一参数,默认参数所计算得到的矩阵可理解为1)。 

模型视图投影矩阵示例代码(PerspectiveView_mvp

var VSHADER_SOURCE ='attribute vec4 a_Position;\n' +'attribute vec4 a_Color;\n' +'uniform mat4 u_ModelMatrix;\n' +'uniform mat4 u_ViewMatrix;\n' +'uniform mat4 u_ProjMatrix;\n' +'varying vec4 v_Color;\n' +'void main() {\n' +'  gl_Position = u_ProjMatrix * u_ViewMatrix * u_ModelMatrix * a_Position;\n' +'  v_Color = a_Color;\n' +'}\n';var FSHADER_SOURCE ='#ifdef GL_ES\n' +'precision mediump float;\n' +'#endif\n' +'varying vec4 v_Color;\n' +'void main() {\n' +'  gl_FragColor = v_Color;\n' +'}\n';function main() {var canvas = document.getElementById('webgl');var gl = getWebGLContext(canvas);if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) return// 设置顶点坐标和颜色(蓝色三角形在前面)var n = initVertexBuffers(gl);gl.clearColor(0, 0, 0, 1);// 获取u_ModelMatrix、u_ViewMatrix和u_ProjectMatrix的存储位置var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');var u_ViewMatrix = gl.getUniformLocation(gl.program, 'u_ViewMatrix');var u_ProjMatrix = gl.getUniformLocation(gl.program, 'u_ProjMatrix');var modelMatrix = new Matrix4(); // 模型矩阵var viewMatrix = new Matrix4();  // 视图矩阵var projMatrix = new Matrix4();  // 投影矩阵// 计算视图矩阵和投影矩阵modelMatrix.setTranslate(0.75, 0, 0);  // 沿正x轴平移0.75个单位viewMatrix.setLookAt(0, 0, 5, 0, 0, -100, 0, 1, 0); // 视点、观察点、正方向projMatrix.setPerspective(30, canvas.width/canvas.height, 1, 100); // 视角、近截面宽高比、near、far// 将模型、视图和投影矩阵分别传递给统一变量gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix.elements);gl.uniformMatrix4fv(u_ProjMatrix, false, projMatrix.elements);gl.clear(gl.COLOR_BUFFER_BIT); gl.drawArrays(gl.TRIANGLES, 0, n); // 绘制右侧三角形// 为另一对三角形准备模型矩阵modelMatrix.setTranslate(-0.75, 0, 0); // 沿负x轴平移0.75个单位// 仅修改模型矩阵gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);gl.drawArrays(gl.TRIANGLES, 0, n);   // 绘制左侧三角形
}function initVertexBuffers(gl) {var verticesColors = new Float32Array([// 顶点坐标和颜色0.0,  1.0,  -4.0,  0.4,  1.0,  0.4, // 后面的绿色-0.5, -1.0,  -4.0,  0.4,  1.0,  0.4,0.5, -1.0,  -4.0,  1.0,  0.4,  0.4, 0.0,  1.0,  -2.0,  1.0,  1.0,  0.4, // 中间的黄色-0.5, -1.0,  -2.0,  1.0,  1.0,  0.4,0.5, -1.0,  -2.0,  1.0,  0.4,  0.4, 0.0,  1.0,   0.0,  0.4,  0.4,  1.0,  // 前面的蓝色-0.5, -1.0,   0.0,  0.4,  0.4,  1.0,0.5, -1.0,   0.0,  1.0,  0.4,  0.4, ]);var n = 9;var vertexColorbuffer = gl.createBuffer();  gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorbuffer);gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);var FSIZE = verticesColors.BYTES_PER_ELEMENT;var a_Position = gl.getAttribLocation(gl.program, 'a_Position');gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE * 6, 0);gl.enableVertexAttribArray(a_Position);var a_Color = gl.getAttribLocation(gl.program, 'a_Color');gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);gl.enableVertexAttribArray(a_Color);return n;
}

代码详解 

顶点着色器第9行实现了等式3

main()函数调用initVertexBuffers()函数(第27行),定义将要传给缓冲区对象的三角形顶点数据(第58行)。我们只定义了3个三角形,其中心都在Z轴上。而在PerspectiveView.js中,我们在Z轴两侧共定义了6个三角形。前面说过,这是因为这3个三角形将与平移变换结合使用。 

接着,我们获取了顶点着色器中u_ModelMatrix变量的存储地址(第30行),然后新建了模型矩阵modelMatrix对象(第34行),并根据参数将其计算出来(第39行)。此时,该模型矩阵会将三角形向X轴正方向平移0.75单位。

 除了计算模型矩阵(第39行),计算视图矩阵和投影矩阵的过程与PerspectiveView.js中一样。模型矩阵被传给u_ModelMatrix(第43行)并进行绘制,绘制了Z轴右侧的3个三角形(第48行)。

下面以相似的方式来绘制左侧的三角形:首先重新计算模型矩阵(第51行),使之将初始的三角形沿X轴负方向平移0.75单位。算出新的模型矩阵后,传给着色器,再调用gl.drawArrays()进行绘制,就画出了左侧的三角形。视图矩阵和投影矩阵不需要变化,不需要管它们。

如你所见,程序只使用了一套数据(3个三角形的顶点和颜色信息)就画出了两套图形(6个三角形)。这样做虽然减少了顶点的个数,但是增加了调用gl.drawArrays()的次数。哪一种方法更高效,或者如何在这两者之间平衡,依赖于程序本身和WebGL的实现。 

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

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

相关文章

如何在 Excel 中求平方根

需要在 Excel 中求一个数字的平方根吗?使用几个内置的 Excel 函数和公式可以轻松计算平方根。在本分步指南中,您将学习在 Excel 中计算平方根的 5 种不同方法,包括使用 SQRT 函数、POWER 函数、指数公式、VBA 代码和 Power Query。跟随教程&a…

项目知识点总结-分页(三)

后端分页查询接口&#xff1a; Controller Service&#xff1a; Mapper&#xff1a; //分页搜索会议的方法List<SearchMeeting> getAllSearchMeeting(Param("sm") SearchMeeting searchMeeting,Param("page") Integer page,Param("pageSize&q…

games101 作业2

题目 光栅化一个三角形 1. 创建三角形的 2 维 bounding box。 2. 遍历此 bounding box 内的所有像素&#xff08;使用其整数索引&#xff09;。然后&#xff0c;使用像素中心的屏幕空间坐标来检查中心点是否在三角形内。 3. 如果在内部&#xff0c;则将其位置处的插值深度值 (…

我学编程全靠B站了,真香(第一期)

你好&#xff0c;我是Martin。 我是就读于B站大学2020届的Martin同学&#xff0c;反正我学习计算机真的是全靠 B 站了。 我是个刷视频狂魔&#xff0c;B站收藏夹里也收藏了很多编程类视频&#xff0c; 比如C/C、Go语言、操作系统、数据结构和算法、计算机网络、数据库、Pyth…

Pytorch中张量矩阵乘法函数(mm, bmm, matmul)使用说明,含高维张量实例及运行结果

Pytorch中张量矩阵乘法函数使用说明 1 torch.mm() 函数1.1 torch.mm() 函数定义及参数1.2 torch.bmm() 官方示例 2 torch.bmm() 函数2.1 torch.bmm() 函数定义及参数2.2 torch.bmm() 官方示例 3 torch.matmul() 函数3.1 torch.matmul() 函数定义及参数3.2 torch.matmul() 规则约…

并查集与LRUCache

一)并查集 在一些应用问题中&#xff0c;需要将N个不同的元素划分成一些互不相交的集合&#xff0c;开始的时候&#xff0c;每一个元素自成一个单元素集合&#xff0c;然后按照一定的规律将归于同一组元素的集合进行合并&#xff0c;并且在此过程中需要反复使用到查询某一个元素…

使用grubby更改RHEL7/8/9的默认内核

使用grubby更改RHEL7/8/9的默认内核 验证默认内核版本获取当前默认内核的索引号检查所有内核的详细信息检查已安装的内核 更改默认内核引导条目使用索引号更改默认内核引导条目 验证默认内核版本 参考&#xff1a;https://linux.cn/article-16147-1.html # 验证默认内核版本 …

炫云云渲染3ds max效果图渲染教程

很多人在第一次使用炫云云渲染渲染效果图的时候不知道怎么使用&#xff0c;其实现在使用炫云渲染效果图真的很简单&#xff0c;我们一起来看看。 一客户端安装 1、打开炫云云渲染官网&#xff0c;点击右上角的客户端下载&#xff0c;选择炫云客户端&#xff08;NEXT版&#xf…

【JavaEE】多线程(三)

多线程&#xff08;三&#xff09; 续上文&#xff0c;多线程&#xff08;二&#xff09;&#xff0c;我们已经讲了 创建线程Thread的一些重要的属性和方法 那么接下来&#xff0c;我们继续来体会了解多线程吧~ 文章目录 多线程&#xff08;三&#xff09;线程启动 startsta…

华为云云耀云服务器L实例评测|cento7.9在线使用cloudShell下载rpm解压包安装mysql并开启远程访问

文章目录 ⭐前言⭐使用华为cloudShell连接远程服务器&#x1f496; 进入华为云耀服务器控制台&#x1f496; 选择cloudShell ⭐安装mysql压缩包&#x1f496; wget下载&#x1f496; tar解压&#x1f496; 安装步骤&#x1f496; 初始化数据库&#x1f496; 修改密码&#x1f4…

实验4 交换机端口隔离(access模式)

交换机端口隔离&#xff08;access模式&#xff09; 实验目的实验拓扑实验步骤&#xff08;1&#xff09;在未划分vlan前&#xff0c;配置pc1、pc2的地址&#xff0c;如图所示&#xff08;2&#xff09;测试两台pc机的连通性&#xff08;3&#xff09;创建vlan&#xff0c;并验…

Day66|图part5:130. 被围绕的区域、827.最大人工岛

130. 被围绕的区域 leetcode链接&#xff1a;题目链接 这题看起来很复杂&#xff0c;其实跟之前找飞地和找边缘地区的是差不多的&#xff0c;主要分三步&#xff1a; 使用dfs将边缘的岛都找出来&#xff0c;然后用A代替防止混淆&#xff1b;再用dfs找中间不与任何岛相连的飞地…

【码银送书第七期】七本考研书籍

八九月的朋友圈刮起了一股晒通知书潮&#xff0c;频频有大佬晒出“研究生入学通知书”&#xff0c;看着让人既羡慕又焦虑。果然应了那句老话——比你优秀的人&#xff0c;还比你努力。 心里痒痒&#xff0c;想考研的技术人儿~别再犹豫了。小编咨询了一大波上岸的大佬&#xff…

UDP与TCP报头介绍,三次握手与四次挥手详谈

先介绍我们UDP/TCP协议缓冲区 在UDP和TCP在数据传输和介绍时有有缓冲区概念的。 UDP缓冲区 UDP没有真正意义上的 发送缓冲区. 调用sendto会直接交给内核, 由内核将数据传给网络层协议进行后 续的传输动作; UDP具有接收缓冲区. 但是这个接收缓冲区不能保证收到的UDP报的顺序…

C语言天花板——指针(初阶)

&#x1f320;&#x1f320;&#x1f320; 大家在刚刚接触C语言的时候就肯定听说过&#xff0c;指针的重要性以及难度等级&#xff0c;以至于经常“谈虎色变”&#xff0c;但是今天我来带大家走进指针的奇妙世界。&#x1f387;&#x1f387;&#x1f387; 一、什么是指针&…

旋转角度对迭代次数的影响

( A, B )---3*30*2---( 1, 0 )( 0, 1 ) 让网络的输入只有3个节点&#xff0c;AB训练集各由5张二值化的图片组成&#xff0c;让A中有3个1&#xff0c;B中全是0&#xff0c;统计迭代次数并排序。 在3*5的空间内分布3个点有19种可能&#xff0c;但不同的分布只有6种 差值就诶够 …

七天学会C语言-第二天(数据结构)

1. If 语句&#xff1a; If 语句是一种条件语句&#xff0c;用于根据条件的真假执行不同的代码块。它的基本形式如下&#xff1a; if (条件) {// 条件为真时执行的代码 } else {// 条件为假时执行的代码 }写一个基础的If语句 #include<stdio.h> int main(){int x 10;…

硬件故障诊断:快速定位问题

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

Linux基础开发工具使用快速上手

软件包管理器 概念理解 在Linux下安装软件的话&#xff0c;一个比较原始的办法是下载程序的源代码&#xff0c;然后进行编译&#xff0c;进而得到可执行程序&#xff0c;然后就可以运行这个软件了。但是这种做法太麻烦了&#xff0c;于是就有些人把一些常用的软件提前编译好&…

笔记1.5:计算机网络体系结构

从功能上描述计算机网络结构 分层结构 每层遵循某个网络协议完成本层功能 基本概念 实体&#xff1a;表示任何可发送或接收信息的硬件或软件进程。 协议是控制两个对等实体进行通信的规则的集合&#xff0c;协议是水平的。 任一层实体需要使用下层服务&#xff0c;遵循本层…