学了这么久的Android OpenGL的知识,今天花一部分时间实现一个三角形隧道的效果,这个案例结合了一些基础的Android OpenGL ES的知识点,效果图如下图所示。

三角隧道效果示图

首先,在GLSurfaceView的渲染器Render中实现onSurfaceCreated方法,该方法主要完成屏幕的初始化操作等,包括屏幕颜色清空,允许深度缓存测试,设置灯光光效等。这里解释下深度缓存测试,启用了深度缓存之后,OpenGL在绘制的时候就会检查,当前像素前面是否有别的像素,如果别的像素挡道了它,那它就不会绘制,也就是说,OpenGL就只绘制最前面的一层,所以需要绘制透明图片时,就需要关闭它。

@Override

public void onSurfaceCreated(GL10 gl, EGLConfig config) {

//告诉系统要进行视图修正,表示颜色和纹理坐标插补的质量

gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);

//屏幕颜色清空

gl.glClearColor(0, 0, 0, 1);

//应用深度缓存,当颜色深度一致时,后者绘制的图像不会在前者之上绘制

gl.glEnable(GL10.GL_DEPTH_TEST);

//初始化app

initApp(gl);

//设置灯光光效

setUpLight(gl);

}

setUpLight(gl)用于设置光效,执行步骤为:开启光效à使用0号光源à设置环境光à设置散射光à设置聚焦光。

private void setUpLight(GL10 gl) {
    //开启光效
    gl.glEnable(GL10.GL_LIGHTING);
    //使用0号光源
    gl.glEnable(GL10.GL_LIGHT0);
    //环境光颜色
    FloatBuffer lightAmbient = FloatBuffer.wrap(new float[]{0.4f, 0.4f, 0.4f, 1});
    //设置环境光
    gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, lightAmbient);
    //设置散射光
    FloatBuffer lightDiffuse = FloatBuffer.wrap(new float[]{0.8f, 0.8f, 0.8f, 1});
    gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, lightDiffuse);
    //设置聚焦光
    FloatBuffer lightPosition = FloatBuffer.wrap(new float[]{10f, 10f, 10f});
    gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightPosition);
}

接着当程序执行到onSurfaceChanged方法时,在这个方法中设置视口大小,设置透视投影,创建初始的透视投影矩阵。gl.glLoadIdentity()的目的是将居住重置,这样操作以后之前的矩阵状态都会失效。

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
    float radio=(float)width/(float)height;
    gl.glViewport(0,0,width,height);
    //设置透视投影
    gl.glMatrixMode(GL10.GL_PROJECTION);
    //glLoadIdentity()的作用就是把矩阵堆栈中的在栈顶的那个矩阵置为单位矩阵,好让之前的任何变换都不影响后面的变化。
    gl.glLoadIdentity();
    //创建一个对称的透视投影矩阵
    GLU.gluPerspective(gl,45.0f,radio,1f,10f);
}

OpenGL有两种投影:正射投影(垂直投影)和透视投影。透视投影通过指定一个平截头体来定义视见体的范围(如下图所示,人的位置相当于摄像机,中间物体为拍摄物体位置);

void gluPerspective (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)

fovy是眼睛上下睁开的幅度,角度值,值越小,视野范围越狭小(眯眼),值越大,视野范围越宽阔(睁开铜铃般的大眼),在我们的代码这个参数是45.0f;

zNear表示近裁剪面到眼睛的距离,zFar表示远裁剪面到眼睛的距离,注意zNear和zFar不能设置设置为负值(你怎么看到眼睛后面的东西);

aspect表示裁剪面的宽w高h比,这个影响到视野的截面有多大;

透视投影原理图

接着就执行到了onDrawFrame的方法了,每次执行都要清除颜色和深度缓存,设置摄像机观测点矩阵,位置在(0,0,1)位置,开启顶点,颜色,纹理绘制功能,执行绘制,关闭顶点,颜色,纹理贴图等功能。

@Override
public void onDrawFrame(GL10 gl) {//清除颜色和深度缓存gl.glClear(GL10.GL_COLOR_BUFFER_BIT|GL10.GL_DEPTH_BUFFER_BIT);//设置模型观测试点矩阵gl.glMatrixMode(GL10.GL_MODELVIEW);//重置矩阵gl.glLoadIdentity();//视点变换,eyex, eyey,eyez 相机在世界坐标的位置,centerx,centery,centerz 相机镜头对准的物体在世界坐标的位置//第一组数据就是脑袋的位置//第二组数据就是眼睛看的物体的位置//第三组就是头顶朝向的方向(因为你可以歪着头看同一个物体)。GLU.gluLookAt(gl, 0, 0, 1, centerX, centerY, 0, 0, 1, 0);//设置平滑的渲染模式gl.glShadeModel(GL10.GL_SMOOTH);//允许绘制顶点
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);gl.glEnableClientState(GL10.GL_COLOR_ARRAY);gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);mTunnel3D.render(gl,-0.6f);mTunnel3D.nextFrame();gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);gl.glDisableClientState(GL10.GL_COLOR_ARRAY);gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}
具体的绘制操作被放在试题类Tunnel3D中完成,下面来看下Tunnel3D的一些操作。Tunnel3D执行初始化变量操作,
public Tunnel3D(int revolution, int depth) {start_a = 0;start_v = 0;nx = revolution;ny = depth;nv = nx * ny;colors = new byte[nv * 3];vertics = new float[nv * 3];faces = new short[((nx + 1) * (ny - 1)) << 1];texture = new float[nv * 2];//生成数据genVertex();genFaces();genColors();genTexture();buildBuffers();fillVertex();fillFaces();fillColors();fillTexture();
}
genVertex函数用于生成顶点的坐标数组,这里采用三角变化函数的用法进行生成。
//产生顶点坐标
private void genVertex() {int i = 0;double delta_x = 360.0 / (double) nx;double delta_y = 1.0;for (int y = 0; y < ny; y++) {for (int x = 0; x < nx; x++) {//sin度的计算值vertics[i + 0] = (float) Math.sin(Math.toRadians((double) x * delta_x));vertics[i + 1] = (float) Math.cos(Math.toRadians((double) x * delta_x));//todovertics[i + 2] = (float) (-y * delta_y);i += 3;}}Log.v("Yu","vertics:"+vertics);
}
buildBuffers函数用于数组转buffer的操作,对于openGL来说操作都是通过buffer来进行的。
private void buildBuffers() {vertices_direct = ByteBuffer.allocateDirect(vertics.length * (Float.SIZE >> 3));vertices_direct.order(ByteOrder.nativeOrder());vertices_buffer = vertices_direct.asFloatBuffer();faces_direct = ByteBuffer.allocateDirect(faces.length * (Short.SIZE >> 3));faces_direct.order(ByteOrder.nativeOrder());faces_buffer = faces_direct.asShortBuffer();
//        colors_direct = ByteBuffer.allocateDirect(colors.length * (Float.SIZE >> 3));
//        colors_direct.order(ByteOrder.nativeOrder());
//        colors_buffer = colors_direct.asFloatBuffer();colors_buffer = ByteBuffer.allocateDirect(colors.length);texture_direct = ByteBuffer.allocateDirect(texture.length * (Float.SIZE >> 3));texture_direct.order(ByteOrder.nativeOrder());texture_buffer = texture_direct.asFloatBuffer();}
//填充vertex
private void fillVertex() {vertices_buffer.clear();vertices_buffer.put(vertics);vertices_buffer.position(0);
}
渲染render函数用于执行三角隧道的渲染,最后通过gl.glDrawArrays绘制三角形。
 //渲染隧道
 public void render(GL10 gl, float depth) {//gl.glTranslatef(-px, -py, depth);//顶点,有 x、y、z值,所以是 3gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertices_buffer);//贴图顶点有两个u和vgl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texture_buffer);//颜色有3个值r,g,bgl.glColorPointer(3, GL10.GL_UNSIGNED_BYTE, 0, colors_buffer);
//        int dy = 0;
//        int nf = (nx + 1) << 1;
//        faces_buffer.position(0);
//        for (int y = 0; y < (ny - 1); y++) {
//            //Log.v("Yu","标记:"+y);
//            gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, nf, GL10.GL_UNSIGNED_BYTE, faces_buffer);
//            dy += nf;
//            faces_buffer.position(dy);
//        }//绘制三角形带gl.glDrawArrays(GL10.GL_TRIANGLES, 0, vertics.length);}
nextFrame函数用于下一帧坐标位置变化的操作。
public void nextFrame() {int i = 0;double delta_x = 360 / nx;double delta_y = 1.0;double delta_z = 220 / ny;for (int y = 0; y < ny; y++) {double sa = start_a + (ny - y) * delta_z;float sx = (float) Math.cos(Math.toRadians(sa));float sy = (float) Math.sin(Math.toRadians(sa));if (y == 0) {px = sx;py = sy;}for (int x = 0; x < nx; x++) {vertics[i + 0] = sx + (float) Math.sin(Math.toRadians((double) x * delta_x));vertics[i + 1] = sy + (float) Math.cos(Math.toRadians((double)x * delta_x));vertics[i + 2] = (float) (-y * delta_y);i += 3;}}start_a += 2;fillVertex();i = 0;delta_x = 1 / nx;delta_y = 1 / ny;for (int y = 0; y < ny; y++) {for (int x = 0; x < nx; x++) {texture[i + 0] = (float) x * (float) delta_x;texture[i + 1] = start_v + (float) y * (float) delta_y;}}start_v += 0.05f;fillTexture();
}

以上就是三角隧道效果的代码,完整代码可以到本人的GitHub上下载

地址:https://github.com/HOTFIGHTER/OpenGL-for-Android

最后感谢收看,有问题多交流!!!

Android图形编程篇--OpenGL实现三角形隧道效果相关推荐

  1. Android图形图像处理:马赛克(Mosaic)效果【直接可用】

    首先看效果 然后这是代码 /*** Create by Mazhanzhu on 2020/9/25* Android图形图像处理:马赛克(Mosaic)效果*/ public class Mosai ...

  2. android图形编程,Android图形编程基础

    Color //方法1 int color1 = Color.BLUE; //方法2 int color2 = Color.argb(177, 255,255,255); //方法3:在xm l里面定 ...

  3. ps2摇杆android图形编程,ROC-RK3308-CC开发实例总结--PS2 Joystick摇杆模块

    本帖最后由 Demon 于 2019-4-8 17:58 编辑 最近本人又调试了一款比较有趣的传感器模块--PS2  Joystick摇杆模块.下面将本人的测试方法分享于大家,下文仅个人见解,若有不足 ...

  4. Android图形图像处理:马赛克(Mosaic)效果

    以图形图像界经典的实验例图Lenna为例,当手指在图片上滑过后,形成马赛克的: 写一个MosaicView继承自AppCompatImageView: package com.zhangphil;im ...

  5. Android开发——图形编程(一)简单介绍与使用绘图类Paint、Canvas

    Android图形编程基础 文章目录 Android图形编程基础 画笔Paint的 画布Canvas 自定义View的基本实现方法 实例代码 绘图绘图,首先要有的就是颜色Color Android系统 ...

  6. OpenGL基础图形编程(八)变换

    八.OpenGL变换 OpenGL变换是本篇的重点内容,它包括计算机图形学中最基本的三维变换,即几何变换.投影变换.裁剪变换.视口变换,以及针对OpenGL的特殊变换概念理解和用法,如相机模拟.矩阵堆 ...

  7. OpenGL基础图形编程

    一.OpenGL与3D图形世界 1.1.OpenGL使人们进入三维图形世界 我们生活在一个充满三维物体的三维世界中,为了使计算机能精确地再现这些物体,我们必须能在三维空间描绘这些物体.我们又生活在一个 ...

  8. 【转】OpenGL基础图形编程(一)

    原文:http://blog.chinaunix.net/uid-20638550-id-1909183.html  分类: 一.OpenGL与3D图形世界 1.1.OpenGL使人们进入三维图形世界 ...

  9. OpenGL基础图形编程(转)

    一.OpenGL与3D图形世界 1.1.OpenGL使人们进入三维图形世界 我们生活在一个充满三维物体的三维世界中,为了使计算机能精确地再现这些物体,我们必须能在三维空间描绘这些物体.我们又生活在一个 ...

  10. OpenGL基础图形编程(一)

    一.OpenGL与3D图形世界 1.1.OpenGL使人们进入三维图形世界 我们生活在一个充满三维物体的三维世界中,为了使计算机能精确地再现这些物体,我们必须能在三维空间描绘这些物体.我们又生活在一个 ...

最新文章

  1. C++中的 istringstream
  2. matlab欧拉迭代,matlab机械臂正逆运动学求解问题,使用牛顿-欧拉迭代算法
  3. 新疆电信IBSS系统集中联机热备份--案例
  4. Stm32 IAP程序编写及用户程序编写
  5. drools6.5_使用Drools 6.0进行部署
  6. 50個AJAX Tools and Frameworks
  7. hdu 1874 畅通project续
  8. Python如何提取docx中的超链接
  9. CMOS checksum error-Defaults loaded 故障解决办法
  10. hexo version control
  11. 求一个整数数组中和最大的连续子数组,例如:[1, 2, -4, 4, 10, -3, 4, -5, 1]的最大连续子数组是[4, 10, -3, 4]
  12. 【下载】无线电杂志上下册合集2006-2011
  13. 数据库出错提示Duplicate entry * for key *的解决方法
  14. Java开发工程师大厂面试常见问题总结(应届生版)
  15. ios系统访问ftp服务器,ios系统访问ftp服务器
  16. 用计算机画函数,用计算机画函数图像 优质课教案设计
  17. android最强论坛,Android开发论坛
  18. Python订票系统这才是看电影选座的正确方法,原来我们都上当了
  19. 【Autoware规控】mpc_follower模型预测控制节点
  20. c语言的int型运算符,C语言运算符

热门文章

  1. ContentProvider
  2. iPhone 开发常用工具
  3. SQL SELECT完整语法
  4. 天刃_张志刚_SEO优化技巧
  5. web视频(点播/直播)播放器选型
  6. 朋友圈爱心拼图php源码_微信朋友圈九宫格爱心拼图怎么弄 拼图教程
  7. java8-常用stream操作(1)
  8. SAP ABAP内表OCCURS,WORK AREA等 语法对比!
  9. 游戏的现实规则和非现实规则
  10. 一年级有计算机教学吗,一年级信息技术教学计划范文