概述及目录(版权所有,请勿转载,欢迎读者提出错误)

  之前用kanzi的3D UI引擎和cocos-2d的时候都有遇到过这个问题,就如何把3D场景中的XY平面的尺寸映射为与屏幕像素一一对应的,即XY平面上的一个单位对应平面上的一个像素。这个在3D UI开发过程中似乎并非必须,或者说很少有人这样用,因为在游戏场景中,UI可以处于场景的任何位置,并不局限于XY平面内。

  本次的分享总结所述的3D UI应用场景并非在游戏中,而是注重在GUI应用上(类似QT等),即使用3D绘图技术实现的一套类似2D UI一样效果的引擎,由于UI系统是3D的,故能实现3D的动画效果。把3D场景中的XY平面的尺寸映射为平面像素一一对应的优点,是能保持并延续我们在2D开发时候的习惯,方便精准地控制UI控件在整个屏幕上的位置布局。

  本文的重点是“3D UI场景中把XY平面的尺寸映射为屏幕像素”,因此需要您有如下的基本知识:

  1、基本3D数理知识;

  2、Opengl相关知识;

  3、对3D计算机图形学中“摄像机”概念有所了解;

  本文包括如下内容:

glm 3D数学库简介

  什么是3D数学库?

  所谓3D数学库,简单地说就是把在3D计算机编程中常用到的数据类型、数学函数、3D处理公式及方法等统一集中起来,方便我们在处理3D场景时使用。

  glm 3D数学库是Opengl官网推荐使用的,包含了几乎所有我们在处理3D场景是需要的数学函数。

  glm的使用也非常简单,glm提供的源码全部都是头文件,我们只需把glm的头文件引用到自己需要使用的工程中即可。

  如下实例代码中,我们通过glm创建了一个4x4的矩阵,并对该矩阵进行了平移变换(详细的glm使用介绍,大家可以参考glm官网的教程或文档)。

//示例代码 1.0 http://www.cnblogs.com/feng-sc/
#include <glm/glm.hpp> //注意: glm的工程路径需要自己配置
#include <glm/gtc/matrix_transform.hpp>
int main()
{
glm::mat4 matrix(1.0);
matrix = glm::translate(matrix, glm::vec3(100.0f, 0.0f, 0.0f));
return ;
}

  作为简介,glm的介绍就到此结束。

透视视锥体介绍

  所谓的透视不是你所想的眼睛能看穿墙的意思,别多想了!简单点,透视就是表示物体近大远小的效果的意思。

  如下图所示,透视视锥体梯体几何图形,它类似于人的眼睛所能看到的范围,在梯体之外的物体将不可见。

  在3D数学里,用什么表示这个透视视锥体呢?没错,是矩阵!

  使用glm函数库能简单地生成透视视锥体的矩阵,如下实例代码:

// 示例代码1.0: www.cnblogs.com/feng-sc/
// fovyInRadians : 弧度表示下图中FOV
// aspect : 视锥体宽与高的比例,可以理解为绘图区域的宽高比
// zNear : 近平面离摄像机的距离
// zFar :远平面离摄像机的距离
glm::mat4 projection = glm::perspective(fovyInRadians, aspect, zNear, zFar); 

(透视视锥体)

  上诉实例代码中,projection又被成为透视矩阵,所有3D世界里的物体,经过与projection矩阵相乘后,最终得到的物体将呈现如下两种特点:

  1、远小近大的效果;

  2、处于透视视锥外的物体将被忽略;

使用glm函数库生成摄像机矩阵

  本段我们先以一段代码起头,如下:

// 示例代码1.0: www.cnblogs.com/feng-sc/
glm::mat4 view = glm::lookAt(m_position, m_target, m_up);

  lookAt函数得到的结果是一个视图矩阵。有人把视图矩阵称为摄像机,也有人把视图矩阵和透视投影矩阵合在一起称为摄像机,我喜欢后者。

  结合投影矩阵,我们总结一下,摄像机分别由如下参数决定:

  1、透视投影矩阵projection决定了摄像机的视野范围,包括视觉张角FOV、近平面、远平面;

  2、视图矩阵决定了摄像机的位置、观察方向;

  最后投影矩阵与视图矩阵将共同决定我们整个场景的显示效果。

// 示例代码1.0 www.cnblogs.com/feng-sc/
glm::mat4 projection = glm::perspective(fovyInRadians, aspect, zNear, zFar);
glm::mat4 view = glm::lookAt(m_position, m_target, m_up);
glm::mat4 vpMat = projection * view

分析如何调整摄像机和透视视锥体,使的3D场景中的XY平面的尺寸与屏幕像素对应;

  OK,终于来到了本文标题讨论的问题点,3D UI场景中把XY平面的尺寸映射为屏幕像素。

  其实到现在为止,我们问题的解决方案也清晰了,如何实现“3D UI场景中把XY平面的尺寸映射为屏幕像素” 呢?是的,就是调整摄像机的位置、远/近平面、摄像机视角,使XY平面的单位尺寸恰好与平面像素的单位对应即可。

  那么现在剩下的问题是:如何调整摄像机,使得我们的XY平面恰好与平面像素对应呢?

  在我们继续之前,我们先来了解一个概念:齐次坐标。

  百度百科解释说:齐次坐标就是将一个原本是n维的向量用一个n+1维向量来表示。例如,二维点(x,y)的齐次坐标表示为(hx,hy,h)(h可以是任意值)。

  我们可以理解为,任何三维的点(hx,hy,h),在二维平面上的投影点均为(x,y)。

(透视视锥体侧面平面图)

  上图为透视视锥体侧面平面图,其中GI为透视视锥体的近平面,BF为远平面,LS和TZ分别为视锥体的两个不同位置的截面。

  从2D平截视锥体看,透视视锥体GBFI范围内的三维物体最后均被投影到GI平面上。由齐次坐标概念可知,点B、U、M在GI平面上的投影均为点M,同理点F、W、P在GI平面上的投影均为点I。

  我们:

   假设TZ平面为XY平面且与屏幕像素对应,屏幕高度像素为h,角∠BAF = FOV (FOV为摄像机张角)

   故,UW = h,UV = h/2;

   故,

    即,由屏幕宽度和摄像机张角,要使XY平面与屏幕像素对应,我们求得摄像机位置点距离XY屏幕距离长度为AV。

  下面的代码设置为屏幕左上角为原点是,摄像机的设置。

// 示例代码1.0 www.cnblogs.com/feng-sc/
float fov = ;
glm::perspective(glm::radians<float>(fov), (float)width / (float)height, 0.1f, 10000.0f);
float z = height / ( * tan(((float)(fov / 2.0)* glm::pi<float>()) / 180.0));
glm::vec3 positon((float)width / 2.0f, (float)height / 2.0f, -z);
glm::vec3 target((float)width / 2.0f, (float)height / 2.0f, 0.0f);
glm::vec3 up(0.0f, -1.0f, 0.0f);
m_view = glm::lookAt(positon target, up);

  

3D UI场景中,把XY平面的尺寸映射为屏幕像素的数学模型推导的更多相关文章

  1. 获取屏幕中某个点的RGB值与CAD屏幕像素值

    '获取CAD屏幕像素的比值 Function ViewScreen() As Double Dim ScreenSize As Variant ScreenSize = ThisDrawing.Get ...

  2. [Unity3D]Unity3D游戏开发3D选择场景中的对象,并显示轮廓效果强化版

    大家好,我是秦培,欢迎关注我的博客,我的博客地址blog.csdn.net/qinyuanpei. 在上一篇文章中,我们通过自己定义着色器实现了一个简单的在3D游戏中选取.显示物体轮廓的实例. 在文章 ...

  3. [Unity3D]Unity3D游戏开发之在3D场景中选择物体并显示轮廓效果

    大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei. 在<仙剑奇侠传>.<古剑奇谭>等游戏中,常常须要玩家在一个3D场景中 ...

  4. 3D游戏引擎中常见的三维场景管理方法

    对于一个有很多物体的3D场景来说,渲染这个场景最简单的方式就是用一个List将这些物体进行存储,并送入GPU进行渲染.当然,这种做法在效率上来说是相当低下的,因为真正需要渲染的物体应该是视椎体内的物体 ...

  5. Unity3D NGUI制作的Button放到场景中,按钮从2D变到3D

    通常我们使用Button都是在UI界面,即NGUI的摄像机下,如果想换到场景中,即不让按钮以UI形式显现,而是和场景中的物体一起随着摄像机移动而缩小,放大. 很简单,把Button从NGUi的摄像机中 ...

  6. 基于 HTML5 WebGL 的 3D 场景中的灯光效果

    构建 3D 的场景除了创建模型,对模型设置颜色和贴图外,还需要有灯光的效果才能更逼真的反映真实世界的场景.这个例子我觉得既美观又代表性很强,所以拿出来给大家分享一下. 本例地址:http://www. ...

  7. 3D场景中的鼠标响应事件

    原文:3D场景中的鼠标响应事件 今天要讲的是3D场景中的鼠标响应事件的处理,首先Button的响应是大家熟知的,只要加上一个click事件,然后写一个响应的处理时间就行了.对于二维平面上的一些控件也很 ...

  8. 如何在3D场景中在模型上面绘制摄取点

    有些时候,我们在屏幕上面绘制一个摄取点,在单屏玩游戏的模式下,我们并不能觉得有什么不妥.但是最近VR的热火朝天,我们带上眼镜看双屏的时候,总觉得这个摄取点看着很不舒服. 这个问题该怎么解决?在这里我首 ...

  9. 在WebGL场景中管理多个卡牌对象的实验

    这篇文章讨论如何在基于Babylon.js的WebGL场景中,实现多个简单卡牌类对象的显示.选择.分组.排序,同时建立一套实用的3D场景代码框架.由于作者美工能力有限,所以示例场景视觉效果可能欠佳,本 ...

随机推荐

  1. Solving SharePoint Server 2010 - 503. The service is unavailable, After installation

    Installed: SharePoint Server 2010 for Internet Enterprise Beta (x64) On: Windows Server 2008 Standar ...

  2. java并发:Condition的应用

    Condition类可以使线程等待,也可以唤醒线程.Condition类的await方法和Object类的wait方法等效Condition类的signal方法和Object类的notify方法等效C ...

  3. tf.unstack\tf.unstack

    tf.unstack 原型: unstack( value, num=None, axis=0, name='unstack' ) 官方解释:https://tensorflow.google.cn/ ...

  4. 【校招面试 之 C/C++】第15题 C 回调函数

    转自:https://segmentfault.com/a/1190000008293902 做略微改动 什么是回调函数 我们先来看看百度百科是如何定义回调函数的: 回调函数就是一个通过函数指针调用的 ...

  5. centos7装NVIDIA显卡驱动

    一.系统及显卡 系统:centos7.5 64位 显卡:gtx 1060 前几天主要是有一个人脸识别的项目测试,需要用到显卡去测试性能,然后装显卡的过程折腾了一下,特此记录. 二.安装过程 1. 下载 ...

  6. Swift 基本语法03-"if let"和"guard let"

    1. /// 如果JY_WINDOW有rootViewController, 并且rootViewController类型是AdvertisementViewController,就执行stopPla ...

  7. error: In function ‘void* opencv_showimg(void*)’:

    今天这个问题折磨了我一下午,终于知道是为什么了,心酸历程.....赶紧来记录一下 错误: /home/wj/workspace/Loitor_VI_Sensor_SDK_V1./SDK/src/cam ...

  8. tomcat用虚拟目录方式发布项目与manager页面配置

    conf/Catalina/localhost:指定项目的配置信息 1.添加:ROOT.xml 听见Context节点: <Context docBase="/usr/local/to ...

  9. DB2与oracle类型对比

    本文摘自http://www.cnblogs.com/cy163/archive/2010/11/17/1880280.html 做过DB2数据库应用迁移的工程师,了解IBM MTK工具在迁移过程中所 ...

  10. RNA-seq连特异性

    RNA-seq连特异性 Oct 15, 2015 The strandness of RNA-seq analysis 前段时间一直在研究关于illumina TrueSeq stranded RNA ...