美文网首页
(五)加载obj和mtl

(五)加载obj和mtl

作者: SunnyDay_ab5f | 来源:发表于2019-11-25 15:46 被阅读0次

    1.shader

    public static String vs =
                "uniform mat4 uMatrix;\n" +
                "uniform vec3 uCamera;\n" +
                "uniform vec3 uLight;\n" +
                "uniform vec3 vKa;\n" +
                "uniform vec3 vKd;\n" +
                "uniform vec3 vKs;\n" +
                "attribute vec4 vPosition;\n" +
                "attribute vec4 vNormal;\n" +
                "varying vec4 vSpecular;\n" +
                "varying vec4 vDiffuse;\n" +
                "varying vec4 vAmbient;\n" +
                "void main(){\n" +
                "float shininess=3.0;\n" +
                "gl_Position=uMatrix*vPosition;\n" +
                "vec4 initAmbient=vec4(vKa,1.0);\n" +
                "vec4 initDiffuse=vec4(vKd,1.0);\n" +
                "vec4 initSpecular=vec4(vKs,1.0);\n" +
                "vAmbient=initAmbient;\n" +
                "vec4 _vNormal=normalize(vNormal);\n" +
                "vec3 eye=uCamera-vPosition.xyz;\n" +
                "eye=normalize(eye);\n" +
                "vec3 vp=uLight-vPosition.xyz;\n" +
                "vp=normalize(vp);\n" +
                "float nDotViewPosition=max(0.0,dot(_vNormal.xyz,vp));\n" +
                "vDiffuse=initDiffuse*nDotViewPosition;\n" +
                "vec3 halfVector=normalize(vp+eye);\n" +
                "float nDotViewHalfVector=dot(_vNormal.xyz,halfVector);\n" +
                "float powerFactor=max(0.0,pow(nDotViewHalfVector,shininess));\n" +
                "vSpecular=initSpecular*powerFactor;\n" +
                "}";
    
    
        public static String fs =
                "precision mediump float;\n" +
                "varying vec4 vSpecular;\n" +
                "varying vec4 vDiffuse;\n" +
                "varying vec4 vAmbient; \n" +
                "void main(){\n" +
                "vec4 finalColor=vec4(1.0,1.0,1.0,1.0);\n" +   //这里如果写1.0f 在opengles 2.0 可以编译的过去,在3.0shader会报错
                "gl_FragColor=finalColor*vSpecular+finalColor*vDiffuse+finalColor*vAmbient;\n" +
                "}";
    

    这部分代码我是在网上找的。

    2.Renderer

    import android.opengl.GLES20;
    import android.opengl.GLSurfaceView;
    import android.opengl.Matrix;
    import android.util.Log;
    
    import java.util.List;
    
    import javax.microedition.khronos.egl.EGLConfig;
    import javax.microedition.khronos.opengles.GL10;
    
    public class MyGLRenderer implements GLSurfaceView.Renderer {
    
        private Triangle mTriangle;
        private String filePath;
    
        private final float[] vPMatrix = new float[16];
        private final float[] projectionMatrix = new float[16];
        private final float[] viewMatrix = new float[16];
        private float[] rotationMatrix = new float[16];
    
    
    
        public volatile float mAngle;
        private ObjFileReader reader;
        private List<Triangle> triangles;
    
        public float getAngle() {
            return mAngle;
        }
    
        public void setAngle(float angle) {
            mAngle = angle;
        }
    
        public void setPath(String filePath) {
            this.filePath = filePath;
        }
    
       //代码没有对加载是否成功做判断 在项目中要做好判断和log打印。
        public static int loadShader(int type, String shaderCode){
    
            // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
            // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
            int shader = GLES20.glCreateShader(type);
    
            // add the source code to the shader and compile it
            GLES20.glShaderSource(shader, shaderCode);
            GLES20.glCompileShader(shader);
            return shader;
        }
    
        private static final String TAG = "MyGLRenderer";
        public void onSurfaceCreated(GL10 unused, EGLConfig config) {
            // Set the background frame color
            GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
            // initialize a triangle
            String objPath = filePath + "patrick.obj";
            String mtlPath = filePath + "patrick.mtl";
            reader = new ObjFileReader();
            reader.readMtlFile(mtlPath);
            triangles = reader.readObjFile(objPath);
            for (int i = 0; i < triangles.size(); i++) {
                triangles.get(i).init2();
            }
        }
    
        public void onDrawFrame(GL10 unused) {
            // Redraw background color
            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
            // Set the camera position (View matrix)
    //        Matrix.setLookAtM(viewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
            Matrix.setLookAtM(viewMatrix, 0, 0, 0, 4, 0f, 0f, 0f, 0f, 1.0f, 0.0f);//upY 方向是正方向 upz则看不到
    
    
            // Calculate the projection and view transformation
            Matrix.multiplyMM(vPMatrix, 0, projectionMatrix, 0, viewMatrix, 0);
    
            float[] scratch = new float[16];
    
            // Create a rotation for the triangle
            // long time = SystemClock.uptimeMillis() % 4000L;
            // float angle = 0.090f * ((int) time);
            Matrix.setRotateM(rotationMatrix, 0, mAngle, 0, 1.0f, 0);
    
            // Combine the rotation matrix with the projection and camera view
            // Note that the vPMatrix factor *must be first* in order
            // for the matrix multiplication product to be correct.
            Matrix.multiplyMM(scratch, 0, vPMatrix, 0, rotationMatrix, 0);
    
    //        // Draw triangle
            for (int i = 0; i < triangles.size(); i++) {
                triangles.get(i).draw2(scratch);
            }
        }
    
        public void onSurfaceChanged(GL10 unused, int width, int height) {
            GLES20.glViewport(0, 0, width, height);
            float ratio = (float) width / height;
    
            // this projection matrix is applied to object coordinates
            // in the onDrawFrame() method
    //        Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
            Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1, 1, 1, 100);//100 这个值要尽可能的大一些,不然模型可能会无法全部显示
        }
    }
    
    

    3.Triangle

    import android.opengl.GLES20;
    import android.util.Log;
    
    import java.nio.ByteBuffer;
    import java.nio.ByteOrder;
    import java.nio.FloatBuffer;
    import java.util.ArrayList;
    import java.util.List;
    
    public class Triangle {
        private int mProgram;
        private FloatBuffer vertexBuffer;
        // Use to access and set the view transformation
        private int vPMatrixHandle;
    
        // number of coordinates per vertex in this array
        static final int COORDS_PER_VERTEX = 3;
        private int positionHandle;
        private int colorHandle;
        private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
        public MtlInfo mtlInfo;//材质纹理信息
        public List<Float> vertexList = new ArrayList<>();
        public List<Float> normalList = new ArrayList<>();
        private int vertexCount;
        private int normalCount;
        private FloatBuffer normalBuffer;
        private int kaHandle;
        private int kdHandle;
        private int ksHandle;
        private int normalHandle;
        private int mCameraHandle;
        private int mLightHandle;
        private float [] fvArray;
        private float[] fvnArray;
        private float[] lightBuffer = new float[]{0f,0f,1000f};//光源
        private float[] cameraBuffer = new float[]{0f,0f,4f};//相机
        private static final String TAG = "Triangle";
        public void init() {
            //加载顶点数据
            fvArray = new float[vertexList.size()];
            for (int i = 0; i < vertexList.size(); i++) {
                fvArray[i] = vertexList.get(i);
            }
            vertexCount = fvArray.length / 3;
            ByteBuffer bb = ByteBuffer.allocateDirect(fvArray.length * 4);//一个三角形3个点,一个点由3个浮点数表示 一个浮点数有4个字节 3*3*4
            //使用设备硬件的本机字节顺序
            bb.order(ByteOrder.nativeOrder());
            //从ByteBuffer创建一个浮点缓冲区
            vertexBuffer = bb.asFloatBuffer();
            //将坐标添加到FloatBuffer
            vertexBuffer.put(fvArray);
            //清除数据缓存
            vertexList.clear();
            fvArray=null;
            //设置缓冲区以读取第一个坐标
            vertexBuffer.position(0);
    
            //加载法线向量数据
            fvnArray = new float[normalList.size()];
            normalCount = fvnArray.length / 3;
            ByteBuffer nbb = ByteBuffer.allocateDirect(fvnArray.length * 4);//一个三角形3个点,一个点由3个浮点数表示 一个浮点数有4个字节 3*3*4
            //使用设备硬件的本机字节顺序
            nbb.order(ByteOrder.nativeOrder());
            //从ByteBuffer创建一个浮点缓冲区
            normalBuffer = nbb.asFloatBuffer();
            //将坐标添加到FloatBuffer
            normalBuffer.put(fvnArray);
            //设置缓冲区以读取第一个坐标
            normalBuffer.position(0);
    
            int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
                    MyShader.vs);
            int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
                    MyShader.fs);
    
            //创建空的OpenGL ES程序
            mProgram = GLES20.glCreateProgram();
            // 将顶点着色器添加到程序中
            GLES20.glAttachShader(mProgram, vertexShader);
    
            // 将片段着色器添加到程序中
            GLES20.glAttachShader(mProgram, fragmentShader);
            // 创建OpenGL ES程序可执行文件
            GLES20.glLinkProgram(mProgram);
        }
    
        public void draw2(float[] mvpMatrix) {
            // 将程序添加到OpenGL ES环境
            GLES20.glUseProgram(mProgram);
            vPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMatrix");
           // 将投影和视图转换传递到着色器
            GLES20.glUniformMatrix4fv(vPMatrixHandle, 1, false, mvpMatrix, 0);
    
            //相机位置句柄
            mCameraHandle =GLES20.glGetUniformLocation(mProgram,"uCamera");
            //灯光位置句柄
            mLightHandle =GLES20.glGetUniformLocation(mProgram,"uLight");
            kaHandle = GLES20.glGetUniformLocation(mProgram, "vKa");
            kdHandle = GLES20.glGetUniformLocation(mProgram, "vKd");
            ksHandle = GLES20.glGetUniformLocation(mProgram, "vKs");
    
            GLES20.glUniform3fv(mCameraHandle,1,cameraBuffer,0);
            GLES20.glUniform3fv(mLightHandle,1,lightBuffer,0);
            GLES20.glUniform3fv(kaHandle,1,mtlInfo.Ka,0);
            GLES20.glUniform3fv(kdHandle,1,mtlInfo.Kd,0);
            GLES20.glUniform3fv(ksHandle,1,mtlInfo.Ks,0);
    
    //        mHCoord =GLES20.glGetAttribLocation(mProgram,"vCoord");
    //        mHTexture =GLES20.glGetUniformLocation(mProgram,"vTexture");
    
           //获取顶点着色器的vPosition成员的句柄
            positionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
            //三角形顶点法线句柄
            normalHandle = GLES20.glGetAttribLocation(mProgram, "vNormal");
    
    
    //        GLES20.glEnableVertexAttribArray(mHCoord);
    //        GLES20.glVertexAttribPointer(mHCoord, 2, GLES20.GL_FLOAT, false, 0, vertTexture);
            // 启用三角形顶点的句柄
            GLES20.glEnableVertexAttribArray(positionHandle);
            // 启用三角形顶点法线的句柄
            GLES20.glEnableVertexAttribArray(normalHandle);
    
            // 准备三角坐标数据
            GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX,
                    GLES20.GL_FLOAT, false,
                    vertexStride, vertexBuffer);
    
            GLES20.glVertexAttribPointer(normalHandle, COORDS_PER_VERTEX,
                    GLES20.GL_FLOAT, false,
                    vertexStride, normalBuffer);
         
            //画三角形
            GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
    
            //禁用顶点数组
            GLES20.glDisableVertexAttribArray(positionHandle);
            GLES20.glDisableVertexAttribArray(normalHandle);
            GLES20.glUseProgram(0);
        }
    
    }
    
    

    因为项目中没有贴图,所以没有加载贴图,代码是demo版的,只供参考。

    3.MyGLSurfaceView

    import android.content.Context;
    import android.opengl.GLSurfaceView;
    import android.view.MotionEvent;
    
    public class MyGLSurfaceView extends GLSurfaceView {
        private final MyGLRenderer renderer;
    
        public MyGLSurfaceView(Context context){
            super(context);
    
            // Create an OpenGL ES 2.0 context
            setEGLContextClientVersion(2);
    
            renderer = new MyGLRenderer();
            String filePath = context.getExternalCacheDir() + "/";
            renderer.setPath(filePath);
            // Set the Renderer for drawing on the GLSurfaceView
            //注意在设置Renderer之前要在glthread线城中解析完数据加载到内存中
            setRenderer(renderer);
            //不会实时绘制模型,调用requestRender()才会绘制
            setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
        }
    
    
        private final float TOUCH_SCALE_FACTOR = 180.0f / 320;
        private float previousX;
        private float previousY;
    
        @Override
        public boolean onTouchEvent(MotionEvent e) {
            // MotionEvent reports input details from the touch screen
            // and other input controls. In this case, you are only
            // interested in events where the touch position changed.
    
            float x = e.getX();
            float y = e.getY();
    
            switch (e.getAction()) {
                case MotionEvent.ACTION_MOVE:
    
                    float dx = x - previousX;
                    float dy = y - previousY;
    
                    // reverse direction of rotation above the mid-line
                    if (y > getHeight() / 2) {
                        dx = dx * -1 ;
                    }
    
                    // reverse direction of rotation to left of the mid-line
                    if (x < getWidth() / 2) {
                        dy = dy * -1 ;
                    }
    
                    renderer.setAngle(
                            renderer.getAngle() +
                                    ((dx + dy) * TOUCH_SCALE_FACTOR));
                    requestRender();
            }
    
            previousX = x;
            previousY = y;
            return true;
        }
    }
    
    

    //效果如下图:


    image.png

    没有贴图看不清楚 。。!

    这个模型还是比较小的,顶点数不多,如果是大模型,一百万个顶点甚至更多的时候,加载会非常耗时,不适合在项目中使用,提个建议,模型解析用c去做,会提升很多效率,亲测同一个模型,用java解析需要2—3f分钟,c的话只要几秒钟。顶点数据,法线数据,推荐用vbo去做。

    相关文章

      网友评论

          本文标题:(五)加载obj和mtl

          本文链接:https://www.haomeiwen.com/subject/oztgyctx.html