WebGL坐标系

确认过了WebGL 你给个三角形A深度是-0.5三角形B深度是0,开启深度检测后,画出来发现深度小的三角形(-0.5)画在了前面,注意深度检测后就是深度大的在后面,由此得出WebGL/OpenGL 裁剪空间和NDC默认就是左手坐标系

然而为什么说一些引擎如threejs是右手坐标系呢,是因为在投影矩阵里给第三行乘了个-1,就是左乘一个Z方向反转矩阵(注意三行三列为-1,其他和单位矩阵一样),会导致z轴翻转,转换成了所谓右手坐标系,可以看下正射投影和透视投影算出的第三行和正常的投影矩阵比

THREE世界坐标系(右手)

RGB分别代表XYZ,相机位置是 0 0 200,目标物体位置是0 0 0

THREE相机坐标系(右手)

证明:
我们先假设相机坐标系是右手坐标系的,世界坐标系中相机位置是(0,0,200), 物体A绿色在(0,0,0), 物体B红色在(0,0,100),所以相机坐标系中,物体A绿色坐标为(0,0,-200),物体B红色坐标为(0,0,-100),我们知道THREE裁剪空间会对Z轴进行反转,所以经过裁剪空间处理后,物体A绿色坐标为(0,0,200),物体B红色坐标为(0,0,100),按照深度大的显示在后面的原理,所以应该是红色物体显示在绿色物体前面,由下图看假设是正确的

let camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 200);
camera.lookAt(new THREE.Vector3(0, 0,0));const boxA = new THREE.Mesh(new THREE.BoxGeometry(10, 10, 10), new THREE.MeshPhongMaterial({color: 'rgb(0,255,0)',
}));
boxA.position.x = 0;
boxA.position.y = 0;
boxA.position.z = 0;
scene.add(boxA);const boxB = new THREE.Mesh(new THREE.BoxGeometry(10, 10, 10), new THREE.MeshPhongMaterial({color: 'rgb(255,0,0)',}));
boxB.position.x = 0;
boxB.position.y = 0;
boxB.position.z = 100;
scene.add(boxB);

THREE裁剪空间

以three的正射投影为例,near=-1,far=1,算出的投影矩阵如下图所示,这都和unity是统一的,最终裁剪空间会对z轴进行反转

Unity世界坐标系(左手)

RGB分别代表XYZ,相机位置是 0 0 0,目标物体位置是0 0 10

Unity相机坐标系(右手)

unity相机空间是右手坐标系,相机朝向为z轴的负方向,下面证明一下。

我们先假设相机坐标系是右手坐标系的,世界坐标系中相机位置是(0,0,-20), 物体A绿色在(0,0,0), 物体B红色在(0,0,-10),所以相机坐标系中,物体A绿色坐标为(0,0,-20),物体B红色坐标为(0,0,-10),我们知道Unity裁剪空间会对Z轴进行反转,所以经过裁剪空间处理后,物体A绿色坐标为(0,0,20),物体B红色坐标为(0,0,10),按照深度大的显示在后面的原理,所以应该是红色物体显示在绿色物体前面,由下图看假设是正确的

Unity裁剪空间

以unity的正射投影为例,near=-1,far=1,算出的投影矩阵如下图所示


所以unity的正射投影矩阵为

这里三行三列为-1,,最终裁剪空间会对z轴进行反转

这就是因为在Unity里当World Space变到Camera Space时,需要做一个反转z轴的操作(因此Unity的视图变换矩阵,相比文章前面的推理还需再乘以一个z轴反转的矩阵)。然后我们做投影变换到Clip Space时,又要给它转回来(再做一次z反转),使得near clip plane在-1,far clip plane在1。

Unity中视图矩阵需要做个特殊处理

Unity和Three 坐标系异同(分析暂时有问题先不看)

three和unity的世界坐标系区别是three右手,unity左手,unity中使用从three计算得到的坐标应该世界矩阵再前乘 negatezMaT,对z轴反转

// 这里后面乘negatezMaT意思给模型矩阵前乘negatezMaT,将世界坐标系转到左手
Matrix4x4 viewMatrix = float16ToMatrix4x4(three.viewMatrix) * negatezMaT;

因为坐标系不同遇到的问题(基于opengl)

threejs
相机位置 (0,0,10),默认看向负半轴方向,小车位置是(0,0,0),具体代码如下,渲染结果如下。

<!DOCTYPE html>
<html lang="en"><head><title>three.js webgl - glTF loader</title><meta charset="utf-8"><meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"><link type="text/css" rel="stylesheet" href="main.css">
</head><body><div id="info"><a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - GLTFLoader<br />Battle Damaged Sci-fi Helmet by<a href="https://sketchfab.com/theblueturtle_" target="_blank" rel="noopener">theblueturtle_</a><br /><a href="https://hdrihaven.com/hdri/?h=royal_esplanade" target="_blank" rel="noopener">Royal Esplanade</a> by <ahref="https://hdrihaven.com/" target="_blank" rel="noopener">HDRI Haven</a></div><div id = "test" style="width: 1180px; height: 695px;"></div><script type="module">import * as THREE from '../build/three.module.js';import { OrbitControls } from './jsm/controls/OrbitControls.js';import { GLTFLoader } from './jsm/loaders/GLTFLoader.js';let camera, scene, renderer;init();render();function init() {// const container = document.createElement('div');// document.body.appendChild(container);var canvasContainer = document.getElementById("test")document.body.appendChild(canvasContainer);camera = new THREE.PerspectiveCamera(60, canvasContainer.clientWidth / canvasContainer.clientHeight, 0.3, 1000);camera.position.set(0, 0, 10);console.log(camera)// camera.lookAt(new THREE.Vector3(0, 0, 0));scene = new THREE.Scene();scene.add(new THREE.DirectionalLight())// scene.add(new THREE.AmbientLight())window.camera = camera;const loader = new GLTFLoader().setPath('models/gltf/DamagedHelmet/glTF/');loader.load('DamagedHelmet.glb', function (gltf) {scene.add(gltf.scene);console.log(gltf.scene.position)render();});let axes = new THREE.AxisHelper(10);scene.add(axes);// var cameraPerspective = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.3, 20);window.cameraPerspective = cameraPerspective;cameraPerspective.position.set(0, 0, 10);var cameraPerspectiveHelper = new THREE.CameraHelper( cameraPerspective );window.cameraPerspectiveHelper = cameraPerspectiveHelper;scene.add( cameraPerspectiveHelper );scene.add( cameraPerspective );renderer = new THREE.WebGLRenderer({ antialias: true });renderer.setPixelRatio(window.devicePixelRatio);// renderer.setSize(window.innerWidth, window.innerHeight);renderer.setSize(canvasContainer.clientWidth, canvasContainer.clientHeight);canvasContainer.appendChild(renderer.domElement);const controls = new OrbitControls(camera, renderer.domElement);controls.addEventListener('change', render); // use if there is no animation loopcontrols.minDistance = 2;controls.maxDistance = 100;controls.target.set(0, 0, 0);controls.update();}function render() {window.cameraPerspectiveHelper.update()window.cameraPerspective.updateMatrix()renderer.render(scene, camera);}</script></body></html>

小车位置是(0,0,0)

three相机位置是(0,0,10)

unity中
相机位置(0,0,-10),小车位置(0,0,0),最终渲染结果如下

小车和相机在世界坐标系下位置如下图所示

three和unity相机的模型矩阵分别是

three和unity中视图矩阵分别是

three和unity中投影矩阵分别是

看出来两个引擎中
视图矩阵是第三行三列正好相反
投影矩阵是相同的

目前发现了两个问题:
1.问题1
就算在unity中修改视图矩阵和three中一样,最终显示结果是下面这样

但是,这个渲染结果和threejs渲染结果还是不一样看着似乎一样,但是它是X轴取反了,而且是我强制改了双面渲染,不然它的模型三角面顶点顺序都变了,这个就涉及到了世界坐标系左手和右手的转换问题,这块令人困惑。
2.问题2
这个汽车模型在three的世界坐标系(右手)中和在unity的世界坐标系(左手)中摆放好像是X轴取反了! 这是为啥


可以看那个字母m的朝向,是不是很奇怪。

参考

【1】.视图变换和投影变换矩阵的原理及推导,以及OpenGL,DirectX和Unity的对应矩阵

【坐标系】各引擎坐标系相关推荐

  1. OSG三维渲染引擎编程学习之十七:“第二章:OSG数学基础” 之 “2.7 世界坐标系、物体坐标系、摄像机坐标系”

    第二章 OSG数学基础 OSG是一个优秀的三维渲染引擎,三维渲染涉及到大量的3D数学知识.3D数学是一门和计算机几何相关的科学,研究怎样用数值的方法来解决几何问题,因此,掌握并灵活运用3D数字知识是O ...

  2. 2.cocos2d-x坐标体系(UI坐标系,GL坐标系,本地坐标,世界坐标,节点坐标)

     openGL & UI坐标体系 OpenGL坐标系:该坐标原点在屏幕左下角,x轴向右,y轴向上.这也就是cocos2dx中用到的坐标系. 屏幕坐标系:该坐标系的原点在屏幕左上角,x轴向右 ...

  3. AirSim(五)---理解篇: Airsim世界坐标系、NED坐标系、机体坐标系以及控制相关API接口函数

    目录 1. 坐标系 coordinate system (1) AirSim API的坐标系:NED 坐标系 with SI unit (2) Unreal Engine的坐标系 (3)AirSim全 ...

  4. 屏幕坐标系和视口坐标系

    一.屏幕坐标系 1.屏幕坐标系: 手机屏幕或者电脑屏幕的一个坐标系. 2.屏幕坐标是以像素来定义的, 屏幕左下角为原点(0,0), 右上角为(Screen.width,Screen.height), ...

  5. 【自动驾驶】16.计算机视觉:相机成像原理:世界坐标系、相机坐标系、图像坐标系、像素坐标系之间的转换

    本篇博客为转载,我对其中的细节添加了一些说明. 原文链接:https://blog.csdn.net/chentravelling/article/details/53558096 0.前言 最近整理 ...

  6. 世界坐标系,相机坐标系和图像坐标系的转换(Python)

    世界坐标系,相机坐标系和图像坐标系的转换(Python) 相机内参外参说明:相机内参外参_pan_jinquan的博客-CSDN博客_相机内参 计算机视觉:相机成像原理:世界坐标系.相机坐标系.图像坐 ...

  7. 单目视觉标定:世界坐标系、相机坐标系、图像坐标系、像素坐标系——简单粗暴,粗暴

    转:https://blog.csdn.net/chentravelling/article/details/53558096 1.正文 图像处理.立体视觉等等方向常常涉及到四个坐标系:世界坐标系.相 ...

  8. 世界坐标系,摄像机坐标系、图像坐标系关系汇总

    **摄像机标定:**在计算机视觉研究领域,摄像机标定是一个重要的环节.摄像机标定就是求取摄像机内外参数的过程. 世界坐标系:绝对坐标系,一般的三维场景都由这个坐标系来表示.摄像机可以放置在环境中的任何 ...

  9. 我国四大常用坐标系及高程坐标系【转载】

    1.北京54坐标系(BJZ54) 北京54坐标系为参心大地坐标系,大地上的一点可用经度L54.纬度M54和大地高H54定位,它是以克拉索夫斯基椭球为基础,经局部平差后产生的坐标系. 新中国成立以后,我 ...

  10. 计算机视觉:相机成像原理:世界坐标系、相机坐标系、图像坐标系、像素坐标系之间的转换(转载)

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/chentravelling/article/details/53558096 0.前言 最近整理了& ...

最新文章

  1. 数据通信技术(十:OSPF特殊区域TOTALLY STUB配置(ZTE))
  2. 使用R构建Xgboost模型并绘制ROC曲线
  3. linux基础命令学习(四)用户与群组
  4. 复杂网络下多码率视频流切换关键技术
  5. linux系统部署静态网站,Linux笔记15 使用Apache服务部署静态网站。
  6. [saiku] 使用 Apache Phoenix and HBase 结合 saiku 做大数据查询分析
  7. php缓存页面,PHP缓存页面函数的简单示例
  8. 29.AngularJS 简介
  9. 假如时光能够倒流, 我会这么学习Java
  10. 互联网公司的三高问题
  11. win10分辨率设置正确但屏幕却被拉伸了,如何处理
  12. 服务器上发布的网站应用80端口时内网可以访问,外网不能访问
  13. 【视频教程】帝国CMS模板开发制作网站系列教程04
  14. 智能水表自动抄表协议cjt188远传协议,支持地址自动分配检查,灵活好用、Mbus通讯测试工具是一款水表等设备的测试工具
  15. sublimelinter java_程序员必备工具SublimeLinter安装使用指南
  16. python判断人生阶段
  17. vbs实现的支持拖动的txt文本切割器
  18. 机器学习算法(1)——Logistic Regression
  19. jenkins + UIAutomation 自动化脚本运行app
  20. 二、Kubernetes安装

热门文章

  1. 自己做的html5手机网站
  2. DIY云端情书打印机(基于腾讯定制开发板)
  3. 如何使用开发者服务器运维微信公众号
  4. 利用数组进行进制转换
  5. web前端和Java后端有什么区别?
  6. taro-ui 的 AtInput标签的bug
  7. SL651-2014水文检测数据通信规约pdf下载
  8. 金融行业数据分类分级“五步走” | 盾见
  9. python爬取当当网的书籍信息并保存到csv文件
  10. 6-2 符号函数 (5 分)(C语言版)