filament渲染引擎中的坐标转换

文章目录

    • 背景
    • openGL中的坐标转换
      • 简单的概念介绍
    • 屏幕坐标转世界坐标
      • openGL的实现
      • filament通过射线拾取计算
      • filament官方给出的转换方式
      • filament实现坐标转换的QA
        • 1、View::pick()
        • 2、为什么filament的计算方式没有除以w分量?
        • 3、为什么别的资料上都是inverse(viewMatrix * projectionMatrix) ?
        • 4、怎么判断这个世界坐标是不是在模型上,也就是怎么判断是不是点击了模型?
    • 世界坐标转屏幕坐标
    • 矩阵运算

背景

模型渲染到屏幕上之后,鼠标点击屏幕,我们怎么知道是否点击了模型,点击了模型的哪个位置呢? 这些需求都需要坐标转换,常规来说就是从世界坐标系转换到屏幕坐标系,或者从屏幕坐标系转换到世界坐标系。

博主在渲染这块也是个新手,大家一起学习。
本文使用的是google的filament渲染引擎。

openGL中的坐标转换

提起坐标转换,就不得不提经典的openGL了,可以参考以下文章:
ModelMatrix、ModelViewMatrix、ProjectionMatrix、NormalMatrix模型矩阵、模型视图矩阵、投影矩阵、正规矩阵详解_妙为的博客-CSDN博客
经典渲染流程:
image.png
坐标转换流程:
image.png

简单的概念介绍

假定读者已经了解了基本的渲染知识,我们这里不做过多解释,毕竟不是重点。以下概念来源:OpenGL矩阵变换的数学推导-腾讯云开发者社区-腾讯云

  • 首先OpenGL有个世界坐标系,我们渲染的物体就是在世界坐标系中,我们的模型需要放到世界坐标系中,那么当我们还没放的时候,模型就和世界坐标系没有联系,它就还处于自己的坐标系中,我们叫做模型坐标系、局部空间、局部坐标系,也就是图中的LOCAL SPACE。
  • 当我们把模型放到世界坐标系中,模型就在世界坐标系里有了坐标,也就是原来在LOCAL SPACE中的那些坐标值,变成了世界坐标系中的坐标值,帮助我们完成这个变换的就是模型矩阵,对应图中的MODEL MATRIX,于是这样我们就把模型放到了世界坐标系WORLD SPACE中
  • 放到世界坐标系后,是不是就确定了我们渲染出来看到的样子?还没有,大家可以想像一下,我把一个东西放在世界坐标系的某个地方,我可以从近处看观察它,也可以从远处观察它,还可以从上下左右观察它,甚至还可以倒着观察它,因些还需要确定我们观察它的状态。OpenGL里帮我们虚拟出了一个Camera(特别注意,这里的Camera不是指我们硬件的Camera),从API的层面上看,我们只需要设置Camera的位置、朝向的点坐标、以及Camera的上方向向量就能将观察状态定下来,而这些设置最终会转换成OpenGL中的视图矩阵,对应图中的VIEW MATRIX -经过View Matrix的变换后,我们观察它的结果就确定了,图中是从距离它一定的距离、上往下观察它,这时候的点坐标就来到了视图坐标系下,对应图中的VIEW SPACE -这时候,我们能看到什么东西,基本已经确定了,不过还有一步投影变换,这是什么东西?大家想像一下,我们看到同一个东西,是不是通常都是近大远小?那么如何实现近大远小?就要靠投影变换,OpenGL提供正交投影和透视投影,正交投影没有近大远小的效果,不管在什么距离上看,都一样大,透视投影则有近大远小的效果,也是符合我们实际生活的一种效果,透视投影应用得比较多

还可以参考以下文章加深理解:
ModelMatrix、ModelViewMatrix、ProjectionMatrix、NormalMatrix模型矩阵、模型视图矩阵、投影矩阵、正规矩阵详解_妙为的博客-CSDN博客
[OpenGL]OpenGL坐标系及坐标转换-腾讯云开发者社区-腾讯云

屏幕坐标转世界坐标

openGL的实现

上面的图让我们知道了渲染的矩阵变换,从屏幕坐标到世界坐标其实就是反步骤来计算。例如顺序矩阵变化是viewMatrix * projectionMatrix,那么求逆就是inverse(viewMatrix * projectionMatrix) 了。
可以参考stack overflow的回答:https://stackoverflow.com/questions/46749675/opengl-mouse-coordinates-to-space-coordinates/46752492#46752492

通过逆矩阵的方式

mat4 inversePrjMat = inverse( prjMat );
vec4 viewPosH      = inversePrjMat * vec4(ndc_x, ndc_y, 2.0*depth - 1.0, 1.0)
vec3 viewPos       = viewPos.xyz / viewPos.w;

filament通过射线拾取计算

https://github.com/google/filament/discussions/5998?sort=new
这种是不使用官方的pick()函数,自己手写计算的射线拾取。这个issue主要存在的问题就是没有设置裁剪空间的w,并且也没有除以w。
射线拾取参考:屏幕坐标转世界坐标与射线生成

filament官方给出的转换方式

 /*** screen space coordinates in GL convention, this can be used to compute the view or* world space position of the picking hit. For e.g.:*   clip_space_position  = (fragCoords.xy / viewport.wh, fragCoords.z) * 2.0 - 1.0*   view_space_position  = inverse(projection) * clip_space_position*   world_space_position = model * view_space_position** The viewport, projection and model matrices can be obtained from Camera. Because* pick() has some latency, it might be more accurate to obtain these values at the* time the View::pick() call is made.*/

具体代码

// 1、获取clip_space_position
const Viewport& vp = view->getViewport();
float clip_space_x = (result.fragCoords.x / vp.width  - 0.5f) * 2.0f;
float clip_space_y = (result.fragCoords.y / vp.height - 0.5f) * 2.0f;
float clip_space_z = result.fragCoords.z * 2.0f - 1.0f;
float4 clip_space_position {clip_space_x, clip_space_y, clip_space_z, 1.0f};// 2、获取视图矩阵
mat4 projection = camera.getProjectionMatrix();
mat4 model = camera.getModelMatrix();
mat4 view_space_position = model * inverse(projection);
// 3、获取世界坐标系
float4 world_space_position = clip_space_position * view_space_position;

filament实现坐标转换的QA

1、View::pick()

View::pick()会有延迟,需要在pick()函数中获取模型矩阵,投影矩阵进行计算。在pick()函数外获取投影矩阵是不准确的,我踩的坑就是在pick()函数外获取的投影矩阵,在使用的时候发现矩阵变化了,导致inverse出来了inf和-nan等值。
inf 表示一个数超过了浮点类型所能表示的最大范围,通常为正无穷或负无穷。
nan 表示一个数不是一个合法的数字,通常出现在无法进行有效运算时。

2、为什么filament的计算方式没有除以w分量?

剪辑空间是齐次坐标系,转换成笛卡尔坐标系需要除以w,而我们设置的w是1.0,当缩放坐标的W为1时,坐标不会增大或缩小,保持原有的大小。所以,当W=1,不会影响到X,Y,Z分量的值。因此不影响最终结果。
什么是齐次坐标系?为什么要用齐次坐标系?

3、为什么别的资料上都是inverse(viewMatrix * projectionMatrix) ?

在filament中,viewMatrix = inverse(getModelMatrix()) ,所以:
inverse(viewMatrix * projectionMatrix) = inverse(viewMatrix) * inverse(projectionMatrix)
= getModelMatrix() * inverse(projectionMatrix)

参考:https://stackoverflow.com/questions/66160973/finding-world-position-of-element-in-screen-space
https://stackoverflow.com/questions/68870053/how-to-get-world-coordinates-from-the-screen-coordinates

4、怎么判断这个世界坐标是不是在模型上,也就是怎么判断是不是点击了模型?

filament中是通过pick()函数来实现的,获取到点击位置对应的实体,如果是模型的话,就可以获取到模型对应实体的name。底层是调用了driver.readPixels()方法来从渲染目标缓冲区中读取相应的像素信息,然后进行点击判断。

世界坐标转屏幕坐标

这部分的转换就是按照上面的渲染流程计算即可。

// 1、获取模型空间位置并将其转换为剪辑空间
vec4 clipSpacePos = projectionMatrix * (viewMatrix * vec4(point3D, 1.0));
// 2、从剪辑空间转换到标准化设备坐标空间(NDC 空间)
vec3 ndcSpacePos = clipSpacePos.xyz / clipSpacePos.w;
// 3、获取窗口位置
vec2 windowSpacePos = ((ndcSpacePos.xy + 1.0) / 2.0) * viewSize + viewOffset;

参考:https://stackoverflow.com/questions/8491247/c-opengl-convert-world-coords-to-screen2d-coords

矩阵运算

坐标转换离不开矩阵的运算,建议是再回头看看线性代数。。没时间系统的看的话,也可以先找一些网上的文章看看。以下几篇讲解的比较通俗,可以看看。
线性代数的秘密:矩阵相乘的本质是什么?
讲一点点数学:什么是矩阵?
线性代数的秘密:逆矩阵的意义是什么?(上)

模型矩阵,投影矩阵,视图矩阵的推导
OpenGL矩阵变换的数学推导-腾讯云开发者社区-腾讯云
屏幕坐标转世界坐标与射线生成

end

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

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

相关文章

idea开发Springboot出租车管理系统VS开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 springboot 出租车管理系统是一套完善的完整信息系统,结合springboot框架和bootstrap完成本系统,对理解JSP java编程开发语言有帮助系统采用springboot框架(MVC模式开发), 系统具有完整的源代码和数据…

(vue3)create-vue 组合式API

优势: 更易维护:组合式api,更好的TS支持 之前是选项式api,现在是组合式,把同功能的api集合式管理 复用功能封装成一整个函数 更快的速度 更小的体积 更优的数据响应式:Proxy create-vue 新的脚手架工…

计算机竞赛 深度学习OCR中文识别 - opencv python

文章目录 0 前言1 课题背景2 实现效果3 文本区域检测网络-CTPN4 文本识别网络-CRNN5 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 **基于深度学习OCR中文识别系统 ** 该项目较为新颖,适合作为竞赛课题方向,…

老卫带你学---leetcode刷题(124. 二叉树中的最大路径和)

124. 二叉树中的最大路径和 问题: 二叉树中的 路径 被定义为一条节点序列,序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。 路径和 是路径中各节点值的总…

【数据结构】单链表的基本操作(节点建立、插入删除)

1. 单链表的基本操作 1.1. 链表的定义1.2. 链表的创建(初始化) 1.2.1. 不带头结点的链表1.2.2. 带头结点的链表 1.3. 链表的插入和删除 1.3.1. 按位序插入 1.3.1.1. 带头结点1.3.1.2. 不带头结点 1.3.2. 指定节点的后插操作1.3.3. 指定元素的前插操作1.3…

外汇天眼:外汇交易一周最佳外汇交易日!

外汇市场运行24小时,但并非每时每刻都适合交易。本文将为您介绍一周中最佳外汇交易日,以及哪些时间段最适合参与外汇交易。 首先,值得注意的是伦敦时段通常是外汇市场最繁忙的时段。然而,即便如此,一周中仍有特定的日…

debian无法使用reboot 等系统命令解决

重启debian的时候,报错没有此命令 然后查看环境配置文件,发现没有debian 安装后没有自动添加环境变量。 1.首先编辑配置文件 nano /etc/profile2.在文件末尾添加如下内容 export PATH$PATH:/sbin/3.保存退出 CTRL O // 保存 ENTER // 回车确认文…

脚手架开发流程详解

开发流程 创建npm项目创建脚手架入口文件,最上方添加 #!/usr/bin/env/ node配置package.json,添加bin属性编写脚手架代码将脚手架发布到npm 使用流程 安装脚手架 npm install -g your-own-cli使用脚手架 your-own-cli脚手架开发难点解析 分包&…

c语言 - 实现每隔1秒向文件中写入当前系统时间

实现思路 主要是通过库函数和结构体获取当前系统时间(年月日和时分秒)保存到变量里,然后通过格式化输出函数将当前系统时间输出到文件中去。 但是需要注意的是题目要求每隔 1 s对系统时间进行输出,所以需要加入 sleep()函数进行调…

AOP执行的流程

Spring AOP是通过动态代理实现的,它在运行时通过生成代理对象来拦截和增强目标方法的执行。 具体运行流程如下: 1. 定义切面:使用Spring的AOP注解(如Aspect)定义切面类,标识切面的切点和通知。 2. 创建目…

computed和methods有什么区别

面试题:computed和methods有什么区别 标准而浅显的回答 在使用时,computed当做属性使用,而methods则当做方法调用computed可以具有getter和setter,因此可以赋值,而methods不行computed无法接收多个参数,而m…

二、浏览器--事件循环(也叫事件环,也叫event loop)--任务队列(等待执行的任务(存放的定时器,http,事件等进程))--渲染三者的关系

引用B站视频,搜索标题:【事件循环】【前端】事件原理讲解,超级硬核,忍不住转载 本视频总结: 超级复杂的JS底层。事件循环和事件队列的关系。宏任务、微任务和raf回调这3个事件队列的关系。任务队列和执行栈的关系。d…

rust类型转换

类型转换 类型转换分为隐式类型转换和显式类型转换。 隐式类型转换是由编译器完成的,开发者并未参与,所有又称自动强制转换。 显式类型转换是由开发者指定的,就是一般意义上的类型转换。 一、显式转换 (一)as 1.原生…

数据结构与算法之链表: 基于链表实现js中的原型链原理与算法实现 (Typescript版)

常见数据类型的原型链指向 obj -> Object.prototype -> nullfunc -> Function.prototype -> Object.prototype -> nullarr -> Array.prototype -> Object.prototype -> nullobj是Object实例func是Function实例,也是Object实例arr是Array实…

配置OSPFv3基本功能 华为笔记

1.1 实验介绍 1.1.1 关于本实验 OSPF协议是为IP协议提供路由功能的路由协议。OSPFv2(OSPF版本2)是支持IPv4的路由协议,为了让OSPF协议支持IPv6,技术人员开发了OSPFv3(OSPF版本3)。 无论是OSPFv2还是OSPFv…

设计模式2、抽象工厂模式 Abstract Factory

解释说明:提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。 简言之,一个工厂可以提供创建多种相关产品的接口,而无需像工厂方法一样,为每一个产品都提供一个具体工厂 抽象工厂(Abstra…

学校安全用电管理系统解决方案

随着科技的发展和进步,电力已成为我们日常生活和学习的重要支柱。然而,电力的使用也带来了一定的安全风险。特别是对于学校这个复杂而又活跃的环境,安全用电管理系统的角色显得尤为重要。 一、学校用电管理系统的现状 目前&#xff0…

win10默认浏览器改不了怎么办,解决方法详解

win10默认浏览器改不了怎么办,解决方法详解_蓝天网络 在使用Windows 10操作系统时,你可能会遇到无法更改默认浏览器的情况。这可能是因为其他程序或设置正在干扰更改。如果你也遇到了这个问题,不要担心,本文将为你提供详细的解决…

CSS基础

目录 一.CSS介绍 三种CSS的写法 1.内部样式 2.内联样式 3.外部表示 二.CSS选择器 1.标签选择器 2.类选择器 ​编辑 3.ID选择器 ​编辑 4.后代选择器 ​编辑 5.子选择器 6.并集选择器 7.伪类选择器 三.CSS常用属性值 1.字体设置 2.文本属性 1.文字颜色 2.文…

kafka 集群搭建 常用命令

1、集群搭建&#xff1a; <1> 将kafka 压缩包解压到某一目录 tar -zxvf kafka_2.12-3.5.1.tgz <2> 修改节点配置文件 vim config/server.properties broker.id0 log.dirs/tmp/kafka-logs <3> 将安装好的kafka 分发到其他服务器 scp -r kafka_2.12-2.4…