游戏开发论坛

 找回密码
 立即注册
搜索
查看: 15550|回复: 8

android openglES20 下多材质组obj文件导入的例子

[复制链接]

33

主题

159

帖子

272

积分

中级会员

Rank: 3Rank: 3

积分
272
QQ
发表于 2012-8-27 12:21:00 | 显示全部楼层 |阅读模式


本例实现由 obj文件读取 3d mesh 信息(支持多材质OBJ文件),
并使用自定义渲染管线进行渲染
,简单地测试了一个由2个材质组构成的 3d obj文件

由于之前是直接从direct跳到 glse,中间没有学过 opengl 所以框架开发上沿用了之前在direct开发中的模式

框架中通用部分有以下几类:
        G9Render 渲染器类,控制模型进管线
        G9Camera 摄像机类,(光源也作为摄像机传入,学DIRECT的后遗症)
        G9Mesh 类主控 3D网格的构建与引用(mesh类无矩阵,所以可以多次引用)
        G9Model 类为模型,这里模型与网格是不同的概念, mesh主是简单地网格,不存在于空间概念中,而model是网格存在于世界的位置信息
                        模型与网格分开的好处是显而易见的,一个网格可以被多个模型引用并显示在世界的不同位置不同大小
                        到了渲染期,从G9Model中取世界矩阵, camera中取视矩阵与投影,再从 G9mesh类中取MeshInfo(网格的各个subsets中的顶点信息)
                        进入EFFECT管线后渲染
        ModelCollection 类是简单的模型队列,进入渲染器的数据区
       
       
框架外的两个类
        MainActivity 喵
        MyGame0824 是一个 派生自GlGameView的类(基类是 glSurfaceView),在G9GameView中,增加了InitCamera InitModel的虚方法
                (原因我写在程序里面了,发现android 的 gles20 的调用顺序很混乱,有几个操作必须在 onSurfaceCreated之后才能进行)



例子下载

58

主题

1437

帖子

2207

积分

金牌会员

Rank: 6Rank: 6

积分
2207
发表于 2012-8-27 12:25:00 | 显示全部楼层

Re:android openglES20 下多材质组obj文件导入的例子

喵了咪,香蕉很好,黄瓜也不错

33

主题

159

帖子

272

积分

中级会员

Rank: 3Rank: 3

积分
272
QQ
 楼主| 发表于 2012-8-27 12:29:00 | 显示全部楼层

Re: android openglES20 下多材质组obj文件导入的例子

例程链接

http://upload.gameres.com/20128/sf_27122650_4628.zip

然后我要开始发牢骚了,OPENGL这东西怪不得要被DX比下去,算法支撑实在太差了吧,要是从网上去下载开源的算法类,又怕算法的效率不高影响FPS
毕竟3D里面很多东西都是每帧要算的.
GLES里连基础的三元四元的 dot cross 及向量按变换矩阵变换的方法都没
matrix vector vertex什么的全是 float[] 搞的很多时候还要浪费同行 if(para1.length !=3).....
在 这个例程里做了个算法支撑类 G9Function 虽然还很不完善,但还是补充了几个常用的计算

PS: 想在杭州找个工作,熟悉C++ C# DIRECT9.0,
   会点儿 java 和 android gles20
完全自学的,没什么证书,年纪不小,现工作于国企

33

主题

159

帖子

272

积分

中级会员

Rank: 3Rank: 3

积分
272
QQ
 楼主| 发表于 2012-8-27 12:33:00 | 显示全部楼层

Re: android openglES20 下多材质组obj文件导入的例子

下面是矩阵和向量的一些个小小算法,初学的可以看下呵,事实上写完了之后才知道有 android-GL这个东东,不过总觉得自己写的用起来实在

public final class G9Function {
        /**
         * 用于向量的规格化,注意只支持float[3],在内部扔出异常 没扔到外部去了 所以DEBUG时要注意加断点
         * */
        public static void glV3Normalize(float[] vecInOut){
                int iSize =vecInOut.length;
                if(iSize !=3)
                {
                        throw new RuntimeException("err in glV3Normalize");//       
                }
                float fScale = (float)Math.sqrt(vecInOut[0]*vecInOut[0]+vecInOut[1]*vecInOut[1]+vecInOut[2]*vecInOut[2]);
                if(fScale == 0)
                        return;
                fScale = 1/fScale;//喵的,除法会不会很费时?
                for(int i=0;i<iSize; i++)
                {
                        vecInOut *= fScale;
                }
                return;               
       
        }//ef
        /**
         * 叉积函数,进函数前参数请注意normalize(),只支持3元向量
         * */
        public static void glV3Cross(float[] v3OUT,float[] v3A,float[] v3B){
                //参数检测
                if((v3OUT.length !=3)||(v3A.length !=3)||v3B.length!=3){

                        throw new RuntimeException("err in glV3Cross");
                }
                /*
                v3OUT[0] =  v3B[1]*v3A[2]-v3A[1]*v3B[2];
                v3OUT[1] =  v3B[2]*v3A[0]-v3A[2]*v3B[0];
                v3OUT[2] =  v3B[0]*v3A[1]-v3A[0]*v3B[1];
                */
                v3OUT[0] =  v3A[1]*v3B[2]-v3B[1]*v3A[2];
                v3OUT[1] =  v3A[2]*v3B[0]-v3B[2]*v3A[0];
                v3OUT[2] =  v3A[0]*v3B[1]-v3B[0]*v3A[1];
                return;
        }//ef
        /**
         * 点积函数,进函数前注意normalize() 只支持3元向量
         */
        public static float glV3Dot(float[] v3A,float[] v3B){
                if((v3A.length !=3)||v3B.length!=3){
                       
                        throw new RuntimeException("err in glV3Dot");
                }
                return v3A[0]*v3B[0] + v3A[1]*v3B[1] + v3A[2]*v3B[2];
               
        }//ef
        /**
         * 三元向量相加 (参数必须normalize后才有意义,即 v3Dst是后两个向量的中间插值)
         * @param v3Dst 输出
         * @param v3LParam 左参
         * @param v3RParam 右参
         */
        public static void glV3Add(float[] v3Dst,float[] v3LParam,float[] v3RParam){
                if((v3Dst.length !=3 )||(v3LParam.length != 3)|| (v3RParam.length!=3))
                        throw new RuntimeException("err in glV3Add");
                for(int i=0; i<3; i++){
                        v3Dst = v3LParam+v3RParam;
                }
        }//ef
        /**
         * 三元量(位置v3Position)相减
         *                 注意,作为位置信息的参数不应该规格化
         * @param v3Dst 输出,即v3R点到v3L点的向量
         * @param v3LParam 左参
         * @param v3RParam 右参
         */
        public static void glV3Subtract(float[] v3Dst,float[] v3LParam,float[] v3RParam){
                if((v3Dst.length !=3 )||(v3LParam.length != 3)|| (v3RParam.length!=3))
                        throw new RuntimeException("err in glV3Add");
                for(int i=0; i<3; i++){
                        v3Dst = v3LParam-v3RParam;
                }
        }//ef
        /**
         * 3元向量变换,mxXform是变换矩阵 注意会改变参数的3元量!!
         * */
        public static void glV3Transform(float[] v3InOut,float[] mxXform)
        {
                if((v3InOut.length !=3)||(mxXform.length !=16))
                        throw new RuntimeException("err in glV3Transform");
                float f0,f1,f2;
                /*
                f0 = v3InOut[0]*mxXform[0] + v3InOut[1]*mxXform[1] +
                                v3InOut[2]*mxXform[2]+v3InOut[3]*mxXform[3];
                f1 = v3InOut[0]*mxXform[4] + v3InOut[1]*mxXform[5] +
                                v3InOut[2]*mxXform[6]+v3InOut[3]*mxXform[7];
                f2 = v3InOut[0]*mxXform[8] + v3InOut[1]*mxXform[9] +
                                v3InOut[2]*mxXform[10]+v3InOut[3]*mxXform[11];
                */
                f0 = v3InOut[0]*mxXform[0] + v3InOut[1]*mxXform[4] +v3InOut[2]*mxXform[8] + 1*mxXform[12];
                               
                f1 =  v3InOut[0]*mxXform[1] + v3InOut[1]*mxXform[5] +v3InOut[2]*mxXform[9] + 1*mxXform[13];
               
                f2 =  v3InOut[0]*mxXform[2] + v3InOut[1]*mxXform[6] +v3InOut[2]*mxXform[10] + 1*mxXform[14];
                v3InOut[0] = f0;
                v3InOut[1] = f1;
                v3InOut[2] = f2;
                return;
               
        }//ef
        /**
         * 4元向量变换,mxXform是变换矩阵 注意会改变参数的3元量
         * */
        public static void glV4Transform(float[] v4InOut,float[] mxXform)
        {
                if((v4InOut.length !=4)||(mxXform.length !=16))
                        throw new RuntimeException("err in glV3Transform");
                float f0,f1,f2,f3;
                f0 = v4InOut[0]*mxXform[0] + v4InOut[1]*mxXform[1] +
                                v4InOut[2]*mxXform[2]+v4InOut[3]*mxXform[3];
                f1 = v4InOut[0]*mxXform[4] + v4InOut[1]*mxXform[5] +
                                v4InOut[2]*mxXform[6]+v4InOut[3]*mxXform[7];
                f2 = v4InOut[0]*mxXform[8] + v4InOut[1]*mxXform[9] +
                                v4InOut[2]*mxXform[10]+v4InOut[3]*mxXform[11];
                f3 = v4InOut[0]*mxXform[12] + v4InOut[1]*mxXform[13] +
                                v4InOut[2]*mxXform[14]+v4InOut[3]*mxXform[15];
                v4InOut[0] = f0;
                v4InOut[1] = f1;
                v4InOut[2] = f2;
                v4InOut[3] = f3;
                return;
               
        }//ef
        /**         
         * 任意轴旋转  mxOut为传出矩阵  fAngle为角度, v3axis喵的,是中轴
         * 测试通过,但与D3D里的同价函数比较后,两个出的矩阵是完全相反的,应该是左右手不同造成的
         *与GL相关旋转函数比较后一致
         */
        public static void glRotateAxis(float[] mxOut,float fAngle,float[] v3Axis){
                //先检错               
                if((mxOut.length !=16)||(v3Axis.length!=3))
                {

                        throw new RuntimeException("err in glRotateAxis");
                }
                //不改变v3Axis 复制一个后去规格化
                float[] v3a = glV3Copy(v3Axis);
                glV3Normalize(v3a);
                // ux v3a[0] ;uy = v3a[1] ; uz = v3a[2];
                float s = (float)Math.sin(Math.toRadians(fAngle));//转角sin值
                float c = (float)Math.cos(Math.toRadians(fAngle));//转角cos值
                //还是按书里的矩阵推导来填
       
                mxOut[0] = c+(1-c)*v3a[0]*v3a[0];
                mxOut[1] = (1-c)*v3a[0]*v3a[1] + s*v3a[2];
                mxOut[2] = (1-c)*v3a[0]*v3a[2] -s*v3a[1];
                mxOut[3] = 0;
               
                mxOut[4] = (1-c)*v3a[1]*v3a[0] - s*v3a[2];
                mxOut[5] = c+(1-c)*v3a[1]*v3a[1];
                mxOut[6] = (1-c)*v3a[1]*v3a[2]+s*v3a[0];
                mxOut[7] = 0;
               
                mxOut[8] = (1-c)*v3a[2]*v3a[0] + s*v3a[1];
                mxOut[9] = (1-c)*v3a[2]*v3a[1] - s*v3a[0];
                mxOut[10] = c+(1-c)*v3a[2]*v3a[2];
                mxOut[11] = 0;
               
                mxOut[12] = 0;
                mxOut[13] = 0;
                mxOut[14] = 0;
                mxOut[15] = 1.0f;
               
               
        }//ef
        /**
         * 内部方法]] 考贝一份float[3]的 vector
         * 注意参数
         */
        public static float[] glV3Copy(float[] v3Source){
               
                if(v3Source.length!=3)
                {
                        throw new  RuntimeException("err in glVec3Copy");
                }
                float[] v3Out = new float[3];
                for(int i=0; i<3; i++){
                        v3Out = v3Source;
                }
                return v3Out;
        }//ef
        /**
         * float数组考贝,从src 到dst
         * @param arrDST 目标
         * @param arrSRC 源
         * @return 数组长度
         */
        public static int glFArrayCopy(float[] arrDST,float[] arrSRC){
                int iSize = arrDST.length;
                if(arrSRC.length != iSize)
                        throw new RuntimeException("err in glFArrayCopy");
                for(int i=0 ; i< iSize; i++){
                        arrDST = arrSRC;
                }
                return iSize;
        }//ef
        /**
         * 将一组FLOAT按序压入一个float buffer ,由于GL要求float buffer 建在系统内存中
         * 即allocateDirect()特作此函数
         * @param data 要压入buffer人数据
         * @return 由些函数建立的 floatbuffer
         */
        public static FloatBuffer PushIntoFLoatBuffer(float[] data){
                FloatBuffer fb = null;
                ByteBuffer bb = ByteBuffer.allocateDirect(data.length *4);
                bb.order(ByteOrder.nativeOrder());
                fb = bb.asFloatBuffer();
                fb.put(data);
                fb.position(0);
                return fb;
        }//ef
       
        public static FloatBuffer PushIntoFLoatBuffer(ArrayList<Float> arrData){
                //要先做成 数组,再压到BUFFER里去 所以会出现一个无句柄的中间量,
                int iSize = arrData.size();
                float[] data = new float[iSize];
                for(int i=0; i<iSize; i++){
                        data = arrData.get(i);
                }
               
                FloatBuffer fb = null;
                ByteBuffer bb = ByteBuffer.allocateDirect(data.length *4);
                bb.order(ByteOrder.nativeOrder());
                fb = bb.asFloatBuffer();
                fb.put(data);
                fb.position(0);
                return fb;
        }//ef
        /**
         * 将一组INT压入INT BUFFER,使用 allocateDirect() 及 nativeOrder将BUFFER建在系统内存
         * 因为,GLES只认识系统native的内存
         */
        public static IntBuffer PushIntoIntBuffer(int[] data){
                IntBuffer ib = null;
                ByteBuffer bb = ByteBuffer.allocateDirect(data.length * 4);//4 = Integer.SIZE/8  
                bb.order(ByteOrder.nativeOrder());
                ib = bb.asIntBuffer();
                ib.put(data);
                ib.position(0);
                return ib;               
        }//ef
        /**
         * 通过资源图片创建纹理 返回纹理id
         * @param pthis 暂定为activity的context
         * @param IdDrawable 图片的id (放在drawable内)
         * @return 纹理ID
         */
        public static int CreateTexture(Resources resource,int IdDrawable){
                int[] arrTexID = new int[1];
                GLES20.glGenTextures(1, arrTexID, 0);               
                int IdTexOut = arrTexID[0];
                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, IdTexOut);//将ID绑定到一个纹理(现为空)
                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);
                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE);
                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);
                //接下去通过流来加载图片  这里注意不一定要 stream 也可以直接 decodeResource 或文件
                InputStream is = resource.openRawResource(IdDrawable);
               
                Bitmap bitmapTemp = null;
                try{
                        bitmapTemp = BitmapFactory.decodeStream(is);
                }
                catch (Exception e) {
                        //
                        e.printStackTrace();
                }
                finally{
                        try {
                                is.close();
                        } catch (IOException e) {
                                Log.e("ERR", e.toString());
                        }
                }
                //再实际地加载图片
                GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmapTemp, 0);
                //提醒注意 别忘记干掉bitmapTemp 已经在显存了,再次加载只要id就行,所以bitmaptemp没用了
                bitmapTemp.recycle();
                //返回
                return IdTexOut;
               
        }//ef
        /**
         * 通过资源图片创建纹理 返回纹理id
         * @param resource 系统资源
         * @param strTexFileName 文件名(尺寸不用我提醒了吧,必须放在系统 assets档下)
         * @return 纹理ID
         */
        public static int CreateTexture(Resources resource, String strTexFileName)   {
                // 从资源assets中加载纹理
                int[] arrTexID = new int[1];
                GLES20.glGenTextures(1, arrTexID, 0);
               
                int IdTexOut = arrTexID[0];               
                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, IdTexOut);//将ID绑定到一个纹理(现为空)
                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);
                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE);
                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);
                //从ASSETS私有文件中读取
                Bitmap bitmapTemp = null;
                InputStream ins = null;
               
               
                try {
                        ins = resource.getAssets().open(strTexFileName);
                        bitmapTemp = BitmapFactory.decodeStream(ins);
                       
                } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }finally{
                        try {
                                ins.close();
                        } catch (IOException e) {
                                //
                                e.printStackTrace();
                        }
                }
               
               
                if(bitmapTemp == null)
                        return -1;
               
                GLUtils.texImage2D(GLES20.GL_TEXTURE_2D,0,bitmapTemp,0);//TNN的这种操作居然没有THROW的,GL个狗屁                       
                bitmapTemp.recycle();
               
                int iERR = GLES20.glGetError();
                if(iERR !=0)
                        Log.v("","");
               
                return IdTexOut;
        }//ef
       
}//EC

58

主题

1437

帖子

2207

积分

金牌会员

Rank: 6Rank: 6

积分
2207
发表于 2012-8-27 13:26:00 | 显示全部楼层

Re: Re: android openglES20 下多材质组obj文件导入的例子

压力不大的话就在国企呆着吧,虽然账面工资是低点。
dana9919: Re: android openglES20 下多材质组obj文件导入的例子

例程链接

http://upload.gameres.com/20128/sf_27122650_4628.zip

然后我要开始发牢骚了,OPENGL这东西...

33

主题

159

帖子

272

积分

中级会员

Rank: 3Rank: 3

积分
272
QQ
 楼主| 发表于 2012-8-27 14:11:00 | 显示全部楼层

Re: android openglES20 下多材质组obj文件导入的例子

学GLES的时间不长
一直都是以DIRECTX里学过的东西在套现,
做到摄像机的时候有一个关于View Matrix的问题感觉初学的一定要注意,特别是之前学过DIRECT的
direct的视矩阵3X3的部分上的三分量是  right up look
即matrixView的第一列是right的三分量,第二列是 up的三分量,第三列是 look向量的xyz三分量
但到了GL,变成了 right up invLook
invLook即视方向的反方向

0

主题

5

帖子

27

积分

注册会员

Rank: 2

积分
27
发表于 2012-8-29 17:16:00 | 显示全部楼层

Re:android openglES20 下多材质组obj文件导入的例子

感谢楼主的分享!

89

主题

4036

帖子

4132

积分

论坛元老

Rank: 8Rank: 8

积分
4132
发表于 2012-9-4 13:30:00 | 显示全部楼层

Re:android openglES20 下多材质组obj文件导入的例子

你要是在北京,咱可以聊聊。

0

主题

1

帖子

6

积分

新手上路

Rank: 1

积分
6
发表于 2013-2-20 17:07:15 | 显示全部楼层
终于找到了  比其他的乱七八糟的 loader 强百倍啊 尤其贴图
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-2-27 02:58

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表