Direct3D拾取

news2024/12/28 5:09:49

假设在屏幕上单击,击中的位置为点s=(x,y)。由图可以看出,用户选中了茶壶。但是仅给出点s,应用程序还无法立即判断出茶壶是否被选中。所以针对这类问题,我们需要采用一项称为“拾
取(Picking)”的技术。

茶壶和屏幕点s之间的一种联系是茶壶被投影到了一个包含了s的区域中。更准确地说,茶壶被投影到了投影窗口中一个包含点p(点P位于投影窗口中)的区域中,其中点P对应于屏幕中的点s

我们看到,如果自坐标原点发出一条拾取射线(picking ray)该射线将与那些其投影包围了点p的物体(即茶壶)相交。所以,一旦计算出了拾取射线,我们就可对场景中的每个物体进行遍历,并逐个测试射线是否与其相交,与射线相交的物体即为用户所拾取的物体。如果拾取射线不与场景中的任意物体相交,则用户便没有拾取到任何物体,而是选中了屏幕中的背景或些我们并不感兴趣的东西。

拾取原理步骤

  • 给定所单击的屏幕点s,求出它在投影窗口中的对应点P。
  • 计算拾取射线。即自坐标原点发出且通过点P的那条射线。
  • 将拾取射线和物体模型变换至同一坐标系中。
  • 进行物体/射线的相交判断。相交的物体即为用户所拾取的屏幕对象。

屏幕到投影窗口的变换

视口变换的矩阵

\begin{bmatrix} \frac{Width}{2} & 0 & 0 & 0\\ 0 & -\frac{Height}{2} & 0 & 0\\ 0 & 0 & MaxZ-MinZ & 0\\ X+\frac{Width}{2} & Y+\frac{Height}{2} & MinZ & 1 \end{bmatrix}(里面的参数为D3DVIEWPORT9中的参数)

对投影窗口中的点p=(p_{x},p_{y},p_{z})实施视口变换(将p放入1x4矩阵后与视口变换矩阵相乘),就得到了屏幕点s=(s_{x},s_{y})

s_{x}=p_{x}(\frac{Width}{2})+X+\frac{Width}{2}s_{y}=p_{y}(\frac{Height}{2})+Y+\frac{Height}{2}

视口变换之后z坐标并不作为2D图像的一部分进行存储,而是被保存在深度缓存中。解上面的方程后得到p_{x}=\frac{2s_{x}-2X-Width}{Width}p_{y}=\frac{-2s_{y}+2Y+Height}{Height}

假定视口的X和Y成员都为0(一般情况下如此,因为是相对父窗口的大小),这样就得到p_{x}=\frac{2s_{x}}{Width}-1p_{y}=\frac{2s_{y}}{Height}+1p_{z}=1

按照定义投影窗口与平面z=1重合,所以p_{z}=1,但是,至此我们还有一些工作要做。由于投影矩阵对投影窗口中的点进行了比例变换以模拟不同的视场,即呈现出近大远小的效果。为了反求出缩放之前该点的位置,我们必须对该点做一次比例变换的逆运算,设P为投影矩阵,由于项P_{00}P_{11}是该变换矩阵中对应于x和y坐标的比例系数(可根据投影矩阵转换反推得到),所以有
p_{x}=(\frac{2x}{viewporWidth}-1)(\frac{1}{P_{00}})p_{y}=(\frac{2y}{viewporWidth}+1)(\frac{1}{P_{11}})p_{z}=1

拾取射线的计算

射线可用参数方程p(t)=p_{0}+tu,其中p_{0}是射线的起点,它描述了射线的位置,u是一个描述了射线方向的向量,由15.2可看出射线的起点与坐标原点重合,所以p_{0}=(0,0,0),如果射线经过了投影窗口中的p点,则方向向量u为,u=p-p_{0}=(p_{x},p_{y},1)-(0,0,0)=p,则下面函数用于在给定屏幕坐标系中选定点的x和y坐标条件下,计算观察坐标系中的拾取射线。

struct Ray
{
	D3DXVECTOR3 m_origin;       //射线起点
	D3DXVECTOR3 m_direction;    //射线方向
};	

//通过给定屏幕坐标系中选定点(x,y),计算观察坐标系中拾取射线
d3d::Ray CalcPickingRay(int x, int y)
{
	float px = 0.0f;
	float py = 0.0f;

	//视口结构
	D3DVIEWPORT9 vp;
	Device->GetViewport(&vp);
	D3DXMATRIX proj;
	Device->GetTransform(D3DTS_PROJECTION, &proj);
	
	px = (((2.0f * x) / vp.Width) - 1.0f) / proj(0, 0);
	py = (((-2.0f * y) / vp.Height) + 1.0f) / proj(1, 1);
	
	d3d::Ray ray;
	ray.m_origin = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
	ray.m_direction = D3DXVECTOR3(px, py, 1.0f);
	return ray;
}

对射线进行变换

在上节中我们计算所得的拾取射线是在观察坐标系中描述的。为了进行射线/物体相交测试,射线
和物体必须位于同一坐标系中。我们并不打算将所有的物体都变换至观察坐标系中,这是因为将射线变换至世界坐标系甚至某个物体的局部坐标系往往更容易。

借助变换矩阵对其起点P_{0}和方向u分别进行变换,就实现了射线p(t)=p_{0}+tu的变换。注意,起点是按照来变换的,而方向是按照向量来变换的。本章的例程中实现了如下函数用于对射线进行变换。

void d3d::TransformRay(Ray* ray, D3DXMATRIX* T)
{
	//对起点进行变换 w=1
	D3DXVec3TransformCoord(&ray->m_origin, &ray->m_origin, T);
	//对方向进行变换 w=0
	D3DXVec3TransformNormal(&ray->m_direction, &ray->m_direction, T);
	D3DXVec3Normalize(&ray->m_direction, &ray->m_direction);
}

 

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

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

相关文章

谷歌竞价排名10个引爆利器揭秘分享-华媒舍

谷歌是目前世界上最受欢迎的搜索引擎之一,而竞价排名则是企业在谷歌平台上提升在线曝光度的重要手段。本文将介绍10个能够帮助企业轻松提高谷歌竞价排名的利器,让您的产品或服务脱颖而出。 第一利器:关键词优化 关键词优化是提升竞价排名的基…

Accelerate 0.24.0文档 一:两万字极速入门

文章目录 一、概述1.1 PyTorch DDP1.2 Accelerate 分布式训练简介1.2.1 实例化Accelerator类1.2.2 将所有训练相关 PyTorch 对象传递给 prepare()方法1.2.3 启用 accelerator.backward(loss) 1.3 Accelerate 分布式评估1.4 accelerate launch1.4.1 使用accelerate launch启动训…

垃圾/垃圾桶识别相关开源数据集汇总

垃圾箱图片数据集 数据集下载链接:http://suo.nz/3cvbiC 垃圾箱多类检测数据集 数据集下载链接:http://suo.nz/2eluH3 蒙得维亚的垃圾箱图片 数据集下载链接:http://suo.nz/2lRHLK 垃圾桶满溢检测数据集 数据集下载链接:http:…

PostgreSQL 入门教程

PostgreSQL 入门教程 1. 历史背景2. 概念3. 特点4. 用法4.1 数据库连接4.2 数据库创建4.3 表创建4.4 数据插入4.5 数据查询4.6 数据更新4.7 数据删除 5. 安装步骤6. 简单示例7. 扩展7.1 数据类型7.2 查询优化7.3 并发控制7.4 数据备份和恢复7.5 扩展性和高可用性7.6 安全性加固…

MATLAB中ginput函数用法

目录 语法 说明 示例 标识点和绘制坐标 返回用于选择坐标的按键 标识地理坐标区上的点 ginput函数的功能是标识坐标区坐标。 语法 [x,y] ginput(n) [x,y] ginput [x,y,button] ginput(___) 说明 [x,y] ginput(n) 可用于标识笛卡尔坐标区、极坐标区或地理坐标区内…

如何成功创建百度百科词条?教你从零开始创建自己的百度百科【建议收藏】

百度百科是一个开放的网络百科全书,用户可以自由编辑和贡献内容。如果你想创建一个百度百科页面,需要做好以下准备: 1.确定主题:选择一个你熟悉或者感兴趣的主题,确保该主题在百度百科上还没有相关的页面。 2.收集资…

数据结构 | 队列的实现

数据结构 | 队列的实现 文章目录 数据结构 | 队列的实现队列的概念及结构队列的实现队列的实现头文件,需要实现的接口 Queue.h初始化队列队尾入队列【重点】队头出队列【重点】获取队列头部元素获取队列队尾元素获取队列中有效元素个数检测队列是否为空销毁队列 Que…

通讯协议学习之路(实践部分):UART开发实践

通讯协议之路主要分为两部分,第一部分从理论上面讲解各类协议的通讯原理以及通讯格式,第二部分从具体运用上讲解各类通讯协议的具体应用方法。 后续文章会同时发表在个人博客(jason1016.club)、CSDN;视频会发布在bilibili(UID:399951374) 本文…

破解制造业痛点,数据化方案助力高效生产!

随着科技的飞速发展,我们已进入数据化时代。在这个时代,制造业面临着前所未有的挑战。本文将探讨制造业在当今数据化时代遇到的问题以及相应的解决方案。 一、背景 制造业作为全球经济发展的重要支柱,正面临着数据化带来的巨大变革。在这个以…

DP4301-M无线模块一款SUB-1G无线收发模块

DP4301-M无线模块是一款低成本高效率工作于1GHz以内的收发模块,支持中国智能电无线 集抄标准470MHz~ 510MHz,兼容433MHz ISM/SRD频段均可使用。 此模块且前已经超大量应用于国标智能无线抄表及物联网自组网等双向数据传输系统方案,模 块具备的…

数据恢复工具推荐,高效恢复,这4款很实用!

很多电脑用户都会选择将文件直接保存在电脑上,但是在实际的操作过程中,数据丢失的情况难免会出现。而实用的数据恢复工具或许能有效帮助我们找回丢失的数据。电脑上有哪些使用效果比较好的数据恢复工具呢? 今天小编总结了几款好用的工具&…

基于springboot实现生鲜超市管理的设计与实现系统【项目源码】

基于springboot实现生鲜超市管理的设计与实现系统演示 Java技术 Java是由Sun公司推出的一门跨平台的面向对象的程序设计语言。因为Java 技术具有卓越的通用性、高效性、健壮的安全性和平台移植性的特点,而且Java是开源的,拥有全世界最大的开发者专业社群…

SAP ABAP选择屏幕程序语法及实例

选择屏幕有单个栏位检索(PARAMETERS)和范围筛选(SELECT-OPTION)两种。 1、单个栏位检索(PARAMETERS) 语法: parameters[default ][lower case][obligatory] [as checkbox][radiobutton group…

2.jvm类加载系统

目录 概述类加载器执行顺序加载时机与过程类加载的四个时机一个类的一生 类加载途径 自定义类加载器工作准备编写自定义加载器结果 结束 概述 类加载器 jvm 的类加载是通过 ClassLoader 及其子类来完成的。 有以下类加载器 注意: bootstrap 引导程序 根据上图总结…

vue-组件注册及使用

​🌈个人主页:前端青山 🔥系列专栏:Vue篇 🔖人终将被年少不可得之物困其一生 依旧青山,本期给大家带来vue篇专栏内容-组件注册及使用 目录 1、组件的注册及使用 2、组件常用属性 2.1、directive 2.2、computed 2.…

删除快一年的数据,能够恢复吗?

在数字化时代,数据已经成为了企业和个人生活中不可或缺的一部分。然而,由于各种原因,我们有时会需要删除某些数据,比如过期的文件、无用的照片或者账号下的旧信息等。但是,当我们删除这些数据后,是否真的能…

一个车厢号码识别算法(2005年的老程序----ccc)

一个车厢号码识别算法(2005年的老程序----ccc) 2023-09-18 ccc 程序的识别效果 对图中的车厢号码部分用上下两条线限定分为,然后进行识别。 从上面的识别效果可以看出,识别算法具有一定的鲁棒性,能够适应车厢号码的各…

如何改变偏执的性格?

偏执不等同于固执和顽固,固执和顽固更多是好面子的因素,是自尊心的一种表现,而偏执更多是表示处于“不知”的心理状态。当然这里仅仅是讨论性格上的偏执,从性格的角度来分析,如果从精神角度来分析偏执那就比较严重了&a…

在以BUF,字节存储区中,存放有n个带符号整数。试编写统计其中负偶数个数(假设≤9)并且显示。

;默认认采用ML6.11汇编程序 DATAS SEGMENT;此处输入数据段代码BUF DB -2,2,3,4,-4N$-BUF DATAS ENDS STACKS SEGMENT;此处处输入堆栈段代码 STACKS ENDS CODES SEGMENTASSUME CS:CODES,DS: DATAS, SS:STACKS START:MOV AX, DATASMOV DS,AXMOV BX,0MOV CX,0 LOP: mov AX,[BX] RO…