上一篇自己动手写opengl 由于时间原因停止了更新,现在继续。

1. 首先我们定义以下变量

 public static class DisplayInfo{Canvas canvas;int height;int width;}private static DisplayInfo mInfo;public static void initDrawEnvirement(DisplayInfo info){mInfo = info;}public enum MatrixMode{MODE_MODEL_VIEW,MODE_PROJECTION}//for testingpublic static M4 mCurrentSurfaceViewProjectionMatrix = null;public static M4 mCurrentSurfaceViewModelViewMatrix = null;public static Stack<M4> mModelViewMatrixStack = new Stack<M4>();public static Stack<M4> mProjectionMatrixStack = new Stack<M4>();public static M4 mCurrentModelViewMatrix = new M4();public static M4 mCurrentProjectionMatrix = new M4();public static M4 mCurrentViewPortMatrix = new M4();public static MatrixMode mMatrixMode = MatrixMode.MODE_MODEL_VIEW;public static float mViewPortZNear = 0.0f;public static float mViewPortZFar = 1.0f;public static  GLColor mVertexColor = new GLColor(0, 0, 0);public static ArrayList<GLVertex> mVertexList = new ArrayList<GLVertex>();

从上面可以看到我们的变量基本上有以下几个

1. ModelView matrix

2.Project matrix

3.Viewport matrix

这几个矩阵就构成了把一个3D空间的(x,y,z)转换为2D空间的所有的东西。下面看看他们如何实现他们,与矩阵相关的几个函数如下:

矩阵模式

    public static void glMatrixMode(MatrixMode mode){mMatrixMode = mode;}

矩阵指定

glLoadIdentity

  public static void glLoadIdentity(){if(mMatrixMode == MatrixMode.MODE_MODEL_VIEW){mCurrentModelViewMatrix.setIdentity();}else{mCurrentProjectionMatrix.setIdentity();}}

矩阵保存

glPushMatrix

   public static void  glPushMatrix(){if(mMatrixMode == MatrixMode.MODE_MODEL_VIEW){mModelViewMatrixStack.push(new M4(mCurrentModelViewMatrix));}else{mProjectionMatrixStack.push(new M4(mCurrentProjectionMatrix));}}

矩阵恢复

glPopMatrix

    public static void  glPopMatrix(){if(mMatrixMode == MatrixMode.MODE_MODEL_VIEW){mCurrentModelViewMatrix = mModelViewMatrixStack.pop();}else{mCurrentProjectionMatrix = mProjectionMatrixStack.pop();}}

矩阵修改

glMultMatrix

  public static void glMultMatrix(M4 m){if(mMatrixMode == MatrixMode.MODE_MODEL_VIEW){mCurrentModelViewMatrix.multiply(m);}else{mCurrentProjectionMatrix.multiply(m);}}

ViewPort矩阵指定

    public static void glDepthRangef(float zNear,float zFar){mViewPortZNear = zNear;mViewPortZFar = zFar;}
   public static   void glViewport(int x,int y,int width,int height) {int surfaceHeight = mInfo.height;float far = mViewPortZFar;float near = mViewPortZNear;float sx = width/2.0f;float ox = sx + x;float sy = height/2.0f;float oy = sy + surfaceHeight - height - y;   float A = (far - near)/2.0f;float B = (far + near)/2.0f;// compute viewport matrixfloat[][] f = new float[4][4];f[0][0] = sx;  f[0][1] = 0;   f[0][2] = 0;  f[0][3] = ox;f[1][0] = 0;   f[1][1] =-sy;  f[1][2] = 0;  f[1][3] = oy;f[2][0] = 0;   f[2][1] = 0;   f[2][2] = A;  f[2][3] = B;f[3][0] = 0;   f[3][1] = 0;   f[3][2] = 0;  f[3][3] = 1;mCurrentViewPortMatrix = new M4();mCurrentViewPortMatrix.m = f;}

这下好了所有矩阵都有了,唯一的事情就是指定顶点和绘制方式了

2. 然后我们指定顶点

    public static  void glVertexPointer(int size,int type,int stride,java.nio.Buffer pointer) {if((type!= GL10.GL_FLOAT && type!= GL10.GL_FIXED) ||size != 3){throw new RuntimeException("this lib only support GL_FLOAT GL_FIXED type and size must equals 3, stride must equals 0!");}mVertexList.clear();int capacity = pointer.capacity();pointer.position(0);while(true){if(capacity >= size){capacity-=size;GLVertex verTex = new GLVertex();if(type == GL10.GL_FLOAT){verTex.x= ((FloatBuffer)pointer).get();verTex.y= ((FloatBuffer)pointer).get();verTex.z= ((FloatBuffer)pointer).get();}else if(type == GL10.GL_FIXED){verTex.x= ((IntBuffer)pointer).get()>>16;verTex.y= ((IntBuffer)pointer).get()>>16;verTex.z= ((IntBuffer)pointer).get()>>16;}mVertexList.add(verTex);if(capacity >= stride){capacity -= stride;for(int i = 0; i < stride; ++i){if(type == GL10.GL_FLOAT){((FloatBuffer)pointer).get();}else if(type == GL10.GL_FIXED){((IntBuffer)pointer).get();}}}else{break;}}else{break;}}}

看上去是不是很简单呢,接下就是绘制了

3. 最后我们绘制图像

 public static void glDrawElements(int mode, int mIndexCount,int type, Buffer mIndexBuffer) {if(mode!= GL10.GL_TRIANGLES){throw new RuntimeException();}if((type!= GL10.GL_UNSIGNED_SHORT&&type!=GL10.GL_UNSIGNED_BYTE) || mode != GL10.GL_TRIANGLES){throw new RuntimeException("this lib glDrawElements only support GL_TRIANGLES and GL_UNSIGNED_SHORT !");}mIndexBuffer.position(0);ArrayList<GLVertex> drawingList = preDealVertex();//clearColor();int capacity = mIndexCount;while(true){if(capacity >= 3){if(type == GL10.GL_UNSIGNED_SHORT){capacity-=3;ShortBuffer buffer = ((ShortBuffer)mIndexBuffer);GLVertex v1 = drawingList.get(buffer.get());GLVertex v2 = drawingList.get(buffer.get());GLVertex v3 = drawingList.get(buffer.get());drawTriangles(v1,v2,v3);}else if(type == GL10.GL_UNSIGNED_BYTE){capacity-=3;ByteBuffer buffer = ((ByteBuffer)mIndexBuffer);GLVertex v1 = drawingList.get(buffer.get());GLVertex v2 = drawingList.get(buffer.get());GLVertex v3 = drawingList.get(buffer.get());drawTriangles(v1,v2,v3);}}else{break;}}}

空间变换到此完成,可这只是万里长征的第一步。后面还有很多事情要做:

1.图元装配和裁剪:

图元装配发生在视口变换之前,图元装配上面已经做了,但是没有进行裁剪。

所以后面将研究如何将视景体之外的裁剪掉。

这个阶段主要有两个任务,一个是图元组装,另一个是图元处理。

  1. 所谓图元组装是指顶点数据根据设置的绘制方式被结合成完整的图元。例如,点绘制方式仅需要一个单独的顶点,此方式下每个顶点为一个图元;线段绘制方式则需要两个顶点,此方式下每两个顶点构成一个图元;三角形绘制方式下需要三个顶点构成一个图元。
  2. 图元处理最重要的工作是裁剪,其任务是消除位于半空间(half-space)之外的部分几何图元,这个半空间是由一个剪裁平面所定义的。例如,点剪裁就是简单的接受或者拒绝顶点,线段或者多边形剪裁可能需要增加额外的顶点,具体取决于直线或者多边形与剪裁平面之间的位置关系之所以要进行裁剪时因为随着观察位置角度的不同,并不总能看到(显示到设备屏幕上)特定3D物体某个图元的全部
  3. 裁剪时,若图元完全位于视景体以及自定义裁剪平面的内部,则将图元传递到后面的步骤进行处理;如果完全位于视景体或者自定义裁剪平面的外部,则丢弃该图元;如果其有一部分位于内部,另一部分位于外部,则需要裁剪该图元。

2. 光栅化:纹理插值

  • 1.虽然虚拟3D世界中的几何信息是三维的,但由于目前用于显示的设备都是二维的,因此在真正执行光栅化工作之前,首先要将虚拟3D世界汇总的物体投影到视平面上。根据摄像机位置的不同,同一个3D场景的物体投影到视平面可能会产生不同的效果。
  • 2.另外,由于虚拟3D世界当中物体的几何信息一般采用连续的数学量来表示,因此投影的平面结果也是用连续的数学量表示的。但目前的显示设备屏幕都是离散化的,因此还需要将投影的结果离散化。将其分解为一个一个离散化的小单元,这些小单元一般称之为片元。
    • 其实每个片元都对应帧缓冲中的一个像素,之所以不直接称之为像素是因为3D空间中的物体时可以相互遮挡的。而一个3D场景最终显示到屏幕上虽然是一个整体,但每个3D物体的每个图元是独立处理的。可能出现这种情况,系统先处理的是位于观察点较远的图元,其光栅化成为了一组片元,暂时送入帧缓冲的相对应位置。但后面继续处理距离观察点较远的图元是也光栅化了一组片元,两组片元中有对应到帧缓冲中同一个位置的,这时距离近的片元将覆盖距离远的片元(如何覆盖的检测是在深度检测阶段完成)。因此某片元就不一定能成为最终屏幕上的像素,称之为像素就不准确了,可以理解为候选像素。
    • 每个片元包含其对应的顶点坐标、顶点颜色、顶点纹理坐标以及顶点的深度等信息,这些信息是系统根据投影前此片元对应的3D空间中的位置及与此片元相关的图元的各顶点信息进行插值计算而生成的

3. 前后平面裁剪

如果需要源代码,请下载此软件到手机上。

http://a.app.qq.com/o/simple.jsp?pkgname=com.wa505.kf.epassword

参考文章

http://blog.csdn.net/u013746357/article/details/52799601

http://www.songho.ca/opengl/gl_transform.html

http://mobile.51cto.com/aengine-437172.htm

自己动手实现OpenGL-OpenGL原来如此简单(三)相关推荐

  1. 用opengl编写一个简单的画图软件示例代码

    //用opengl编写一个简单的画图软件示例代码(存在闪烁问题) //本代码,抄写自一本教授opengl的书,可惜,里面的代码存在一些问题,导致不能正常显示,现在是增加了一些语句的代码 #includ ...

  2. OpenGL《圣诞节主题三位场景动画》

    OpenGL<圣诞节主题三位场景动画>(分为五个部分介绍) 目录:第一部分 结果展示 ********第二部分 环境搭建 ********第三部分 加载3D模型(obj) ******** ...

  3. 关于openGL, openGL ES, openVG及android中2D调用关系的报告

    关于openGL, openGL ES, openVG及android中2D调用关系的报告 http://blog.chinaunix.net/u3/99423/showart_2203591.htm ...

  4. python装饰器–原来如此简单

    python装饰器–原来如此简单 今天整理装饰器,内嵌的装饰器.让装饰器带参数等多种形式,非常复杂,让人头疼不已.但是突然间发现了装饰器的奥秘,原来如此简单.... # -*- coding:gbk ...

  5. 修复手机通讯服务器软件,手机通讯录误删怎么恢复?恢复原来如此简单,后悔太晚知道...

    原标题:手机通讯录误删怎么恢复?恢复原来如此简单,后悔太晚知道 说起手机通讯录,它对于所有的手机用户来讲都是至关重要的.不知道你们有没有发生过误删重要联系人的情况,下面就给大家分享两种直接有效的还原方 ...

  6. ANN原来如此简单!——用Excel实现的MNIST手写数字识别(之三)

    ANN原来如此简单 人工神经网络目前仍然是一个火热的话题,许多人都对它充满了兴趣.然而,对于想了解ANN具体是怎么回事的同学来说,往往缺乏一个足够简单可视化的方法去了解神经网络的内部构造.网络上的各种 ...

  7. PHP开发群控,玩客云改群控的试玩体验,群控插件开发原来如此简单

    认识众多玩家高手/拆客/DIYer,查阅更多资源,一起学习技术知识 您需要 登录 才可以下载或查看,没有帐号?立即注册 x 上周参加小融的活动,把自己手里两台玩客云刷成了群控系统.刷机免费,开放API ...

  8. lstm处理时序数据结构图_LSTM原理与实践,原来如此简单

    LSTM原理与实践,原来如此简单 首发于公众号:机器学习荐货情报局 做干货最多的公众号,关注了不吃亏原创不易,转载请标明出处 目录 一.介绍 1.1 LSTM介绍 LSTM全称Long Short-T ...

  9. python卸载第三方库原来如此简单

    python卸载第三方库原来如此简单 打开CMD pip freeze>modules.txt pip uninstall -r modules.txt -y 第二步是将python库里面的第三 ...

  10. 专利科普:发明专利授权原来如此简单

    专利科普:发明专利授权原来如此简单 一.如何让发明专利具有更高的授权率 二.如何做到快速授权(发明3-9个月拿证) 三.材料工艺发明专利注意事项 四.机械领域发明的注意事项 五.计算机网络科研成果产生 ...

最新文章

  1. 浅析人类最贵、最大的机器学习模型GPT-3及背后隐含的商业逻辑
  2. 步步理解 JAVA 泛型编程 – 共三篇
  3. swagger 修改dto注解_Swagger 详解
  4. Python学习之类和实例
  5. C++ 整型所能表示的数据范围
  6. 《学习OpenCV3》第2章 OpenCV初探
  7. 如何给main传参数
  8. heartbeat+drbd+mysql高可用架构
  9. mysql blob 字段,mysql BLOB字段类型用法介绍
  10. IDEA:Windows 下载安装 IDEA 详细教程
  11. python就业班完整视频_('传智 Python基础班+就业班 最新完整视频教程',)
  12. android 检测cpu温度传感器,软件是如何测量手机CPU温度的?即使手机没有温度传感器...
  13. 从源码分析Redis分布式锁的原子性保证
  14. 【电脑技术】查杀U盘蠕虫病毒
  15. Java网络爬虫基础概述
  16. ES 创建索引设置(setting)基础
  17. mencoder 报错处理
  18. 实战项目:设计实现一个流程编排框架(分析)
  19. 关于商商城商品表设计(二)
  20. 入门篇-华为云分布式数据库中间件(DDM)创建逻辑库和逻辑表

热门文章

  1. mysql v8 漏洞_mysql'密码安全 - osc_v8gts6gd的个人空间 - OSCHINA - 中文开源技术交流社区...
  2. hook修改信息_React系列二十一 Hook(二)高级使用
  3. C++知识点48——类继承与类的作用域
  4. python时间序列峰值检测_python – 二维数组中的峰值检测
  5. 对python的认识800字_我对python里True和False的理解
  6. uiautomatorviewer_【问题】解决Android8.0以上运行不了uiautomatorviewer的办法
  7. java.lang.RuntimeException: Canvas: trying to draw too large(203212800bytes) bitmap.
  8. nginx 内核优化参数
  9. puppet 类、模块
  10. CSS3 Animation动画的十二原则