android opengl es 变形效果

本文介绍了一个使用Android OpenGL ES实现3D物体变形效果的应用程序。程序包含四个核心类:VERTEX(定义3D顶点),OBJECT(存储顶点的3D对象),Morphing(处理按键并返回InputStream)和MyRenderer(负责绘制)。通过加载txt文本文件的数据,程序能够创建3D物体,并在用户按下按键时执行变形动画。在onDrawFrame方法中,程序根据变形步数更新顶点位置,实现平滑的变形效果。
摘要由CSDN通过智能技术生成

这个小程序需要的三个txt文本文件在被粘在示例图后面, 此变形效果程序分为以下四个类

(1)Morphing 除主功能外在本程序中还有按键处理及返回InputStream

(2)MyRenderer 负责绘制

(3)OBJECT 三维物体类

(4)VERTEX 三维顶点类

 


从最简单的VERTEX 类开始,可见此类主要映射三维各顶点

package sim.feel;
/**
 * 三维顶点类
 * @author Sim
 */
public class VERTEX {
    float x, y, z;

    public VERTEX(float x, float y, float z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
}

 

 

接下来是OBJECT类此声明了顶点数及将x,y,z保存到一个List中

 

package sim.feel;

import java.util.ArrayList;
import java.util.List;

/**
 * 三维物体类
 *
 * @author Sim
 */
public class OBJECT {
    // 顶点数
    int verts;
    List<VERTEX> points = new ArrayList<VERTEX>();
}


接下来是Morphing类,此类则是按键处理与返回InputStream

package sim.feel;

import java.io.IOException;
import java.io.InputStream;

import android.app.Activity;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Window;
import android.view.WindowManager;

public class Morphing extends Activity {
    private MyRenderer myRenderer = new MyRenderer();
    private GLSurfaceView glSurfaceView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 无标题栏
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        // 全屏
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        new LoadFile(getResources());
        glSurfaceView = new GLSurfaceView(this);
        glSurfaceView.setRenderer(myRenderer);
        setContentView(glSurfaceView);
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        return myRenderer.onKeyUp(keyCode, event);
    }

}

// 返回File的InputStream

class LoadFile {
    public static Resources res;

    public LoadFile(Resources resources) {
        LoadFile.res = resources;
    }

    public static InputStream getFile(String name) {
        AssetManager am = LoadFile.res.getAssets();
        try {
            return am.open(name);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}

 

最后就是我们的MyRenderer类,它是最复杂的一个类,主要包含了加载txt文本文件,按键,及三个要实现的方法

 

package sim.feel;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.Random;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLSurfaceView.Renderer;
import android.view.KeyEvent;

public class MyRenderer implements Renderer {
    // X,Y,Z轴的旋转角度
    private float xrot, yrot, zrot;
    // X,Y,Z 轴的旋转速度
    private float xspeed, yspeed, zspeed;
    // 物体的位置
    private float cx, cy, cz = -15;
    // 随机
    private Random random = new Random();
    // 变换的步数
    private int step = 0, steps = 200;
    // 是否使用变形
    private boolean morph = false;
    // verticesBuffer
    FloatBuffer verticesBuffer;
    // colorsBuffer
    FloatBuffer colorsBuffer;
    // vertices
    private float[] vertices = new float[486];
    // colors
    private float[] colors = new float[486];
    // 我们的四个物体,帮助物体,原物体,目标物体
    OBJECT morph1 = new OBJECT();
    OBJECT morph2 = new OBJECT();
    OBJECT morph3 = new OBJECT();
    OBJECT morph4 = new OBJECT();

    OBJECT helper = new OBJECT();
    OBJECT sour = new OBJECT();
    OBJECT dest = new OBJECT();


    // LoadBuffer
    public void LoadBuffer() {
        ByteBuffer verticesByteBuffer = ByteBuffer
                .allocateDirect(vertices.length * 9 * 4);
        verticesByteBuffer.order(ByteOrder.nativeOrder());
        verticesBuffer = verticesByteBuffer.asFloatBuffer();
        verticesBuffer.put(vertices);
        verticesBuffer.position(0);

        ByteBuffer colorsByteBuffer = ByteBuffer
                .allocateDirect(colors.length * 4 * 12);
        colorsByteBuffer.order(ByteOrder.nativeOrder());
        colorsBuffer = colorsByteBuffer.asFloatBuffer();
        colorsBuffer.put(colors);
        colorsBuffer.position(0);

    }

    @Override
    public void onDrawFrame(GL10 gl) {
        LoadBuffer();
        // 清除屏幕和深度缓存
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        // 重置模型变换矩阵
        gl.glLoadIdentity();
        gl.glTranslatef(cx, cy, cz);
        // 旋转
        gl.glRotatef(xrot, 1, 0, 0);
        gl.glRotatef(yrot, 0, 1, 0);
        gl.glRotatef(zrot, 0, 0, 1);

        // 根据旋转速度,增加旋转角度
        xrot += xspeed;
        yrot += yspeed;
        zrot += zspeed;

        // 顶点临时变量
        float tx, ty, tz;
        // 保存中间计算的临时顶点
        VERTEX q = new VERTEX(0, 0, 0);

        // 启用顶点及颜色
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);

        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, verticesBuffer);
        gl.glColorPointer(2, GL10.GL_FLOAT, 0, colorsBuffer);

        // 绘制模型中的点
        colorsBuffer.clear();
        verticesBuffer.clear();
        // 循环绘制模型1中的每一个顶点
        for (int i = 0; i < morph1.verts; i++) {
            // 如果启用变形,则计算中间模型
            if (morph) {
                q = calculate(i);
            } else {
                q.x = q.y = q.z = 0;
            }
            helper.points.get(i).x -= q.x;
            helper.points.get(i).y -= q.y;
            helper.points.get(i).z -= q.z;
            // 保存计算结果到tx,ty,tz变量中
            tx = helper.points.get(i).x;
            ty = helper.points.get(i).y;
            tz = helper.points.get(i).z;

            colorsBuffer.put(0.0f);
            colorsBuffer.put(1.0f);
            colorsBuffer.put(1.0f);
            colorsBuffer.put(1.0f);

            verticesBuffer.put(tx);
            verticesBuffer.put(ty);
            verticesBuffer.put(tz);

            colorsBuffer.put(0.0f);
            colorsBuffer.put(0.5f);
            colorsBuffer.put(1.0f);
            colorsBuffer.put(1.0f);
            // 如果启用变形,则绘制2步后的顶点
            tx -= 2 * q.x;
            ty -= 2 * q.y;
            ty -= 2 * q.y;
            verticesBuffer.put(tx);
            verticesBuffer.put(ty);
            verticesBuffer.put(tz);

            colorsBuffer.put(0.0f);
            colorsBuffer.put(0.0f);
            colorsBuffer.put(1.0f);
            colorsBuffer.put(1.0f);
            tx -= 2 * q.x;
            ty -= 2 * q.y;
            ty -= 2 * q.y;
            verticesBuffer.put(tx);
            verticesBuffer.put(ty);
            verticesBuffer.put(tz);
        }
        gl.glDrawArrays(GL10.GL_POINTS, 0, morph1.verts * 3);

        // 禁用顶点及颜色
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glDisableClientState(GL10.GL_COLOR_ARRAY);

        if (morph && step <= steps) {
            step++;
        } else {
            morph = false;
            sour = dest;
            step = 0;
        }
        gl.glFinish();

    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        float ratio;
        if (height == 0) {
            height = 1;
        }
        ratio = (float) width / (float) height;
        gl.glViewport(0, 0, width, height);
        gl.glMatrixMode(GL10.GL_PROJECTION);
        gl.glLoadIdentity();
        gl.glFrustumf(-ratio, ratio, -1, 1, 2.0f, 100.0f);
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity();
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        // 设置半透明模式
        gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE);
        // 设置清除色为黑色
        gl.glClearColor(0, 0, 0, 0);
        // 设置深度缓存中值为1
        gl.glClearDepthf(1.0f);
        // 设置深度测试函数
        gl.glDepthFunc(GL10.GL_LESS);
        // 启用深度测试
        gl.glEnable(GL10.GL_DEPTH_TEST);
        // 设置着色模式为光滑着色
        gl.glShadeModel(GL10.GL_SMOOTH);
        // 精细修正
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);

        objload("sphere.txt", morph1);
        objload("torus.txt", morph2);
        objload("tube.txt", morph3);

        for (int i = 0; i < 486; i++) {
            float xx = ((float) (rand() % 14000) / 1000) - 7;
            float yy = ((float) (rand() % 14000) / 1000) - 7;
            float zz = ((float) (rand() % 14000) / 1000) - 7;
            morph4.points.add(new VERTEX(xx, yy, zz));
        }
        objload("sphere.txt", helper);
        sour = dest = morph1;

    }

    // 随机数
    public int rand() {
        return Math.abs(random.nextInt());
    }

    // 计算第i个顶点每次变换的位移
    public VERTEX calculate(int i) {
        VERTEX a = new VERTEX(0, 0, 0);
        a.x = (sour.points.get(i).x - dest.points.get(i).x) / steps;
        a.y = (sour.points.get(i).y - dest.points.get(i).y) / steps;
        a.z = (sour.points.get(i).z - dest.points.get(i).z) / steps;
        return a;
    }

    // 读取文件顶点数
    public String readstr(BufferedReader br) {
        String str = "";
        // 因为第一行为注释,所以此方法读取的是第二行
        do {
            try {
                str = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } while ((str.charAt(0) == '/') || (str.charAt(0) == '/n'));
        return str;
    }

    // 将所有顶点装载到List就是points中
    public void objload(String name, OBJECT k) {
        int ver = 0;
        String oneline;
        int i;
        BufferedRead

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值