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~7共8种光源。其它的光源默觉得黑色,即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能够设置从0到7共八个光源。pname: 光源參数名称,能够有例如以下:
GL_SPOT_EXPONENTGL_SPOT_CUTOFFGL_CONSTANT_ATTENUATIONGL_LINEAR_ATTENUATIONGL_QUADRATIC_ATTENUATIONGL_AMBIENT(用于设置环境光颜色)GL_DIFFUSE(用于设置漫反射光颜色)GL_SPECULAR(用于设置镜面反射光颜色)GL_SPOT_DIRECTIONGL_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_AMBIENTGL_DIFFUSEGL_SPECULARGL_EMISSIONGL_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的博客, viewmode=list">http://blog.csdn.net/huachao10019
Android OpenGL加入光照和材料属性的更多相关文章
- Android OpenGL 编写简单滤镜
Android 上使用Opengl进行滤镜渲染效率较高,比起单纯的使用CPU给用户带来的体验会好很多.滤镜的对象是图片,图片是以Bitmap的形式表示,Opengl不能直接处理Bitmap,在Andr ...
- Android OpenGL ES 开发教程 从入门到精通
感谢,摘自:http://blog.csdn.net/mapdigit/article/details/7526556 Android OpenGL ES 简明开发教程 Android OpenGL ...
- Android OpenGL ES(一)----必备知识
1.手机的坐标空间 我们都知道要想在手机上随心所欲的绘制图形,就必须了解手机的坐标体系.下图就是将坐标映射到手机屏幕的坐标. 图1手机屏幕基本坐标系 2.OpenGL基本图形 在OpenGL里,只能绘 ...
- EGL接口介绍-----Android OpenGL ES底层开发
引自:http://www.cnitblog.com/zouzheng/archive/2011/05/30/74326.html EGL 是 OpenGL ES 和底层 Native 平台视窗系统之 ...
- Android OpenGL ES .介绍
引自:http://blog.csdn.net/hgl868/article/details/6971624 1. OpenGL ES 简介 Android 3D引擎采用的是OpenGL ES. ...
- Android OpenGL ES(七)基本几何图形定义 .
在前面Android OpenGL ES(六):创建实例应用OpenGLDemos程序框架 我们创建了示例程序的基本框架,并提供了一个“Hello World”示例,将屏幕显示为红色. 本例介绍Ope ...
- 【Android】一道Android OpenGL笔试题
一道Android OpenGL笔试题 SkySeraph May. 5th 2016 Email:skyseraph00@163.com 更多精彩请直接访问SkySeraph个人站点:www.sky ...
- android opengl
引用:http://weimingtom.iteye.com/blog/1616972 二维坐标系变换为原点在左上角(测试用) * GLES * JOGL * LWJGL * libgdx(使用g2d ...
- Xamarin Android提示找不到资源属性定义
Xamarin Android提示找不到资源属性定义 错误信息:”Resource.Attribute”未包含”actonBarSize”的定义Xamarin Android经常会出现找不到资源属性的 ...
随机推荐
- 安装vmware+CentOS 7.4
安装步骤 选择第一个 按tab键 空格下一行 输入 红框内容 回车 注意事项 道路不通排查过程1.ip地址2.vmware 编辑-虚拟网络编辑器3.windows 服务 vmware相关服务 要开启 ...
- hdu 2389(二分图hk算法模板)
Rain on your Parade Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 655350/165535 K (Java/Ot ...
- hdu 1081(最大子矩阵)
To The Max Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...
- 如何设置WordPress文章特色图像(Featured Image)
WordPress的特色图像(Featured Image)是一个很方便的功能,过去为了给每篇文章设置一个缩略图,我们需要用脚本去匹配文章中的第一张或者最后一张图片,或者通过附件方式获取图片,有了特色 ...
- Android点击图标重新启动问题
原文:http://blog.csdn.net/jianiuqi/article/details/54091181 项目中的小问题:发现应用打包安装后按home键切换到后台后,点击应用图标又重新打开了 ...
- 解决Gradle报错找不到org.gradle.api.internal.project.ProjectInternal.getPluginManager()方法问题
因为本地的AndroidStudio很久没用了,所以想要研究下github上的某个代码的时候,还得重新配下环境 打开了几个项目,都是提示如下错误 Error:Unable to find method ...
- http中使用json封装数据的性能测试
http中使用json封装数据的性能测试 一个项目使用json封装数据,接口例如: 客户端发送: POST /list.do HTTP/1.1 Host: zoomi.com.cn ...
- mybatis 报错: Invalid bound statement (not found)
错误: org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): test.dao.Produc ...
- 计划任务at cron
计划任务作用:做一些周期性的任务,主要用于定时备份数据,同步时间,定时删除日志 所有计划任务执行的输出都会以邮件的方式发送给指定用户,除非重定向 (1)at:一次性调度执行 1)安装 yum inst ...
- 2018 ACM-ICPC 青岛网络赛
最近打比赛不知道为什么总是怀疑自己 写完之后不敢交,一定跟学长说一遍自己的思路 然后发现"哦原来我是对的" 然后就A掉了…… 所以还是要有自信 Problem A 最大值直接输出m ...