最近在入坑Layabox,花了几天时间做世界坐标和屏幕坐标的互转,由于Layabox没有现成的代码所以只能自己手动写,大概就是模仿unity里面的ScreenToWorldPoint和WorldToScreenPoint函数。

大致思路是,屏幕坐标的z轴就是,物体离相机的距离。

需要注意的是,unity 和 layabox 坐标系的区别,三维坐标( unity 左手坐标系, layabox 右手坐标系 ) 和 屏幕坐标系都不同( unity原点在左下角,layabox 原点在右下角 )

https://www.cnblogs.com/mttnor/p/9647850.html 里面的感觉比较明了,参考里面的图片可以更好的理解我的代码

/**[SixGod]
* 世界坐标转屏幕坐标
* @param {Laya.Camera} camera 参照相机
* @param {Laya.Vector3} point 需要转换的点
*/
static WorldToScreen2(camera, point) {
var pointA = this.InverseTransformPoint(camera.transform, point);
var distance = pointA.z; var out = new Laya.Vector3();
camera.viewport.project(point, camera.projectionViewMatrix, out);
var value = new Laya.Vector3(out.x / Laya.stage.clientScaleX, out.y / Laya.stage.clientScaleY, distance);
return value;
}
/**[SixGod]
* 屏幕坐标转世界坐标
* @param {Laya.Camera} camera 参照相机
* @param {Laya.Vector3} point 需要转换的点
*/
static ScreenToWorld(camera, point) {
var halfFOV = (camera.fieldOfView * 0.5) * Math.PI / 180;
let height = point.z * Math.tan(halfFOV);
let width = height * camera.aspectRatio; let lowerLeft = this.GetLowerLeft(camera.transform, point.z, width, height);
let v = this.GetScreenScale(width, height); // 放到同一坐标系(相机坐标系)上计算相对位置
var value = new Laya.Vector3();
var lowerLeftA = this.InverseTransformPoint(camera.transform, lowerLeft);
value = new Laya.Vector3(-point.x / v.x, point.y / v.y, 0);
Laya.Vector3.add(lowerLeftA, value, value);
// 转回世界坐标系
value = this.TransformPoint(camera.transform, value);
return value;
} /**[SixGod]
* 获取三维场景和屏幕比例
* @param {Number} width 宽
* @param {Number} height 长
*/
static GetScreenScale(width, height) {
var v = new Laya.Vector3();
v.x = Laya.stage.width / width / 2;
v.y = Laya.stage.height / height / 2;
return v;
} /**[SixGod]
* 获取相机在 distance距离的截面右下角世界坐标位置
* @param {Laya.Transform} transform 相机transfrom
* @param {Number} distance 距离
* @param {Number} width 宽度
* @param {Number} height 长度
*/
static GetLowerLeft(transform, distance, width, height) {
// 相机在 distance距离的截面左下角世界坐标位置
// LowerLeft
var lowerLeft = new Laya.Vector3(); // lowerLeft = transform.position - (transform.right * width);
var right = new Laya.Vector3();
transform.getRight(right);
Laya.Vector3.normalize(right, right);
var xx = new Laya.Vector3(right.x * width, right.y * width, right.z * width);
Laya.Vector3.add(transform.position, xx, lowerLeft); // lowerLeft -= transform.up * height;
var up = new Laya.Vector3();
transform.getUp(up);
Laya.Vector3.normalize(up, up);
var yy = new Laya.Vector3(up.x * height, up.y * height, up.z * height);
Laya.Vector3.subtract(lowerLeft, yy, lowerLeft); // lowerLeft += transform.forward * distance;
var forward = new Laya.Vector3();
transform.getForward(forward);
Laya.Vector3.normalize(forward, forward);
var zz = new Laya.Vector3(forward.x * distance, forward.y * distance, forward.z * distance);
Laya.Vector3.subtract(lowerLeft, zz, lowerLeft);
return lowerLeft;
} /**[SixGod]
* 世界坐标转相对坐标
* @param {Laya.Transform} origin camera.transform
* @param {Laya.Vector3} point 需要转换的点
*/
static InverseTransformPoint(origin, point) {
var xx = new Laya.Vector3();
origin.getRight(xx);
var yy = new Laya.Vector3();
origin.getUp(yy);
var zz = new Laya.Vector3();
origin.getForward(zz);
var zz1 = new Laya.Vector3(-zz.x, -zz.y, -zz.z);
var x = this.ProjectDistance(point, origin.position, xx);
var y = this.ProjectDistance(point, origin.position, yy);
var z = this.ProjectDistance(point, origin.position, zz1);
var value = new Laya.Vector3(x, y, z);
return value;
} /**[SixGod]
* 相对坐标转世界坐标
* @param {Laya.Transform} origin camera.transform
* @param {Laya.Vector3} point 需要转换的点
*/
static TransformPoint(origin, point) {
var value = new Laya.Vector3();
Laya.Vector3.transformQuat(point, origin.rotation, value);
Laya.Vector3.add(value, origin.position, value);
return value;
} /**[SixGod]
* 向量投影长度, 向量CA 在向量 CB 上的投影长度
* @param {Laya.Vector3} A
* @param {Laya.Vector3} C
* @param {Laya.Vector3} B
*/
static ProjectDistance(A, C, B) {
var CA = new Laya.Vector3();
Laya.Vector3.subtract(A, C, CA);
var angle = this.Angle2(CA, B) * Math.PI / 180;
var distance = Laya.Vector3.distance(A, C);
distance *= Math.cos(angle);
return distance;
} /**[SixGod]
* 向量夹角
* @param {Laya.Vector3} ma 向量A
* @param {Laya.Vector3} mb 向量B
*/
static Angle2(ma, mb) {
var v1 = (ma.x * mb.x) + (ma.y * mb.y) + (ma.z * mb.z);
var ma_val = Math.sqrt(ma.x * ma.x + ma.y * ma.y + ma.z * ma.z);
var mb_val = Math.sqrt(mb.x * mb.x + mb.y * mb.y + mb.z * mb.z);
var cosM = v1 / (ma_val * mb_val); if (cosM < -1) cosM = -1;
if (cosM > 1) cosM = 1; var angleAMB = Math.acos(cosM) * 180 / Math.PI;
return angleAMB;
}

Layabox 世界坐标和屏幕坐标互转的更多相关文章

  1. OSG世界坐标转屏幕坐标(转载)

    OSG世界坐标转屏幕坐标 #define M(row,col) m[col * 4 + row] void Transform_Point(double out[4], const double m[ ...

  2. Unity 坐标 转换 详解 World世界坐标 Screen屏幕坐标 View视口坐标 GUI坐标 NGUI坐标 localPosition相对父级坐标

    在制作游戏中我们经常会遇到这样一个需求: 在人物模型的上面显示 名字.称号 一类的文字或者图片 如下图 人物模型属于是Camera1   UI Title信息属于NGUI Camera2 如下图 这时 ...

  3. threejs 世界坐标与屏幕坐标相互转换

    屏幕坐标转世界坐标: let pX = (screenPoint.x / this.scene.renderer.domElement.clientWidth) * 2 - 1; let pY = - ...

  4. ogre世界坐标鱼屏幕坐标相互转换

    bool worldCoordToScreen(Vector3 objPos, Camera* cam, Vector2 screenRect,  Vector2& screenPos) { ...

  5. threejs 世界坐标转化为屏幕坐标

    网站: http://www.yanhuangxueyuan.com/Three.js_course/screen.html 方法.project 通过Vector3对象的方法project,方法的参 ...

  6. u3d 楼梯,圆环,椭圆,直线运动。世界坐标。点击。U3d stair, ring, ellipse, linear motion.World coordinates.Click .

    u3d 楼梯,圆环,椭圆,直线运动.世界坐标.点击. U3d stair, ring, ellipse, linear motion.World coordinates.Click . 作者:韩梦飞沙 ...

  7. 【Python文件处理】递归批处理文件夹子目录内所有txt数据

    因为有个需求,需要处理文件夹内所有txt文件,将txt里面的数据筛选,重新存储. 虽然手工可以做,但想到了python一直主张的是自动化测试,就想试着写一个自动化处理数据的程序. 一.分析数据格式 需 ...

  8. Unity学习疑问记录之坐标体系

    [Unity3D的四种坐标系] 1.World Space(世界坐标):我们在场景中添加物体(如:Cube),他们都是以世界坐标显示在场景中的.transform.position可以获得该位置坐标. ...

  9. (十五)WebGIS中平移功能的设计和实现

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.前言 这一章我们将详细讲解WebGIS工具栏中另一个基础工具——平 ...

随机推荐

  1. 堆排Heap Sort

    1. #define LeftChild(i) (2*(i)+1) void PercDown(vector<int>&num, int i, int n) { int child ...

  2. ABC Fennec VS. Snuke

    题目描述 Fennec and Snuke are playing a board game. On the board, there are N cells numbered 1 through N ...

  3. The Maximum Unreachable Node Set

    题目描述 In this problem, we would like to talk about unreachable sets of a directed acyclic graph G = ( ...

  4. ssh 怎样以root用户登录

    #sudo vim /etc/ssh/sshd_config 找到并用#注释掉这行:PermitRootLogin prohibit-password 新建一行 添加:PermitRootLogin ...

  5. struts 2.1.8.1的sx:datetimepicker标签出现NaN错误的原因和解决办法

     作者:Junsan.Jin 邮箱:junsanjin@gmail.com QQ:1305896503 本文原始地址:http://www.rsky.com.cn/Article/java/201 ...

  6. 一、美国国家经济研究局NBER教育经济研究项目工作论文合集

    一.美国国家经济研究局NBER教育经济研究项目工作论文合集 (一)项目地址: American National Bureau of Economic Research - Economics of ...

  7. 组合数学之Pólya计数理论

    1 群 群$(G, cdot)$: 闭合, 结合律, 幺元, 逆 1.1 置换群 置换为双射$pi:[n]to [n]$, 置换之间的操作符 $cdot$ 定义为函数的复合, 即$(pi cdot s ...

  8. JAVA SE Lesson 1

    1.  类是一种抽象的概念,对象是类的一种具体表示形式,是具体的概念.先有类,然后由类来生成对象(Object).对象又叫做实例(Instance).2.  类由两大部分构成:属性以及方法.属性一般用 ...

  9. 自制一个可编辑QueryString的类URLModifier

    有些情况下,需要 新增/删除/替换 url中的部分Querystring中的参数,而.net自带的Uri类只能解析,不能编辑,,并且如果是Relative类型的链接,转成Uri类型之后,很多参数又不能 ...

  10. python爬虫之字体反爬

    一.什么是字体反爬? 字体反爬就是将关键性数据对应于其他Unicode编码,浏览器使用该页面自带的字体文件加载关键性数据,正常显示,而当我们将数据进行复制粘贴.爬取操作时,使用的还是标准的Unicod ...