光的的成分包括三种:
①环境光:(ambient)没有方向,向四周均匀发散,全局因素。
②散射光:(diffuse)具有方向性,根据入射光角度均匀反射开来,物体表面的颜色主要取决于散射光。③镜面光:(specular)具有很强的方向性。
opneGL中的光照同样是状态机,所以要使用光照,就要:
gl.glEnable(GL10.GL_LIGHTING);
在启用了光照之后,就要对三种光进行设置,如果没有对任何一种光进行设置的话,我们所绘制的物体将会很难看得清楚,这里我们先来看全局环境光。
设置光:gl.glLightModelfv();
两个参数,第一个为光的类型,第二个为指定光数据的缓冲区。光与颜色类似,都是由r,g,b,a四个值组成,所以,我们要指定光数据的缓冲区,就要先定义一个数组来指定各个分量的值。
float [] global_ambient = {1,1,1,1};然后将这个数组转换成浮点缓冲区,就是第二个参数了。
为方便观察,我们设置一个透明的Dialog附在已经写好的Renderer上面,通过复选按钮控制是否开启光照,通过Seekbar控制r,g,b各分量值,如下图所示:
首先在Layout中画好xml,然后在Mainactivity中创建一个Dialog:
private void buildDialog() { d = new Dialog(this,android.R.style.Theme_Translucent_NoTitleBar_Fullscreen); d.setContentView(R.layout.light_setting); d.show(); }注:主题要为透明,不然看不见后面的效果。
然后就需要为复选框和三个seekbar加监听器了,发现如果一个一个加监听器很麻烦,所以就要用到反射:
try { Class clazz = R.id.class; Field [] fs = clazz.getDeclaredFields(); CheckBox box = null; SeekBar bar = null; for( Field f : fs ){ int id = (Integer)f.get(null); View view = d.findViewById(id); if( view != null ){ if( view instanceof CheckBox ){ box = (CheckBox) view; box.setOnCheckedChangeListener(box1); }else if( view instanceof SeekBar ){ bar = (SeekBar) view; bar.setOnSeekBarChangeListener(bar1); } } } } catch (Exception e) { e.printStackTrace(); }然后在监听器中对Checkbox和SeekBar进行处理就OK。
运行效果图:
附代码:
public class MyLightingRenderer extends AbstractRenderer{ @Override public void onDrawFrame(GL10 gl) { gl.glClear(GL10.GL_COLOR_BUFFER_BIT);//设置清屏色 gl.glColor4f(1f, 1f, 1f, 1f);//设置绘图颜色 gl.glMatrixMode(GL10.GL_MODELVIEW);//模型视图矩阵 gl.glLoadIdentity();//加载单位矩阵 GLU.gluLookAt(gl, 0, 0, 5, 0, 0, 0, 0, 1, 0);//放置眼球位置 gl.glRotatef(xRotate, 1, 0, 0);//x轴旋转角度 gl.glRotatef(yRotate, 0, 1, 0);//y轴旋转角度 gl.glClear(GL10.GL_DEPTH_BUFFER_BIT); gl.glEnable(GL10.GL_DEPTH_TEST); gl.glColor4f(1f,1f,1f,1f); /*********************光照**************************/ if(open_lighting){ //启用光照 gl.glEnable(GL10.GL_LIGHTING); }else{ //禁止光照 gl.glDisable(GL10.GL_LIGHTING); } float [] global_ambient = {r,g,b,a,}; //设置全局环境光 gl.glLightModelfv(GL10.GL_LIGHT_MODEL_AMBIENT,BufferUtils.arr2FloatBuffer(global_ambient)); //画一个球 BufferUtils.drawSphere(gl,0.4f,8,8); } }
public class MainActivity extends Activity { private AbstractRenderer renderer; MyGLSurfaceView view; private Dialog d; private Resources r; protected void onCreate(Bundle savedInstanceState) { r = this.getResources(); super.onCreate(savedInstanceState); view = new MyGLSurfaceView(this); //render渲染器 renderer = new MyLightingRenderer(); // view.setEGLConfigChooser(5,6,5,0,8,8); view.setRenderer(renderer); // view.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);//默认渲染模式,持续渲染。 // view.setRenderMode( GLSurfaceView.RENDERMODE_WHEN_DIRTY );//脏渲染(命令渲染)脏渲染模式下ondrawframe()方法只调用一次。 setContentView(view); buildDialog(); addCheckBoxEvent(); } //添加复选框事件 private void addCheckBoxEvent() { //匿名内部类:box监听 CompoundButton.OnCheckedChangeListener box1 = new CompoundButton.OnCheckedChangeListener() { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { /* //通过反射实现 try { int id = buttonView.getId(); String name = r.getResourceName( id ); Log.i("xiaoyu",name); name.substring(name.lastIndexOf("_") + 1); Class clazz = renderer.getClass(); Field f = clazz.getField(name); f.setAccessible(true); f.set(renderer,isChecked); } catch (Exception e) { e.printStackTrace(); }*/ renderer.open_lighting = isChecked; } }; //seekbar监听 final SeekBar.OnSeekBarChangeListener bar1 = new SeekBar.OnSeekBarChangeListener(){ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { float scale = (float)progress/(float)seekBar.getMax(); switch (seekBar.getId()){ case R.id.sb_r: renderer.r = scale; case R.id.sb_g: renderer.g = scale; case R.id.sb_b: renderer.b = scale; } } public void onStartTrackingTouch(SeekBar seekBar) { } public void onStopTrackingTouch(SeekBar seekBar) { } }; /**************************利用反射给CheckBox和三个SeekBar加监听器*********************************/ try { Class clazz = R.id.class; Field [] fs = clazz.getDeclaredFields(); CheckBox box = null; SeekBar bar = null; for( Field f : fs ){ int id = (Integer)f.get(null); View view = d.findViewById(id); if( view != null ){ if( view instanceof CheckBox ){ box = (CheckBox) view; box.setOnCheckedChangeListener(box1); }else if( view instanceof SeekBar ){ bar = (SeekBar) view; bar.setOnSeekBarChangeListener(bar1); } } } } catch (Exception e) { e.printStackTrace(); } } private void buildDialog() { d = new Dialog(this,android.R.style.Theme_Translucent_NoTitleBar_Fullscreen); d.setContentView(R.layout.light_setting); d.show(); } class MyGLSurfaceView extends GLSurfaceView{ public MyGLSurfaceView(Context context) { super(context); } public MyGLSurfaceView(Context context, AttributeSet attrs) { super(context, attrs); } } }