前言

最近的需求需要涉及到在web上实现各个矩阵的变换和逆变换,不过功能也仅限于此,没必要因为这个功能而引用three.js,所以就想着gluProject和gluUnProject两个函数在JavaScript上实现一遍,于是对照着这两个函数的源码进行改写。改写用到了矩阵向量库glMatrix。

gluProject和gluUnProject源码

GLint GLAPIENTRY
gluProject(GLdouble objx, GLdouble objy, GLdouble objz, const GLdouble modelMatrix[16], const GLdouble projMatrix[16],const GLint viewport[4],GLdouble *winx, GLdouble *winy, GLdouble *winz)
{double in[4];double out[4];in[0]=objx;in[1]=objy;in[2]=objz;in[3]=1.0;__gluMultMatrixVecd(modelMatrix, in, out);__gluMultMatrixVecd(projMatrix, out, in);if (in[3] == 0.0) return(GL_FALSE);in[0] /= in[3];in[1] /= in[3];in[2] /= in[3];/* Map x, y and z to range 0-1 */in[0] = in[0] * 0.5 + 0.5;in[1] = in[1] * 0.5 + 0.5;in[2] = in[2] * 0.5 + 0.5;/* Map x,y to viewport */in[0] = in[0] * viewport[2] + viewport[0];in[1] = in[1] * viewport[3] + viewport[1];*winx=in[0];*winy=in[1];*winz=in[2];return(GL_TRUE);
}GLint GLAPIENTRY
gluUnProject(GLdouble winx, GLdouble winy, GLdouble winz,const GLdouble modelMatrix[16],                     //注意:模型视图矩阵const GLdouble projMatrix[16],const GLint viewport[4],GLdouble *objx, GLdouble *objy, GLdouble *objz)
{double finalMatrix[16];double in[4];double out[4];//合并MVP矩阵__gluMultMatricesd(modelMatrix, projMatrix, finalMatrix);//MVP矩阵求逆矩阵if (!__gluInvertMatrixd(finalMatrix, finalMatrix)) return(GL_FALSE);in[0]=winx;in[1]=winy;in[2]=winz;in[3]=1.0;//从屏幕坐标变换为0到1之间的坐标/* Map x and y from window coordinates */in[0] = (in[0] - viewport[0]) / viewport[2];in[1] = (in[1] - viewport[1]) / viewport[3];//从0到1之间变换到-1到1./* Map to range -1 to 1 */in[0] = in[0] * 2 - 1;in[1] = in[1] * 2 - 1;in[2] = in[2] * 2 - 1;//乘以MVP逆矩阵之后得到世界空间的坐标__gluMultMatrixVecd(finalMatrix, in, out);//从齐次坐标变换为笛卡尔坐标if (out[3] == 0.0) return(GL_FALSE);out[0] /= out[3];out[1] /= out[3];out[2] /= out[3];//将结果赋值。*objx = out[0];*objy = out[1];*objz = out[2];return(GL_TRUE);
}

JavaScript改写版本

其实,如果懂渲染管线的知识,应该这两个函数的源码应该非常清晰易懂。如果看不懂,请先搞懂各个坐标转换的知识。
下面是两个函数的JavaScript版本改写,要先下载glMatrix.js。

//将世界坐标转换为屏幕坐标。function project(objX, objY, objZ, modelviewMatrix, projectMatrix, viewport, winX, winY, winZ) {var input = new Array(4);var output = new Array(4);input[0] = objX;input[1] = objY;input[2] = objZ;input[3] = 1.0;vec4.transformMat4(output, input, modelviewMatrix);//模型视图变换vec4.transformMat4(input, output, projectMatrix);//投影变换//透视除法,进入标准化设备坐标if (input[3] == 0.0) return;input[0] /= input[3];input[1] /= input[3];input[2] /= input[3];//将坐标由-1到1,转换到0-1input[0] = input[0] * 0.5 + 0.5;input[1] = input[1] * 0.5 + 0.5;input[2] = input[2] * 0.5 + 0.5;//将x,y转换到屏幕坐标input[0] = input[0] * viewport[2] + viewport[0];input[1] = input[1] * viewport[3] + viewport[1];winX = input[0];winY = input[1];winZ = input[2];}//将屏幕坐标转换为世界坐标。function Unproject(winX, winY, winZ, modelviewMatrix, projectMatrix, viewport, objX, objY, objZ) {var finalMatrix = mat4.create();var input = new Array(4);var output = new Array(4);mat4.invert(modelviewMatrix, modelviewMatrix);mat4.invert(projectMatrix, projectMatrix);//合并MVP矩阵mat4.multiply(finalMatrix, modelviewMatrix, projectMatrix);input[0] = winX;input[1] = winY;input[2] = winZ;input[3] = 1.0;//从屏幕坐标变换为0到1之间的坐标input[0] = (input[0] - viewport[0]) / viewport[2];input[1] = (input[1] - viewport[1]) / viewport[3];//从0到1之间变换到-1到1之间input[0] = input[0] * 2 - 1;input[1] = input[1] * 2 - 1;input[2] = input[2] * 2 - 1;//乘以MVP逆矩阵之后得到世界空间的坐标vec4.transformMat4(output, input, finalMatrix);//从齐次坐标变换为笛卡尔坐标if (output[3] == 0.0) return;output[0] /= output[3];output[1] /= output[3];output[2] /= output[3];//将结果赋值。objX = output[0];objY = output[1];objZ = output[2];}

我自己写了个小的测试例子,大家如果感兴趣可以下载,自行打断点进行测试。
下载地址

【OPENGLWEBGL】将OpenGL里的gluProject和gluUnProject函数web化相关推荐

  1. 旁观OpenGL里的透视投影矩阵

    OpenGL里的代码已经形成和使用了好多年,从程序员的角度,对OpenGL底层代码做升级或修改的实际意义并不大,而且风险高.所以,修改底层算法的想法是有些太狂了.但是,从教学的角度.提供一种新的视角去 ...

  2. linux 为什么 c语言,为什么C程序里一定要写main函数

    为什么C程序里一定要写main函数 一. 学习过程 编写程序f.c: 对其进行编译,正常通过,再对其进行连接,出现错误: 显示的出错信息为: 翻译成中文是:在c0s模块没有定义符号'_main'. 那 ...

  3. Visual Basic里与Print有关的函数

    在Visual Basic里信息要按一定的格式输出,需要使用tab.Spc.Space$函数,这些函数必须与Print方法配合使用. 1.Tab函数 格式:Tab(n) 功能:把光标移到由参数n指定的 ...

  4. python中str是什么函数_python里的str是什么函数

    python里的str是什么函数 发布时间:2020-05-18 11:39:40 来源:亿速云 阅读:280 作者:小新 今天小编给大家分享的是python里的str是什么函数,相信很多人都不太了解 ...

  5. 痞子衡嵌入式:嵌入式里通用微秒(microseconds)计时函数框架设计与实现

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是嵌入式里通用微秒(microseconds)计时函数框架设计与实现. 在嵌入式软件开发里,计时可以说是非常基础的功能模块了,其应用也非常 ...

  6. SQL里有取整函数,四舍五入函数,和截取函数 - eminem - JavaEye技术网站

    SQL里有取整函数,四舍五入函数,和截取函数 关键字: s round(123.456,2) ------------ 123.47 ROUND ( numeric_expression , leng ...

  7. vc 编译c语言时出错,在vc++里输入c语言空函数,为什么编译没错,连接出错?

    在vc++里输入c语言空函数,为什么编译没错,连接出错? 來源:互聯網  2010-02-14 09:24:33  評論 分類: 電腦/網絡 >> 程序設計 >> 其他編程語言 ...

  8. Opengl 入门,学习网站,常用函数详解 (gluproject,gluUnProject,glReadPixels)

    Opengl 学习网站 想要系统的学,推荐learnopengl网站官网链接.,同时可以看工具书<OpenGL编程指南(第8版)> 目前市面上的教程,大部分是针对新版本的opengl,即核 ...

  9. GLSL里的矩阵对向量的乘法与OpenGL里用数组生成矩阵进行向量乘法的非直觉不一致

    在GLSL里写成如下的mat*vector, 在实际操作过程中并不和直觉的乘法相同,直觉上做的是: 然而做的是 例如在.c文件里设置mat为 vector = 以为做的是mat*vector 实际上做 ...

最新文章

  1. 一步步学习SPD2010--第十四章节--在Web页面使用控件(3)--验证用户数据输入
  2. Java的Exception和Error面试题10问10答
  3. 编程爱好者学vb还是python-编程语言Java和Python对比哪个比较好
  4. 单防区扩展模块怎么用_Zens推出模块化可扩展无线充电器 可为6台设备同时供电...
  5. figma导出android切图,谁再说Figma没办法导出标注和切图,你把这个插件转发给他...
  6. yield return的理解
  7. decimal转为string sql_SQL注入详解|OWASP Top 10安全风险实践(二)
  8. 大型数据库的设计原则与开发技巧
  9. excel 2016 新建时 出现 内存或磁盘不足错误的解决方法
  10. python之6-1常用函数
  11. Jmeter的基本功能使用方法
  12. 无线通信网络学习笔记-1
  13. PS怎么用3D功能怎么用?如何用PS做立体字
  14. 娃哈哈,又c,又JAVA的,莫明其妙的
  15. github windows系统监控_你需要的:Windows | 精品软件集
  16. 可以模拟人工操作的软件;如访问网页,在网页中自动获取固定信息等
  17. (附源码)ssm校园拼车服务系统 毕业设计211633
  18. 如何快速获取图片的ROI区域坐标
  19. VPS主机在未来会取代虚拟主机空间吗?
  20. 被误解的C++——法国大革命

热门文章

  1. 用计算机的简便方法,和孩子一起做个计算器软件,真的是太简单啦!
  2. 对自己学习的一点总结
  3. 三星经典android手机,回忆杀,三星最经典的Note系列旗舰手机
  4. 儿童用灯哪个品牌好?分享五款儿童护眼台灯品牌
  5. 【OpenFOAM】-olaFlow-算例3- currentWaveFlume
  6. 从进军空气消毒赛道看格兰仕的改变
  7. JS javascript实现url编码和url解码(urlEncode urlDecode)
  8. 特征工程二(多重共线性)
  9. (转载) 漫谈 SLAM 技术(下)
  10. 【EPIC】自建平台付款建议程序EPIC