ThreeJS 屏幕坐标与世界坐标互转
文章目录
- 屏幕坐标系和标准设备坐标
- 屏幕坐标转世界坐标
- 世界坐标转屏幕坐标
要理解坐标系间的转换过程,需要提前了解:
- ThreeJS 中的几种坐标系
- 屏幕坐标系和标准设备坐标系
不想看链接中的内容这边也有不规范的简述:
物体的坐标转换过程大致为:局部坐标 -> 世界坐标 -> 观察空间坐标 -> 裁剪空间坐标 -> 屏幕空间坐标
我们将 观察空间坐标系 和 裁剪空间坐标系 之间的转换统一处理,最终得到 标准设备坐标系
因此坐标转换过程就变成了:局部坐标 -> 世界坐标 -> 标准设备坐标 -> 屏幕空间坐标
原本世界坐标转换到观察空间坐标需要乘上视图矩阵 CameraMatrixWorldInverse(ViewMatrix)
随后,观察空间坐标转换到裁剪空间坐标需要乘上相机投影矩阵:ProjectMatrix
在 ThreeJS 中有一个方法 Vector3.project(camera)
综合了这两步:
project( camera ) {return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix );
}
屏幕坐标系和标准设备坐标
ThreeJS 是使用了 canvas
画布绘制图形的,因此屏幕坐标系就是 canvas
中的坐标系,也就是左上角是坐标原点:
在 ThreeJS 中,一个物体可看作一个 Mesh
,Mesh
的坐标是用一个 Vector3
来表示的,Vector3
中包含了 x
、y
、z
坐标。
空间坐标系是三维的,其原点默认在屏幕中心,且 x y z
的范围是 [-1,1]
,因此其 x
、y
轴在屏幕坐标系中的表示就是:
屏幕坐标转世界坐标
屏幕坐标转空间坐标需要经过两个步骤:屏幕坐标 -> 标准设备坐标 -> 世界坐标
ThreeJS 中,画布一般是全屏的,因此画布的宽高 w,h
就是:window.innerWidth
和 window.innerHeight
,所以 Three 的空间坐标系中点 (cx, cy)
在屏幕坐标系中就是:(w / 2,h / 2)
。
(根据情况,有时候宽高会是 canvas.offsetWidth
和 canvas.offsetHeight
)
假设 canvas
中有一点 (x,y)
,这个点在空间坐标系中为 (x1,y1)
,那么这个转换公式是:
x1=(x/w)∗2−1x1 = (x / w) * 2 - 1 x1=(x/w)∗2−1
y1=−(y/h)∗2+1y1 = -(y / h) * 2 + 1 y1=−(y/h)∗2+1
公式推导过程如下:
首先,我们知道了空间坐标系中点在屏幕坐标系中的表示:cx=w/2cx = w / 2cx=w/2,cy=h/2cy = h / 2cy=h/2
那么,屏幕坐标系中的点 (x,y)(x, y)(x,y) 应用这个原点 (cx,cy)(cx, cy)(cx,cy) 后的表示为:x′=x−cxx' = x - cxx′=x−cx,y′=cy−yy' = cy - yy′=cy−y (因为这两个坐标系的
y
轴方向是相反的)然后再将 (x′,y′)(x', y')(x′,y′) 标准化到 [−1,1][-1, 1][−1,1] 之间,也就是分别除以 cxcxcx 、cycycy :
x′cx=x−cxcx=xw2−1=(x/w)∗2−1\frac{x'}{cx} = \frac{x - cx}{cx} = \frac{x}{\frac{w}{2}} - 1 = (x / w) * 2 - 1 cxx′=cxx−cx=2wx−1=(x/w)∗2−1
同理:
y′cy=cy−ycy=1+−yw2=−(y/h)∗2+1\frac{y'}{cy} = \frac{cy - y}{cy} = 1 + \frac{-y}{\frac{w}{2}} = -(y / h) * 2 + 1 cyy′=cycy−y=1+2w−y=−(y/h)∗2+1
使用代码表示就是:
const x = event.clientX;//鼠标单击坐标X
const y = event.clientY;//鼠标单击坐标Y// 屏幕坐标转标准设备坐标
const x1 = ( x / window.innerWidth ) * 2 - 1;
const y1 = -( y / window.innerHeight ) * 2 + 1;
//标准设备坐标(z=0.5这个值并没有一个具体的说法)
const stdVector = new Vector3(x1, y1, 0.5);
然后,再通过 Vector3.unproject(camera)
方法将标准设备坐标转为世界坐标:
const worldVector = stdVector.unproject(camera);
世界坐标转屏幕坐标
与上面的坐标转换相反,世界坐标转屏幕坐标的过程为:世界> 标准设备坐标 -> 屏幕坐标
通过 Vector3
对象的方法 project(camera)
,返回的结果是世界坐标 worldVector
在 camera
相机对象矩阵变化下对应的标准设备坐标, 标准设备坐标 xyz
的范围是[-1,1]
。
同样的,假设画布宽为 w
,高为 h
,屏幕坐标系中的一点为 (x, y)
,标准设备坐标系中对应的点为 (x1, y1)
从标准设备坐标系转换到屏幕坐标系与我们前面计算出的公式相反:
x=x1∗w2+w2x = x1 * \frac{w}{2} + \frac{w}{2} x=x1∗2w+2w
y=y1∗h2−h2y = y1 * \frac{h}{2} - \frac{h}{2} y=y1∗2h−2h
首先计算出屏幕坐标系中心:
const centerX = window.innerWidth / 2;
const centerY = window.innerHeight / 2;
计算出的 centerX
和 centerY
同时也表示了坐标轴的一半大小。
然后,将设备坐标系使用 project
方法转换到标准设备坐标系,再转换到屏幕坐标系中:
const standardVec = worldVector.project(camera);const screenX = Math.round(centerX * standardVec.x + centerX);
const screenY = Math.round(-centerY * standardVec.y + centerY);
ThreeJS 屏幕坐标与世界坐标互转相关推荐
- U3D屏幕坐标,世界坐标,像素坐标之间的关系
U3D屏幕坐标,世界坐标,像素坐标之间的关系 U3D中,屏幕坐标和世界坐标单位一样,二者之间是直接的一一对应关系,不受屏幕分辨率影响.默认情况下屏幕空间画布的左下角坐标是世界原点(0,0,0),这种情 ...
- OSG——- 对点选物体平移(鼠标点选物体、物体随鼠标移动、屏幕坐标转世界坐标)
之前的一篇博文是有一篇对点选物体进行平移.缩放旋转.那一篇是很简单的调用了OSG中定义的一些dragger,但这些dragger都有坐标轴或者tapbox等在模型上,与我最近要做的事情的需求不同.网上 ...
- UE5如何将屏幕坐标转为世界坐标和世界方向
哈喽,大家好,一起分享一下关于UE5如何将屏幕坐标转为世界坐标的方法. 屏幕坐标转为世界坐标 在PlayerControoler下找到这个函数: DeprojectScreenPositionToWo ...
- Unity中屏幕坐标与世界坐标之间的转换
世界坐标系转换为屏幕坐标 屏幕坐标转世界坐标 using System.Collections; using System.Collections.Generic; using UnityEngine ...
- d3.js 获取当前像素坐标_Cesium开发入门篇 | 06坐标系及坐标变换
Cesium中常用的坐标 1.屏幕坐标(像素) 即二维笛卡尔平面坐标,我们通过鼠标点击直接获取的坐标就是屏幕坐标了,单位是像素值,也可以通过new Cesium.Cartesian2(x, y)创建. ...
- cesium camera相机系统
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 概括 一.cesium常见的坐标系 二.几种坐标系的转换方法 1.经纬度坐标转世界坐标 2.世界坐标转经纬度 3.弧度和经纬 ...
- 【Unity3D】世界坐标与屏幕坐标
Unity3D由于是在三维世界中编程,而最终的结果是需要反馈到肉眼所示的2D屏幕之上的.这就产生了一种比较需要考虑的问题,尤其在一些涉及屏幕与Unity3D的3D世界交互的情况.网络上对于这方面的文字 ...
- Cocos Creator 世界坐标转屏幕坐标
Cocos creator某一坐标转屏幕坐标(screen position),以前都是屏幕坐标转世界坐标. 先上代码为敬(只是提供一种思路,有更好的实现和建议欢迎留言) //Scene的设计分辨率是 ...
- threejs旋转模型动画教程
第一次使用threejs到实际项目中,开始的时候心情有点小激动,毕竟是第一次嘛,然而做着做着就感受到这玩意水好深,满满的都是坑,填都填不过来.经过老板20天惨无人道的摧残,终于小有成就. 因为第一次搞 ...
最新文章
- Alpha 冲刺报告(3/10)
- 你知道这些产品设计灵感网站吗?
- ACM的输入输出总结
- 关闭加速渲染_“瀑布屏”旗舰 摩托罗拉Edge+渲染图曝光,Moto G8正式发布
- 为什么谈及硬件,必言软件?软硬件协同让开源世界“阴阳调和”
- 白宫发布太空系统网络安全防护指令
- Codeforces 486D Valid Sets (树型DP)
- NutUI 2.1.0 发布,移动端轻量级 Vue 组件库
- vi/vim命令使用
- SqlServer日常积累(二)
- Java TemplateProcessingException之Cannot execute subtraction: operands are null and #1234
- 程序员的快乐到底是什么?
- 高中OJ3837. 【NOIP2014模拟9.14】心灵终结
- java 帕斯卡,帕斯卡三角 有多少种可能,java编程 帕斯卡三角形 立刻求高手!! 给满分...
- java语言(3):通俗易懂的泛型
- 2020软件下载站源码手机自适应
- 安卓使用无障碍服务监听微信和QQ的收款信息
- SAP 过账显示不在允许过账期间 消息号M7053
- ARP地址解析协议详解
- 哪个男孩不想完成一次快速的查询?从MySQL、ES、HBASE等技术一起探讨下!