opengles之3D模型加载(obj模型文件)

时间:2022-11-18 04:45:43

效果图

opengles之3D模型加载(obj模型文件)

opengles之3D模型加载(obj模型文件)

opengles之3D模型加载(obj模型文件)

模型加载类

package test.com.opengles9_1;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;

import android.content.res.Resources;
import android.util.Log;
/**
* Created by hbin on 2016/9/9.
*/
public class LoadUtil {
//从obj文件中加载仅携带顶点信息的物体
public static LoadedObjectVertexOnly loadFromFile(String fname, Resources r,MySurfaceView mv)
{
LoadedObjectVertexOnly lo=null;

ArrayList<Float> alv=new ArrayList<Float>();//原始顶点坐标列表
ArrayList<Float> alvResult=new ArrayList<Float>();//结果顶点坐标列表

try
{
InputStream in=r.getAssets().open(fname);
InputStreamReader isr=new InputStreamReader(in);
BufferedReader br=new BufferedReader(isr);
String temps=null;

while((temps=br.readLine())!=null)
{
String[] tempsa=temps.split("[ ]+");
if(tempsa[0].trim().equals("v"))
{//此行为顶点坐标
alv.add(Float.parseFloat(tempsa[1]));
alv.add(Float.parseFloat(tempsa[2]));
alv.add(Float.parseFloat(tempsa[3]));
}
else if(tempsa[0].trim().equals("f"))
{//此行为三角形面
int index=Integer.parseInt(tempsa[1].split("/")[0])-1;
alvResult.add(alv.get(3*index));
alvResult.add(alv.get(3*index+1));
alvResult.add(alv.get(3*index+2));

index=Integer.parseInt(tempsa[2].split("/")[0])-1;
alvResult.add(alv.get(3*index));
alvResult.add(alv.get(3*index+1));
alvResult.add(alv.get(3*index+2));

index=Integer.parseInt(tempsa[3].split("/")[0])-1;
alvResult.add(alv.get(3*index));
alvResult.add(alv.get(3*index+1));
alvResult.add(alv.get(3*index+2));
}
}

//生成顶点数组
int size=alvResult.size();
float[] vXYZ=new float[size];
for(int i=0;i<size;i++)
{
vXYZ[i]=alvResult.get(i);
}
//创建物体对象
lo=new LoadedObjectVertexOnly(mv,vXYZ);
}
catch(Exception e)
{
Log.d("load error", "load error");
e.printStackTrace();
}
return lo;
}
}

package test.com.opengles9_1;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import android.opengl.GLES20;
/**
* Created by hbin on 2016/9/9.
* //加载后的物体——仅携带顶点信息
*/
public class LoadedObjectVertexOnly {
int mProgram;//自定义渲染管线着色器程序id
int muMVPMatrixHandle;//总变换矩阵引用
int maPositionHandle; //顶点位置属性引用
String mVertexShader;//顶点着色器代码脚本
String mFragmentShader;//片元着色器代码脚本

FloatBuffer mVertexBuffer;//顶点坐标数据缓冲
int vCount=0;

public LoadedObjectVertexOnly(MySurfaceView mv,float[] vertices)
{
//初始化顶点坐标与着色数据
initVertexData(vertices);
//初始化shader
initShader(mv);
}

//初始化顶点坐标的方法
public void initVertexData(float[] vertices)
{
//顶点坐标数据的初始化================begin============================
vCount=vertices.length/3;

//创建顶点坐标数据缓冲
//vertices.length*4是因为一个整数四个字节
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);
vbb.order(ByteOrder.nativeOrder());//设置字节顺序
mVertexBuffer = vbb.asFloatBuffer();//转换为Float型缓冲
mVertexBuffer.put(vertices);//向缓冲区中放入顶点坐标数据
mVertexBuffer.position(0);//设置缓冲区起始位置
//特别提示:由于不同平台字节顺序不同数据单元不是字节的一定要经过ByteBuffer
//转换,关键是要通过ByteOrder设置nativeOrder(),否则有可能会出问题
//顶点坐标数据的初始化================end============================
}

//初始化shader
public void initShader(MySurfaceView mv)
{
//加载顶点着色器的脚本内容
mVertexShader=ShaderUtil.loadFromAssetsFile("vertex_color.sh", mv.getResources());
//加载片元着色器的脚本内容
mFragmentShader=ShaderUtil.loadFromAssetsFile("frag_color.sh", mv.getResources());
//基于顶点着色器与片元着色器创建程序
mProgram = ShaderUtil.createProgram(mVertexShader, mFragmentShader);
//获取程序中顶点位置属性引用
maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
//获取程序中总变换矩阵引用
muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
}

public void drawSelf()
{
//制定使用某套着色器程序
GLES20.glUseProgram(mProgram);
//将最终变换矩阵传入着色器程序
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, MatrixState.getFinalMatrix(), 0);
// 将顶点位置数据传入渲染管线
GLES20.glVertexAttribPointer
(
maPositionHandle,
3,
GLES20.GL_FLOAT,
false,
3*4,
mVertexBuffer
);
//启用顶点位置数据
GLES20.glEnableVertexAttribArray(maPositionHandle);
//绘制加载的物体
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
}
}

绘制类
package test.com.opengles9_1;

import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.view.MotionEvent;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

/**
* Created by hbin on 2016/9/9.
*/
public class MySurfaceView extends GLSurfaceView {
private final float TOUCH_SCALE_FACTOR=180.0f/320;//角度缩放比例
private SceneRenderer mRenderer;//场景渲染器

private float mPreviousY;//上次的触控位置Y坐标
private float mPreviousX;//上次的触控位置X坐标


public MySurfaceView(Context context) {
super(context);
this.setEGLContextClientVersion(2);
mRenderer=new SceneRenderer();
setRenderer(mRenderer);
//设置渲染模式为主动渲染
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
}

//触摸事件回调方法
@Override
public boolean onTouchEvent(MotionEvent e)
{
float y=e.getY();
float x=e.getX();
switch (e.getAction())
{
case MotionEvent.ACTION_MOVE:
float dy=y-mPreviousY;//计算y方向位移
float dx=x-mPreviousX;//计算x方向位移
mRenderer.yAngle+=dx*TOUCH_SCALE_FACTOR;
mRenderer.xAngle+=dy*TOUCH_SCALE_FACTOR;
requestRender();//重绘画面
}

mPreviousY=y;//记录触控笔位置
mPreviousX=x;//记录触控笔位置
return true;
}

private class SceneRenderer implements GLSurfaceView.Renderer
{
float yAngle;//绕y轴旋转角度
float xAngle;//绕x轴旋转的角度
//从指定的obj文件中加载对象
LoadedObjectVertexOnly lovo;
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
//设置屏幕背景色RGBA
GLES20.glClearColor(0.0f,0.0f,0.0f,1.0f);
//打开深度检测
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
//打开背面剪裁
GLES20.glEnable(GLES20.GL_CULL_FACE);
//初始化变换矩阵
MatrixState.setInitStack();
//加载要绘制的物体
lovo=LoadUtil.loadFromFile("ch.obj",MySurfaceView.this.getResources(),
MySurfaceView.this);
}

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
//设置视窗大小及位置
GLES20.glViewport(0,0,width,height);
//计算GLSurface宽高比
float ratio=(float)width/height;
//计算透视投影矩阵
MatrixState.setProjectFrustum(-ratio,ratio,-1,1,2,100);
//计算摄像机9参数位置矩阵
MatrixState.setCamera(0,0,0,0f,0f,-1f,0f,1.0f,0.0f);
}

@Override
public void onDrawFrame(GL10 gl) {
//清除深度缓冲与颜色缓冲
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT|GLES20.GL_COLOR_BUFFER_BIT);
//坐标系推远
MatrixState.pushMatrix();
MatrixState.translate(0,-2f,-25f);
//绕y轴,x轴旋转
MatrixState.rotate(yAngle,0,1,0);
MatrixState.rotate(xAngle,1,0,0);

//若加载的物体不为空则绘制物体
if(lovo!=null)
{
lovo.drawSelf();
}
MatrixState.popMatrix();
}
}
}

项目下载地址

http://download.csdn.net/detail/hb707934728/9626495