最近在入坑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. BGP联盟

    ---恢复内容开始--- 1. 每台路由器设置loop back口,r1和r6另外多设置两个 2. R2 R3 R4 R5 R6做ospf 以R2为例: ospf 1 router-id 2.2.2. ...

  2. Django学习之路由层

    Django请求生命周期 - wsgi, 他就是socket服务端,用于接收用户请求并将请求进行初次封装,然后将请求交给web框架(Flask.Django) - 中间件,帮助我们对请求进行校验或在请 ...

  3. 4)date中的Ymd格式问题

    以下是详细的参数: format 字符 说明 返回值例子日 --- ---d 月份中的第几天,有前导零的 2 位数字 01 到 31D 星期中的第几天,文本表示,3 个字母 Mon 到 Sunj 月份 ...

  4. 吴裕雄--天生自然python学习笔记:Matplotlib 基本绘图

    使用 Matplotlib 组件绘图时,经常要与 Numpy 组件搭配使用 . 使用 Matplotlib 绘图首先要导入 Matplotlib 组件 , 由于大部分绘图功能是在 matplotlib ...

  5. OpenCV 图像平滑处理

    #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" us ...

  6. IT技术团队的管理幅度

    一.先科普下 管理幅度,又称管理宽度,是指在一个组织结构中,管理人员所能直接管理或控制的员工数目.这个数目是有限的,当超这个限度时,管理的效率就会随之下降. 二.经历现状 20左右的中小型团队,不算大 ...

  7. python标准库:ftplib模块

    ftplib模块包含了文件传输协议(FTP)客户端的实现. 下面的例子展示了如何登入和获取进入目录的列表,dir函数传入一个回调函数,该回调函数在服务器相应时每一行调用一次.ftplib模块默认的回调 ...

  8. js 实现手风琴

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. 每日一译系列-模块化css怎么玩(译文)

    原文链接:How Css Modules Work 原文作者是Preact的作者 这是一篇关于如何使用Css Modules的快速介绍,使用到的工具是Webpack吊炸的css-loader 首先,我 ...

  10. Mac 下配置 adb 环境

    使用 adb 命令可以很直接的观察你的应用 第一步 打开终端,敲入命令:sudo vi .bash_profile(如果有密码就为本机登录密码, 如果没有这个文件就会创建一个新的). 第二步 在文件中 ...