Android OpenGL添加光照和材料屬性

轉(zhuǎn)載請(qǐng)注明出處:【huachao1001的簡(jiǎn)書:http://www.reibang.com/users/0a7e42698e4b/latest_articles】

在上一篇文章【 Android OpenGL顯示任意3D模型文件 】中滥玷,我們學(xué)習(xí)了如何讀取并顯示STL格式的3D文件燃辖,但是,最后讯蒲,看到的并沒有添加光照效果截粗,導(dǎo)致雖然模型在旋轉(zhuǎn),但是我們看到的畫面卻像一個(gè)平面。今天我們開始學(xué)習(xí)如何給模型添加燈照效果,以及如何為模型添加材料屬性筹燕,使得最終看到的旋轉(zhuǎn)模型真正為3D效果。首先衅鹿,看看最終效果撒踪,如下圖所示:

光照效果
截圖
材質(zhì)效果

1 光照效果

因?yàn)槲覀兯龅牧Ⅲw效果是根據(jù)真實(shí)世界原理來計(jì)算的,所以很有必要去了解在現(xiàn)實(shí)世界中塘安,我們所看到的一個(gè)物體有哪些光糠涛。

1.1 真實(shí)世界中的光照

我們知道援奢,在黑暗中兼犯,當(dāng)我們將手電筒對(duì)準(zhǔn)某個(gè)物體時(shí),我們所看到的該物體的“亮度”有3種:

  • 物體表面發(fā)生鏡面反射部分(Specular)集漾,一般是白色切黔。
  • 物體表面發(fā)生漫反射部分(Diffuse),一般是物體表面的顏色具篇。
  • 物體表面沒有照射到光的部分纬霞,即通過環(huán)境光(Ambient)照射,在黑暗中環(huán)境光是黑色驱显。

如下圖所示(圖片出自www.guidebee.info):

光照?qǐng)D示

從上圖中也可以看出诗芜,光源的位置也會(huì)影響到我們所看到的最終畫面。顯然埃疫,我們只需控制好光源位置伏恐、鏡面反射顏色、漫反射顏色栓霜、環(huán)境光顏色這四個(gè)參數(shù)翠桦,就可以做到了。

1.2 Android OpenGL相關(guān)API

1.2.1 光源 GL10.GL_LIGHT0

0號(hào)光源胳蛮,該光源的默認(rèn)顏色為白色销凑,即RGBA(1.0,1.0,1.0,1.0)丛晌,漫反射和鏡面反射也為白色。類似的斗幼,還有其他光源如GL10.GL_LIGHT1澎蛛,系統(tǒng)提供了0~78種光源,其他的光源默認(rèn)為黑色孟岛,即RGBA(0.0,0.0,0.0,1.0).

開啟光源也非常簡(jiǎn)單:

//啟用光照功能
gl.glEnable(GL10.GL_LIGHTING);
//開啟0號(hào)燈
gl.glEnable(GL10.GL_LIGHT0);

1.2.2 設(shè)置各種反射光顏色

一旦開啟了光照功能瓶竭,就可以通過glLightfv函數(shù)來指定各種反射光的顏色了,glLightfv函數(shù)如下:

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: 指光源的序號(hào)斤贰,OpenGL ES可以設(shè)置從07共八個(gè)光源。
  • pname: 光源參數(shù)名稱次询,可以有如下:
  • GL_SPOT_EXPONENT
  • GL_SPOT_CUTOFF
  • GL_CONSTANT_ATTENUATION
  • GL_LINEAR_ATTENUATION
  • GL_QUADRATIC_ATTENUATION
  • GL_AMBIENT(用于設(shè)置環(huán)境光顏色)
  • GL_DIFFUSE(用于設(shè)置漫反射光顏色)
  • GL_SPECULAR(用于設(shè)置鏡面反射光顏色)
  • GL_SPOT_DIRECTION
  • GL_POSITION(用于設(shè)置光源位置)
  • params: 參數(shù)的值(數(shù)組或是Buffer類型)荧恍,數(shù)組里面含有4個(gè)值分別表示R,G,B,A。

指定光源的位置的參數(shù)為GL_POSITION,位置的值為(x,y,z,w)屯吊,如果是平行光則將w 設(shè)為0送巡,此時(shí),(x,y,z)為平行光的方向:

1.3 代碼實(shí)現(xiàn)

在上一篇的基礎(chǔ)上盒卸,直接修改GLRenderer.java文件骗爆,添加一個(gè)openLight函數(shù):


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));


}

另外,分別添加我們?cè)O(shè)定的各種反射光的顏色:

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函數(shù)里面調(diào)用一下openLight(gl);函數(shù)即可摘投。最終效果如下:

光照效果

2 材料屬性

前面我們提到了可以為模型設(shè)置不同的材料屬性,本節(jié)中虹蓄,我們一起學(xué)習(xí)如何為模型設(shè)定不同的材料屬性犀呼。我們知道,同樣是一束光薇组,照在不同顏色材料的物體上面外臂,我們所看到的是不同的,反射出來的不僅僅顏色不同律胀,光澤也是不同的宋光。換句話說,不同的材質(zhì)對(duì)最終的渲染效果影響很大炭菌!

材料的屬性設(shè)置和光源的設(shè)置有些類似罪佳,用到的函數(shù)

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娃兽,表示修改物體的前面和后面的材質(zhì)光線屬性菇民。
  • pname: 參數(shù)類型,這些參數(shù)用在光照方程〉诹罚可以取如下值:
  • GL_AMBIENT
  • GL_DIFFUSE
  • GL_SPECULAR
  • GL_EMISSION
  • GL_SHININESS阔馋。
  • param:指定反射的顏色。

跟設(shè)置光照類似娇掏,設(shè)置材料屬性首先需要定義各種反射光的顏色:

float[] materialAmb = {0.4f, 0.4f, 1.0f, 1.0f};
float[] materialDiff = {0.0f, 0.0f, 1.0f, 1.0f};//漫反射設(shè)置藍(lán)色
float[] materialSpec = {1.0f, 0.5f, 0.0f, 1.0f};

然后就是將這些顏色通過glMaterialfv函數(shù)設(shè)置進(jìn)去:

public void enableMaterial(GL10 gl) {

    //材料對(duì)環(huán)境光的反射情況
    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));

}

當(dāng)然了呕寝,最后也別忘記了在onSurfaceCreated函數(shù)中調(diào)用 enableMaterial(gl);,最后看看效果:

材質(zhì)效果

3 完整的GLRenderer類

最后項(xiàng)目代碼就不上傳了婴梧,直接參考上一篇的文章中的源碼即可下梢,本位值修改了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();// 重置當(dāng)前的模型觀察矩陣


        //眼睛對(duì)著原點(diǎn)看
        GLU.gluLookAt(gl, eye.x, eye.y, eye.z, center.x,
                center.y, center.z, up.x, up.y, up.z);

        //為了能有立體感覺塞蹭,通過改變mDegree值孽江,讓模型不斷旋轉(zhuǎn)
        gl.glRotatef(mDegree, 0, 1, 0);

        //將模型放縮到View剛好裝下
        gl.glScalef(mScalef, mScalef, mScalef);
        //把模型移動(dòng)到原點(diǎn)
        gl.glTranslatef(-mCenterPoint.x, -mCenterPoint.y,
                -mCenterPoint.z);


        //===================begin==============================//

        //允許給每個(gè)頂點(diǎn)設(shè)置法向量
        gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
        // 允許設(shè)置頂點(diǎn)
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        // 允許設(shè)置顏色

        //設(shè)置法向量數(shù)據(jù)源
        gl.glNormalPointer(GL10.GL_FLOAT, 0, model.getVnormBuffer());
        // 設(shè)置三角形頂點(diǎn)數(shù)據(jù)源
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, model.getVertBuffer());

        // 繪制三角形
        gl.glDrawArrays(GL10.GL_TRIANGLES, 0, model.getFacetCount() * 3);

        // 取消頂點(diǎn)設(shè)置
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        //取消法向量設(shè)置
        gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);

        //=====================end============================//

    }


    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {

        // 設(shè)置OpenGL場(chǎng)景的大小,(0,0)表示窗口內(nèi)部視口的左下角,(width, height)指定了視口的大小
        gl.glViewport(0, 0, width, height);

        gl.glMatrixMode(GL10.GL_PROJECTION); // 設(shè)置投影矩陣
        gl.glLoadIdentity(); // 設(shè)置矩陣為單位矩陣番电,相當(dāng)于重置矩陣
        GLU.gluPerspective(gl, 45.0f, ((float) width) / height, 1f, 100f);// 設(shè)置透視范圍

        //以下兩句聲明岗屏,以后所有的變換都是針對(duì)模型(即我們繪制的圖形)
        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);// 設(shè)置深度緩存值
        gl.glDepthFunc(GL10.GL_LEQUAL); // 設(shè)置深度緩存比較函數(shù)
        gl.glShadeModel(GL10.GL_SMOOTH);// 設(shè)置陰影模式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) {

        //材料對(duì)環(huán)境光的反射情況
        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));

    }
}

最后感謝大家的關(guān)注这刷,歡迎關(guān)注huachao1001的博客,http://blog.csdn.net/huachao10019

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末娩井,一起剝皮案震驚了整個(gè)濱河市暇屋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌洞辣,老刑警劉巖咐刨,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異屋彪,居然都是意外死亡所宰,警方通過查閱死者的電腦和手機(jī)绒尊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門畜挥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人婴谱,你說我怎么就攤上這事蟹但。” “怎么了谭羔?”我有些...
    開封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵华糖,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我瘟裸,道長(zhǎng)客叉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮兼搏,結(jié)果婚禮上卵慰,老公的妹妹穿的比我還像新娘。我一直安慰自己佛呻,他們只是感情好裳朋,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著吓著,像睡著了一般鲤嫡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上绑莺,一...
    開封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天暖眼,我揣著相機(jī)與錄音,去河邊找鬼纺裁。 笑死罢荡,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的对扶。 我是一名探鬼主播区赵,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼浪南!你這毒婦竟也來了笼才?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤络凿,失蹤者是張志新(化名)和其女友劉穎骡送,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體絮记,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡摔踱,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了怨愤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片派敷。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖撰洗,靈堂內(nèi)的尸體忽然破棺而出篮愉,到底是詐尸還是另有隱情,我是刑警寧澤差导,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布试躏,位于F島的核電站,受9級(jí)特大地震影響设褐,放射性物質(zhì)發(fā)生泄漏颠蕴。R本人自食惡果不足惜泣刹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望犀被。 院中可真熱鬧项玛,春花似錦、人聲如沸弱判。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽昌腰。三九已至开伏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間遭商,已是汗流浹背固灵。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留劫流,地道東北人巫玻。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像祠汇,于是被迫代替她去往敵國(guó)和親仍秤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 并沒有添加光照效果可很,導(dǎo)致雖然模型在旋轉(zhuǎn)诗力,但是我們看到的畫面卻像一個(gè)平面。今天我們開始學(xué)習(xí)如何給模型添加燈照效果我抠,以...
    CHSmile閱讀 755評(píng)論 0 0
  • 光照模型 在OpenGL光照模型中苇本,除非一個(gè)物體自己會(huì)發(fā)光,否則它將受到3種不同類型的光的照射:環(huán)境光(ambie...
    Beatrice7閱讀 14,300評(píng)論 1 8
  • 版本記錄 前言 OpenGL 圖形庫項(xiàng)目中一直也沒用過菜拓,最近也想學(xué)著使用這個(gè)圖形庫瓣窄,感覺還是很有意思,也就自然想著...
    刀客傳奇閱讀 6,072評(píng)論 0 2
  • OpenGL ES _ 入門_01OpenGL ES _ 入門_02OpenGL ES _ 入門_03OpenGL...
    酷走天涯閱讀 2,283評(píng)論 4 4
  • 王陽明先生的這幾封信全是在解答對(duì)“知行合一”的疑惑纳鼎,有的擔(dān)心人們會(huì)因?yàn)橥蹶柮飨壬难哉摱晃兜淖非髢?nèi)心的存養(yǎng)而拋棄...
    Aprilday_15ac閱讀 606評(píng)論 0 2