• Android OpenGL加入光照和材料属性


    转载请注明出处:【huachao1001的专栏:http://blog.csdn.net/huachao1001】

    在上一篇文章【 Android OpenGL显示随意3D模型文件 】中。我们学习了怎样读取并显示STL格式的3D文件,可是,最后。看到的并没有加入光照效果。导致尽管模型在旋转,可是我们看到的画面却像一个平面。今天我们開始学习怎样给模型加入灯照效果,以及怎样为模型加入材料属性,使得终于看到的旋转模型真正为3D效果。首先。看看终于效果,例如以下图所示:

    光照效果

    材质效果

    1 光照效果

    由于我们所做的立体效果是依据真实世界原理来计算的,所以非常有必要去了解在现实世界中。我们所示一个物体有哪些光。

    1.1 真实世界中的光照

    我们知道,在黑暗中,当我们将手电筒对准某个物体时。我们所示该物体的“亮度”有3种:

    • 物体表面发生镜面反射部分(Specular),通常是白色。

    • 物体表面发生漫反射部分(Diffuse),通常是物体表面的颜色。

    • 物体表面没有照耀到光的部分。即通过环境光(Ambient)照耀,在黑暗中环境光是黑色。

    例如以下图所示(图片出自www.guidebee.info):

    光照图示

    从上图中也能够看出,光源的位置也会影响到我们所示终于画面。

    显然,我们仅仅需控制好光源位置、镜面反射颜色、漫反射颜色、环境光颜色这四个參数,就能够做到了。

    1.2 Android OpenGL相关API

    1.2.1 光源 GL10.GL_LIGHT0

    0号光源,该光源的默认颜色为白色,即RGBA(1.0,1.0,1.0,1.0)。漫反射和镜面反射也为白色。相似的,还有其它光源如GL10.GL_LIGHT1,系统提供了0~78种光源。其它的光源默觉得黑色,即RGBA(0.0,0.0,0.0,1.0).

    开启光源也非常easy:

    //启用光照功能
    gl.glEnable(GL10.GL_LIGHTING);
    //开启0号灯
    gl.glEnable(GL10.GL_LIGHT0);

    1.2.2 设置各种反射光颜色

    一旦开启了光照功能,就能够通过glLightfv函数来指定各种反射光的颜色了,glLightfv函数例如以下:

    public void glLightfv(int light,int pname, FloatBuffer params)
    public void glLightfv(int light,int pname,float[] params,int offset)
    public void glLightf(int light,int pname,float param)

    当中,

    • light: 指光源的序号,OpenGL ES能够设置从07共八个光源。
    • pname: 光源參数名称,能够有例如以下:
      • GL_SPOT_EXPONENT
      • GL_SPOT_CUTOFF
      • GL_CONSTANT_ATTENUATION
      • GL_LINEAR_ATTENUATION
      • GL_QUADRATIC_ATTENUATION
      • GL_AMBIENT(用于设置环境光颜色)
      • GL_DIFFUSE(用于设置漫反射光颜色)
      • GL_SPECULAR(用于设置镜面反射光颜色)
      • GL_SPOT_DIRECTION
      • GL_POSITION(用于设置光源位置)
    • params: 參数的值(数组或是Buffer类型),数组里面含有4个值分别表示R,G,B,A。

    指定光源的位置的參数为GL_POSITION,位置的值为(x,y,z,w),假设是平行光则将w 设为0,此时。(x,y,z)为平行光的方向:

    1.3 代码实现

    在上一篇的基础上,直接改动GLRenderer.java文件。加入一个openLight函数:

    
    public void openLight(GL10 gl) {
    
        gl.glEnable(GL10.GL_LIGHTING);
        gl.glEnable(GL10.GL_LIGHT0);
        gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, Util.floatToBuffer(ambient));
        gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, Util.floatToBuffer(diffuse));
        gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPECULAR, Util.floatToBuffer(specular));
        gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, Util.floatToBuffer(lightPosition));
    
    
    }

    另外,分别加入我们设定的各种反射光的颜色:

    float[] ambient = {0.9f, 0.9f, 0.9f, 1.0f,};
    float[] diffuse = {0.5f, 0.5f, 0.5f, 1.0f,};
    float[] specular = {1.0f, 1.0f, 1.0f, 1.0f,};
    float[] lightPosition = {0.5f, 0.5f, 0.5f, 0.0f,};
    

    最后,在onSurfaceCreated函数里面调用一下openLight(gl);函数就可以。终于效果例如以下:

    光照效果

    2 材料属性

    前面我们提到了能够为模型设置不同的材料属性,本节中。我们一起学习怎样为模型设定不同的材料属性。

    我们知道,相同是一束光,照在不同颜色材料的物体上面。我们所示是不同的,反射出来的不仅仅颜色不同,光泽也是不同的。

    换句话说。不同的材质对终于的渲染效果影响非常大!

    材料的属性设置和光源的设置有些相似,用到的函数

    public void glMaterialf(int face,int pname,float param)
    public void glMaterialfv(int face,int pname,float[] params,int offset)
    public void glMaterialfv(int face,int pname,FloatBuffer params)

    当中,

    • face : 在OpenGL ES中仅仅能使用GL_FRONT_AND_BACK,表示改动物体的前面和后面的材质光线属性。
    • pname: 參数类型,这些參数用在光照方程。能够取例如以下值:
      • GL_AMBIENT
      • GL_DIFFUSE
      • GL_SPECULAR
      • GL_EMISSION
      • GL_SHININESS
    • param:指定反射的颜色。

    跟设置光照相似,设置材料属性首先须要定义各种反射光的颜色:

    float[] materialAmb = {0.4f, 0.4f, 1.0f, 1.0f};
    float[] materialDiff = {0.0f, 0.0f, 1.0f, 1.0f};//漫反射设置蓝色
    float[] materialSpec = {1.0f, 0.5f, 0.0f, 1.0f};

    然后就是将这些颜色通过glMaterialfv函数设置进去:

    public void enableMaterial(GL10 gl) {
    
        //材料对环境光的反射情况
        gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, Util.floatToBuffer(materialAmb));
        //散射光的反射情况
        gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, Util.floatToBuffer(materialDiff));
        //镜面光的反射情况
        gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, Util.floatToBuffer(materialSpec));
    
    }

    当然了,最后也别忘记了在onSurfaceCreated函数中调用 enableMaterial(gl);,最后看看效果:
    材质效果

    3 完整的GLRenderer类

    最后项目代码就不上传了,直接參考上一篇的文章中的源代码就可以,本位值改动了GLRenderer类,把该类的完整源代码贴上:

    package com.hc.opengl;
    
    import android.content.Context;
    import android.opengl.GLSurfaceView;
    import android.opengl.GLU;
    
    import java.io.IOException;
    
    import javax.microedition.khronos.egl.EGLConfig;
    import javax.microedition.khronos.opengles.GL10;
    
    /**
     * Package com.hc.opengl
     * Created by HuaChao on 2016/8/9.
     */
    public class GLRenderer implements GLSurfaceView.Renderer {
    
        private Model model;
        private Point mCenterPoint;
        private Point eye = new Point(0, 0, -3);
        private Point up = new Point(0, 1, 0);
        private Point center = new Point(0, 0, 0);
        private float mScalef = 1;
        private float mDegree = 0;
    
        public GLRenderer(Context context) {
            try {
    
                model = new STLReader().parserBinStlInAssets(context, "huba.stl");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public void rotate(float degree) {
            mDegree = degree;
        }
    
        @Override
        public void onDrawFrame(GL10 gl) {
            // 清除屏幕和深度缓存
            gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    
    
            gl.glLoadIdentity();// 重置当前的模型观察矩阵
    
    
            //眼睛对着原点看
            GLU.gluLookAt(gl, eye.x, eye.y, eye.z, center.x,
                    center.y, center.z, up.x, up.y, up.z);
    
            //为了能有立体感觉。通过改变mDegree值,让模型不断旋转
            gl.glRotatef(mDegree, 0, 1, 0);
    
            //将模型放缩到View刚好装下
            gl.glScalef(mScalef, mScalef, mScalef);
            //把模型移动到原点
            gl.glTranslatef(-mCenterPoint.x, -mCenterPoint.y,
                    -mCenterPoint.z);
    
    
            //===================begin==============================//
    
            //同意给每一个顶点设置法向量
            gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
            // 同意设置顶点
            gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
            // 同意设置颜色
    
            //设置法向量数据源
            gl.glNormalPointer(GL10.GL_FLOAT, 0, model.getVnormBuffer());
            // 设置三角形顶点数据源
            gl.glVertexPointer(3, GL10.GL_FLOAT, 0, model.getVertBuffer());
    
            // 绘制三角形
            gl.glDrawArrays(GL10.GL_TRIANGLES, 0, model.getFacetCount() * 3);
    
            // 取消顶点设置
            gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
            //取消法向量设置
            gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
    
            //=====================end============================//
    
        }
    
    
        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
    
            // 设置OpenGL场景的大小,(0,0)表示窗体内部视口的左下角,(width, height)指定了视口的大小
            gl.glViewport(0, 0, width, height);
    
            gl.glMatrixMode(GL10.GL_PROJECTION); // 设置投影矩阵
            gl.glLoadIdentity(); // 设置矩阵为单位矩阵。相当于重置矩阵
            GLU.gluPerspective(gl, 45.0f, ((float) width) / height, 1f, 100f);// 设置透视范围
    
            //下面两句声明,以后全部的变换都是针对模型(即我们绘制的图形)
            gl.glMatrixMode(GL10.GL_MODELVIEW);
            gl.glLoadIdentity();
    
    
        }
    
    
        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            gl.glEnable(GL10.GL_DEPTH_TEST); // 启用深度缓存
            gl.glClearColor(0f, 0f, 0f, 0f);// 设置深度缓存值
            gl.glDepthFunc(GL10.GL_LEQUAL); // 设置深度缓存比較函数
            gl.glShadeModel(GL10.GL_SMOOTH);// 设置阴影模式GL_SMOOTH
    
            //开启光
            openLight(gl);
            enableMaterial(gl);
            float r = model.getR();
            //r是半径。不是直径,因此用0.5/r能够算出放缩比例
            mScalef = 0.5f / r;
            mCenterPoint = model.getCentrePoint();
        }
    
    
        float[] ambient = {0.9f, 0.9f, 0.9f, 1.0f};
        float[] diffuse = {0.5f, 0.5f, 0.5f, 1.0f};
        float[] specular = {1.0f, 1.0f, 1.0f, 1.0f};
        float[] lightPosition = {0.5f, 0.5f, 0.5f, 0.0f};
    
        public void openLight(GL10 gl) {
    
            gl.glEnable(GL10.GL_LIGHTING);
            gl.glEnable(GL10.GL_LIGHT0);
            gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, Util.floatToBuffer(ambient));
            gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, Util.floatToBuffer(diffuse));
            gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPECULAR, Util.floatToBuffer(specular));
            gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, Util.floatToBuffer(lightPosition));
    
    
        }
    
        float[] materialAmb = {0.4f, 0.4f, 1.0f, 1.0f,};
        float[] materialDiff = {0.0f, 0.0f, 1.0f, 1.0f,};
        float[] materialSpec = {1.0f, 0.5f, 0.0f, 1.0f,};
    
        public void enableMaterial(GL10 gl) {
    
            //材料对环境光的反射情况
            gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, Util.floatToBuffer(materialAmb));
            //散射光的反射情况
            gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, Util.floatToBuffer(materialDiff));
            //镜面光的反射情况
            gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, Util.floatToBuffer(materialSpec));
    
        }
    }

    最后感谢大家的关注,欢迎关注huachao1001的博客,http://blog.csdn.net/huachao10019

  • 相关阅读:
    【读书笔记】组合计数中的行列式方法 基础
    【读书笔记】有序分拆和无序分拆的结论速览
    三种常见的卷积概述(线性卷积周期卷积圆周卷积)以及重叠保留法重叠相加法
    大会COOKIE与session
    JVM监测&工具[整理中](五)
    谷歌浏览器启动参数
    Maven的配置文件pom.xml
    classLoader卸载与jvm热部署
    在Windows Server 2008R2中安装配置SMTP服务
    Could not start the MS DTC Transaction Manager
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/8744661.html
Copyright © 2020-2023  润新知