在前面我们已经可以绘制出一个带有颜色的立方体了,但是这些颜色是系统自带的黄色,绿色等,有时候这并不能满足我们的要求,这时候就需要将纹理映射到立方体上去了。
为使用纹理,我们需要打开OpenGL的一些开关以启动我们需要的一些功能:
gl.glEnable(GL10.GL_TEXTURE_2D);
这个调用是必不可缺的;如果你没有打开此功能,那么你就无法将图像映射到多边形上。它可以在需要时打开和关闭,通常在初始化时打开。
生成纹理
OpenGL 中的纹理通过一个唯一号引用,通过函数 glBindTexture() 实现。你 可以自己指定这个唯一号,或者通过调用 glGenTextures () 函数生成一个唯一 号。
// 2.生成纹理ID
int[] tmp_tex = new int[1];//尽管只有一个纹理,但使用一个元素的数组
//glGenTextures(申请个数,存放数组,偏移值)
gl.glGenTextures(1, tmp_tex, 0); //向系统申请可用的,用于标示纹理的ID
int texture = tmp_tex[0];
纹理绑定
在为纹理生成名称后,在为纹理提供图像数据之前,我们必须绑定纹理。绑定使得指定纹理处于活动状态。一次只能激活一个纹理。活动的或“被绑定”的纹理是绘制多边形时使用的纹理,也是新纹理数据将加载其上纹理,所以在提供图像数据前必须绑定纹理。
gl.glBindTexture(GL10.GL_TEXTURE_2D, texture);
绑定纹理数据,传入指定图片
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0);
下面看一下完整代码:
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLU;
import android.opengl.GLUtils;
public class CubeRenderer implements Renderer {
Bitmap bmp;
float box[] = new float[] {
// FRONT
-0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
// BACK
-0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
// LEFT
-0.5f, -0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
// RIGHT
0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
// TOP
-0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
// BOTTOM
-0.5f, -0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
0.5f, -0.5f, -0.5f,
};
float lightAmbient[] = new float[] { 0.5f, 0.5f, 0.6f, 1.0f }; //环境光
float lightDiffuse[] = new float[] { 0.6f, 0.6f, 0.6f, 1.0f };//漫反射光
float[] lightPos = new float[] {0,0,3,1}; //光源位置
/*
* 因为进行光照处理,你必须告知系统你定义的模型各个面的方向,以便系统计算光影情况,方向的描述是通过向量点来描述的
*/
float norms[] = new float[] { //法向量数组,用于描述个顶点的方向,以此说明各个面的方向
// FRONT
0f, 0f, 1f, //方向为(0,0,0)至(0,0,1)即Z轴正方向
0f, 0f, 1f,
0f, 0f, 1f,
0f, 0f, 1f,
// BACK
0f, 0f, -1f,
0f, 0f, -1f,
0f, 0f, -1f,
0f, 0f, -1f,
// LEFT
-1f, 0f, 0f,
-1f, 0f, 0f,
-1f, 0f, 0f,
-1f, 0f, 0f,
// RIGHT
1f, 0f, 0f,
1f, 0f, 0f,
1f, 0f, 0f,
1f, 0f, 0f,
// TOP
0f, 1f, 0f,
0f, 1f, 0f,
0f, 1f, 0f,
0f, 1f, 0f,
// BOTTOM
0f, -1f, 0f,
0f, -1f, 0f,
0f, -1f, 0f,
0f, -1f, 0f
};
float texCoords[] = new float[] { //纹理坐标对应数组
// FRONT
0.0f, 0.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
// BACK
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 0.0f,
0.0f, 1.0f,
// LEFT
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 0.0f,
0.0f, 1.0f,
// RIGHT
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 0.0f,
0.0f, 1.0f,
// TOP
0.0f, 0.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
// BOTTOM
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 0.0f,
0.0f, 1.0f
};
FloatBuffer cubeBuff;
FloatBuffer normBuff;
FloatBuffer texBuff;
float xrot = 0.0f;
float yrot = 0.0f;
/**
* 将float数组转换存储在字节缓冲数组
* @param arr
* @return
*/
public FloatBuffer makeFloatBuffer(float[] arr) {
ByteBuffer bb = ByteBuffer.allocateDirect(arr.length * 4);//分配缓冲空间,一个float占4个字节
bb.order(ByteOrder.nativeOrder()); //设置字节顺序, 其中ByteOrder.nativeOrder()是获取本机字节顺序
FloatBuffer fb = bb.asFloatBuffer(); //转换为float型
fb.put(arr); //添加数据
fb.position(0); //设置数组的起始位置
return fb;
}
public CubeRenderer(Context c) {
// TODO Auto-generated constructor stub
cubeBuff = makeFloatBuffer(box);//转换float数组
normBuff = makeFloatBuffer(norms);
texBuff = makeFloatBuffer(texCoords);
bmp = BitmapFactory.decodeResource(c.getResources(), R.drawable.splash);
}
protected void init(GL10 gl) {
gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);//设置清屏时背景的颜色,R,G,B,A
gl.glEnable(GL10.GL_LIGHTING); //启用光照
gl.glEnable(GL10.GL_LIGHT0); //开启光源0
//设置光照参数,也可以使用默认的,不设置
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, lightAmbient, 0);
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, lightDiffuse, 0);
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightPos, 0);
gl.glNormalPointer(GL10.GL_FLOAT, 0, normBuff);
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
//使用纹理步骤:
// 1.开启贴图
gl.glEnable(GL10.GL_TEXTURE_2D);
// 2.生成纹理ID
int[] tmp_tex = new int[1];//尽管只有一个纹理,但使用一个元素的数组
//glGenTextures(申请个数,存放数组,偏移值)
gl.glGenTextures(1, tmp_tex, 0); //向系统申请可用的,用于标示纹理的ID
int texture = tmp_tex[0];
//3.绑定纹理,使得指定纹理处于活动状态。一次只能激活一个纹理
gl.glBindTexture(GL10.GL_TEXTURE_2D, texture);
//4.绑定纹理数据,传入指定图片
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0);
//5.传递各个顶点对应的纹理坐标
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texBuff);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); //开启纹理坐标数组
//6.设置纹理参数 (可选)
/*下面的两行参数告诉OpenGL在显示图像时,当它比放大得原始的纹理大
*( GL_TEXTURE_MAG_FILTER )或缩小得比原始得纹理小( GL_TEXTURE_MIN_FILTER )
*时OpenGL采用的滤波方式。通常这两种情况下我都采用 GL_LINEAR 。这使得纹理从很远处
*到离屏幕很近时都平滑显示。使用 GL_LINEAR 需要CPU和显卡做更多的运算。如果您的机器很慢,
*您也许应该采用 GL_NEAREST 。过滤的纹理在放大的时候,看起来马赛克的很。您也可以结合这
*两种滤波方式。在近处时使用 GL_LINEAR ,远处时 GL_NEAREST 。
**/
gl.glTexParameterx(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MAG_FILTER,GL10.GL_LINEAR);
gl.glTexParameterx(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_LINEAR);
gl.glEnable(GL10.GL_DEPTH_TEST); //启用深度缓存
gl.glEnable(GL10.GL_CULL_FACE); //启用背面剪裁
gl.glClearDepthf(1.0f); // 设置深度缓存值
gl.glDepthFunc(GL10.GL_LEQUAL); // 设置深度缓存比较函数,GL_LEQUAL表示新的像素的深度缓存值小于等于当前像素的深度缓存值(通过gl.glClearDepthf(1.0f)设置)时通过深度测试
gl.glShadeModel(GL10.GL_SMOOTH);// 设置阴影模式GL_SMOOTH
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// TODO Auto-generated method stub
init(gl);
}
@Override
public void onSurfaceChanged(GL10 gl, int w, int h) {
// TODO Auto-generated method stub
gl.glViewport(0, 0, w, h); //设置视窗
gl.glMatrixMode(GL10.GL_PROJECTION); // 设置投影矩阵
gl.glLoadIdentity(); //设置矩阵为单位矩阵,相当于重置矩阵
GLU.gluPerspective(gl, 45.0f, ((float) w) / h, 0.1f, 10f);//设置透视范围
}
@Override
public void onDrawFrame(GL10 gl) {
// TODO Auto-generated method stub
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);// 清除屏幕和深度缓存
gl.glMatrixMode(GL10.GL_MODELVIEW); //切换至模型观察矩阵
gl.glLoadIdentity();// 重置当前的模型观察矩阵
GLU.gluLookAt(gl, 0, 0, 3, 0, 0, 0, 0, 1, 0);//设置视点和模型中心位置
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, cubeBuff);//设置顶点数据
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glRotatef(xrot, 1, 0, 0); //绕着(0,0,0)与(1,0,0)即x轴旋转
gl.glRotatef(yrot, 0, 1, 0);
gl.glColor4f(1.0f, 0, 0, 1.0f); //设置颜色,红色
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4); //绘制正方型FRONT面
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 4, 4);
gl.glColor4f(0, 1.0f, 0, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 8, 4);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 12, 4);
gl.glColor4f(0, 0, 1.0f, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 16, 4);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 20, 4);
xrot += 0.5f;
yrot += 0.5f;
}
}
上面重要的部分都已经做了注释,下面看一些运行后效果:
分享到:
相关推荐
OPENGL光照和纹理技术实例.rar OPENGL光照和纹理技术实例.rar
做的是把一个旋转立方体的6个面贴上6幅不同的图片,设置了两个键盘控制,一个是通过glutKeyboardFunc(keyboard);来控制灯光的开和关,用glutSpecialFunc(special);来分别改变立方体延x,y,z轴的旋转角度。
openGL实现机器人,可以自动运动,并且实现了纹理映射和光照
NURBS曲面的创建,并实现简单纹理映射与光照模型
用opengl制作正四面体旋转加光照加纹理映射
方向键可以进行移动,按F键更改纹理,按B键添加光照。 立方体上面的是贝塞尔曲面,可以通过A键和D键进行旋转,还可以通过W和S键进行变换曲面的扭曲程度。按空格键可以时曲面的轮廓消失。 最里边是一个变幻的圆环 。 ...
此程序使用Opengl绘制了带6个纹理的立方体(立方体的每个面用bezier曲面表示),实现了键盘和鼠标控制,其中键盘控制如下: L :控制光照光照 ←:向左旋转速度增加 →:向右旋转速度增加 ↑:向上旋转速度增加 ↓:向...
Android OpenGL实现立方体多纹理图片映射和混色光照效果
本程序画了一个地球仪,包含基本图形的绘制,光照的设置,材质的设置,纹理映射,动画等等
绘制一个具有真实感的三维场景,其中含有2个三维物体。具有光照,纹理效果,可实现交互式的场景漫游。使用OpenGL,完成从建模、坐标变换到消隐算法、光照模型、面绘制算法、纹理映射的全部过程。
第一章OpenGL使人们进入三维图形世界 第二章OpenGL基本理解 ...第十二章OpenGL纹理映射 第十三章OpenGL复杂图元建模 第十四章OpenGL光照模型 第十五章OpenGL的三个特殊效果处理 第十六章OpenGL显示列表
基于OpenGL的B样条曲线曲面的绘制算法,包含了均匀、准均匀、Bezier、各种非均匀B样条曲线曲面的绘制,阶次的升降,以及曲面的光照和纹理映射算法。
介绍了为了增加计算机图形真实感, 如何使用纹理映射的简要说明。
实验一 OpenGL+GLUT...小实验13:纹理映射初步—掌握OpenGL纹理映射的一般步骤 56 小实验13:纹理映射—纹理坐标的自动生成(基于参数的曲面映射) 59 小实验14:纹理映射—纹理坐标的自动生成(基于参考面距离) 61
基于OPENGL的二次曲面屏保程序代码,涉及二次曲面的绘制与纹理映射算法。
教您如何使用键盘来移动场景中的对象,还会教您在OpenGL场景中应用简单的光照。这一课包含了很多内容,如果您对前面的课程有疑问的话,先回头复习一下。进入后面的代码之前,很好的理解基础知识十分重要。
本书以清晰的语言阐述了OpenGL的功能以及众多计算机图形学基本技术 如构建和渲染3D模型 从不同的角度观察物体 使用着色 光照和纹理映射来提高图像的真实感;深入探讨了一些高级技术 其中包括纹理映射 反走样 雾效和...
不过觉得内容挺全的,一共分二大部分:Jeff Molofee的OpenGL教程和OPenGL基础图形编程教程,在Jeff Molofee的OpenGL教程里,你将学习第一个OPENGL三角形的生成、着色、转起来、向3D进军、纹理映射、简单的透明、飘动...
然后深入探讨一些高级技术,包括反走样、混合、雾效、显示列表、图像处理、纹理映射、帧缓存、网格化、NURBS、选择和反馈等;同时讨论其他一些重要主题,像如何提高程序的性能、OpenGL扩展和跨平台技术等。本书只...