• 【坐标系】各引擎坐标系


    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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    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; 
    
    • 1
    • 2

    因为坐标系不同遇到的问题(基于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 <a
    			href="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 loop
    			controls.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>
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110

    小车位置是(0,0,0)
    在这里插入图片描述
    three相机位置是(0,0,10)
    在这里插入图片描述

    unity中
    相机位置(0,0,-10),小车位置(0,0,0),最终渲染结果如下
    在这里插入图片描述
    小车和相机在世界坐标系下位置如下图所示
    在这里插入图片描述

    three和unity相机的模型矩阵分别是
    在这里插入图片描述

    在这里插入图片描述

    three和unity中视图矩阵分别是
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/4bd9eb27ed394edd9ab37ec6e2a37db0.png
    在这里插入图片描述

    three和unity中投影矩阵分别是

    在这里插入图片描述

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

    目前发现了两个问题:
    1.问题1
    就算在unity中修改视图矩阵和three中一样,最终显示结果是下面这样
    在这里插入图片描述
    但是,这个渲染结果和threejs渲染结果还是不一样看着似乎一样,但是它是X轴取反了,而且是我强制改了双面渲染,不然它的模型三角面顶点顺序都变了,这个就涉及到了世界坐标系左手和右手的转换问题,这块令人困惑。
    2.问题2
    这个汽车模型在three的世界坐标系(右手)中和在unity的世界坐标系(左手)中摆放好像是X轴取反了! 这是为啥
    在这里插入图片描述
    在这里插入图片描述
    可以看那个字母m的朝向,是不是很奇怪。

    参考

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

  • 相关阅读:
    【动态规划】583. 两个字符串的删除操作、72. 编辑距离
    代码随想录算法训练营003|203. 移除链表元素,206. 反转链表,707. 设计链表
    科技资讯|苹果下一代Vision Pro头显将更小更轻,预装处方镜片
    【Unity基础】5.动画曲线
    图数据结构之邻接链表Adjacency List(Python版)
    webpack5 Preload / Prefetch解决按需求加载速度
    一文简述:HTTP协议和HTTPS协议
    代码随想录刷题| 多重背包理论基础、背包问题的总结
    数组模拟栈
    Linux 下编译和交叉编译FFmpeg、OpenCV(contrib )库
  • 原文地址:https://blog.csdn.net/qq_22849251/article/details/126504270