第11讲3D游戏编程
计算机学院
本讲学习目标
3D游戏的设计包括两个部分的工作
1, 3D编程的基础知识
2, 3D游戏的创意
OpenGL相关的术语
了解3D游戏的设计和编程
3D游戏基础
3D游戏基础之一 OpenGL
OpenGL Open Graphics Library
OpenGL是一个定义了跨编程语言、跨平台的
编程接口的规范,它用于三维图象(二维)。
OpenGL也是个专业的图形程序接口,是一个
功能强大,调用方便的底层图形库。
3D游戏基础
《OpenGL Reference Manual》,OpenGL
参考手册
可以获得OpenGL文档
3D游戏基础最好有计算机图形学基础
3D游戏基础
OpenGL特点及功能
OpenGL是一个开放的三维图形软件包,它独
立于窗口系统和操作系统,以它为基础开发的
应用程序可以十分方便地在各种平台间移植;
OpenGL广泛用于3D游戏;OpenGL使用简便
,效率高。它具有七大功能:
3D游戏基础
OpenGL特点及功能
1.建模:OpenGL图形库除了提供基本的点、
线、多边形的绘制函数外,还提供了复杂的三
维物体(球、锥、多面体、茶壶等)以及复杂
曲线和曲面绘制函数。
3D游戏基础
OpenGL特点及功能
2.变换:OpenGL图形库的变换包括基本变换
和投影变换。基本变换有平移、旋转、变比镜
像四种变换,投影变换有平行投影(又称正射
投影)和透视投影两种变换。其变换方法有
利于减少算法的运行时间,提高三维图形的显
示速度。
3D游戏基础
OpenGL特点及功能
3.颜色模式设置:OpenGL颜色模式有两种,
即RGBA模式和颜色索引(Color Index)。
3D游戏基础
OpenGL特点及功能
4.光照和材质设置:OpenGL光有辐射光(
Emitted Light)、环境光(Ambient Light)、
漫反射光(Diffuse Light)和镜面光(
Specular Light)。材质是用光反射率来表示
。场景(Scene)中物体最终反映到人眼的颜
色是光的红绿蓝分量与材质红绿蓝分量的反射
率相乘后形成的颜色。
3D游戏基础
OpenGL特点及功能
5:纹理映射(Texture Mapping)。利用
OpenGL纹理映射功能可以十分逼真地表达物
体表面细节。
3D游戏基础
OpenGL特点及功能
6:位图显示和图象增强图象功能除了基本的拷
贝和像素读写外,还提供融合(Blending)、
反走样(Antialiasing)和雾(fog)的特殊图
象效果处理。以上三条可使被仿真物更具真实
感,增强图形显示的效果。
3D游戏基础
OpenGL特点及功能
7:双缓存动画(Double Buffering)双缓存即
前台缓存和后台缓存,简言之,后台缓存计算
场景、生成画面,前台缓存显示后台缓存已画
好的画面。
此外,利用OpenGL还能实现深度暗示(
Depth Cue)、运动模糊(Motion Blur)等特
殊效果。从而实现了消隐算法。
3D游戏基础
Android系统使用 OpenGL 的标准接口来支持
3D 图形功能
3D游戏基础
在Java 框架层,
是 java
标准的 OpenGL 包,包提供了
OpenGL 系统和 Android GUI 系统之间的联
系。
Android系统使用 OpenGL画3D 时要引入上
面两个包中的类
3D游戏基础
Android支持OpenGL列表
1、GL
2、GL 10
3、GL 10 EXT
4、GL 11
5、GL 11 EXT
6、GL 11 ExtensionPack
我们将使用 GL10 这个版本开始接触 OpenGL
,探索 3D 绘图。
GL10指GL1 .0版
opengl 3D 绘图
是一个类包
Provides OpenGL utilities.
opengl 3D绘图
使用opengl绘制3D图形应该有三部分工作
1> create a custom View subclass.(for
stored the next draw graphics).
2> get an gl reader
3> draw some graphic
具体解释如下:
opengl 3D 绘图
1> 在android中首先要取得一个
GLSurfaceView类的对象.这个对象用来保存画
出的图形.
画图的具体操作是在Render中来实现的.通
过GLSurfaceView的setRender对象来开启一
个线程绘制图形.
opengl 3D 绘图
2> 实现接口.
这个类就是绘图的主要类,具体画图是在
的onDrawFrame方
法里面,在GLSurfaceView中会不停的调用这个
方法画图.
每次画前如非特别需要都得去清空一次屏幕.
opengl 3D 绘图
绘图的过程:
1> 设置要画图的点,一般是中心点. (这个可以
去用openGL中ViewPoint)
2> 启用各种数组
3> 关联顶点坐标数组
4> 关联顶点颜色数组
5> 画各种图形.点/线/多边形.
GLSurfaceView类
GLSurfaceView
一个SurfaceView实现,它使用了专用的表
面显示OpenGL画出的图形,是图形运行的环境
GLSurfaceView是也绘制3D图形的环境,可以把
这个环境加载到android 的界面Activity上去
GLSurfaceView派生于View类
GLSurfaceView类
使用GLSurfaceView类
通常,使用GLSurfaceView的子类
在大多数情况下,GLSurfaceView行为是通过调
用 “set”方法定制的.。
例如,通过调用setRenderer(Renderer)。绘
图委派给一个独立的Renderer对象完成
GLSurfaceView类
初始化GLSurfaceView
调用setRenderer(Renderer)完成
调用setRenderer()注册一
个。
(Renderer做具体的OpenGL画图工作)
GLSurfaceView类
使用GLSurfaceView实例
class MyGLSurfaceView extends GLSurfaceView
{
private MyRenderer mMyRenderer; //声明类的对象
public void start()
{ mMyRenderer = new MyRenderer (this); //类对象的实例化
setRenderer(mMyRenderer); //注册一个Renderer
}
public boolean onTouchEvent(final MotionEvent event)
{
queueEvent(new Runnable() {
public void run() {
(() / getWidth(), () / getHeight(), );
} } );
return true;
};
}
Renderer接口
Renderer是GLSurfaceView的一个接口
interface
一个普通的绘图接口
The renderer is responsible for making
OpenGL calls to render a frame.
渲染器负责调用OpenGL函数画一帧(组成动
画的单幅图象)
Renderer接口
使用Renderer
通常,使用Renderer的子类
渲染器将以一个独立的线程被调用,使渲染性
能从UI线程中分离出来。
通常需要通过UI线程与渲染器通信,因为UI线
程是接收输入事件的界面。
可以使用标准的Java技术通跨线程通信,或者
可以使用queueEvent(Runnable接口)的便
捷方法跨线程通信。
Renderer接口
使用Renderer实例
public class SubRenderer implements
{
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// Do nothing special. surface创建以后调用
}
@Override
public void onSurfaceChanged(GL10 gl, int w, int h) {
//在surface发生改变以后调用,例如从竖屏切换到横屏的时候
(0, 0, w, h); //x,y,width,height,(0,0)指左下角,单位:像素
}
Renderer接口
使用Renderer实例
@Override
public void onDrawFrame(GL10 gl) {
//具体画图方法,每次画图前一般都要清空一次屏幕
//通过glClearColor()方法为底色定义了颜色。底色是在我们能到
//的所有东西的后面
//m_red, m_green, m_blue, m_alpha的值是在color
//buffer被 clear 后使用的
(m_red, m_green, m_blue, m_alpha);
// clear the color buffer to show the ClearColor we called above...
(_COLOR_BUFFER_BIT);
}
}
Renderer接口
使用Renderer实例 (docs)
Public Methods
public abstract void onDrawFrame (GL10 gl)
Called to draw the current frame.
This method is responsible for drawing the current frame.
The implementation of this method typically looks like this:
void onDrawFrame(GL10 gl)
{ (_COLOR_BUFFER_BIT |
_DEPTH_BUFFER_BIT);
//... other gl calls to render the scene ... }
Parameters
gl the GL interface.
Use instance of to test if the interface supports GL11 or higher
interfaces.
Renderer接口
使用Renderer实例
public interface GL10
implements(实现) GL
Renderer接口
使用Renderer实例 (docs)
public abstract void onSurfaceChanged (GL10 gl, int width, int
height)
Called when the surface changed size.
Called after the surface is created and whenever the OpenGL ES
surface size changes.
Typically you will set your viewport here. If your camera is fixed
then you could also set your projection matrix here:
void onSurfaceChanged(GL10 gl, int width, int height)
{ (0, 0, width, height);
}
Parameters
gl the GL interface.
Use instanceof to test if the interface supports GL11 or higher
interfaces.
Renderer接口
使用Renderer实例 (docs)
public abstract void onSurfaceCreated (GL10 gl, EGLConfig config)
Called when the surface is created or recreated.
Called when the rendering thread starts and whenever the EGL context
is lost. The EGL context will typically be lost when the Android device
awakes after going to sleep.
Parameters
gl the GL interface. Use instanceof to test if the interface supports GL11
or higher the EGLConfig of the created surface. Can
be used to create matching pbuffers.
OpenglDemo实例
建立一个OpenglDemo实例
演示如何使用
GLSurfaceView类
和Renderer接口,构造
一个3D背景环境,
并能够监听touch,click等事件,
当touch时改变背景环境颜色,
颜色值取决于touch的位置
OpenglDemo实例
监听touch,click
事件,当touch时改变
背景环境颜色
OpenglDemo实例
1,建立一个OpenglDemo工程
OpenglDemo实例
2,在OpenglDemo工程中,从GLSurfaceView类派生出一个子类
SubGLSurfaceView
实现GLSurfaceView的最小代码集
import ;
import ;
public class SubGLSurfaceView extends GLSurfaceView {
public SubGLSurfaceView(Context context)
{
super(context);
};
}
//这个SubGLSurfaceView什么具体的工作也没做
OpenglDemo实例
3,在OpenglDemo工程中,从Renderer接口派生出一个子类SubRenderer
实现SubRenderer的最小代码集,包含有三个回调函数
import ;
import ;
import ;
public class SubRenderer implements {
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// Do nothing special.
}
@Override
public void onSurfaceChanged(GL10 gl, int w, int h) {
(0, 0, w, h);
}
@Override
public void onDrawFrame(GL10 gl) {
// define the color we want to be displayed as the "clipping wall"
// clear the color buffer to show the ClearColor we called above...
(_COLOR_BUFFER_BIT);
}
}
OpenglDemo实例
3,在OpenglDemo工程中,从Renderer接口派生出一个子类
SubRenderer
为了让颜色变化可见,我们必须调用glClear()以及颜
色缓冲的Mask来清空buffer,然后为我们的底色使用
新的底色。
在SubRenderer中来创建一个设置颜色的函数。
public void setColor(float r, float g, float b) {
m_red = r;
m_green = g;
m_blue = b;
}
OpenglDemo实例
3,在OpenglDemo工程中,从Renderer接口派生出一个子类
SubRenderer
下面是SubGLSurfaceView类中创建的方法来处理MotionEvent。
public boolean onTouchEvent(final MotionEvent event) {
queueEvent(new Runnable() {
public void run() {
(() / getWidth(), () /
getHeight(), );
}
});
return true;
}
OpenglDemo实例
我们创建了一个匿名的Runnable对象,这里
的run()方法调用renderer中的setColor方法。
这有会根据MotionEvent坐标做一些小的计算
。
现在我们已经有了一段代码使用OpenGl来改
变我们的背景色了。
OpenglDemo实例
4,在SubGLSurfaceView类中注册子类
SubRenderer的对象
public class SubGLSurfaceView extends GLSurfaceView {
private SubRenderer m_renderer; //声明
public SubGLSurfaceView(Context context)
{
super(context);
m_renderer = new SubRenderer(); //实例化
setRenderer(m_renderer); //注册
};
}
OpenglDemo实例
5,在SubGLSurfaceView类中增加一个touch监听器
public class SubGLSurfaceView extends GLSurfaceView {
private SubRenderer m_renderer;
public SubGLSurfaceView(Context context)
{
super(context);
m_renderer = new SubRenderer();
setRenderer(m_renderer);
};
public boolean onTouchEvent(final MotionEvent event) {
queueEvent(new Runnable() {
public void run() {
(() / getWidth(), () /
getHeight(), ); //颜色值随位置变化
} } );
return true;
};
}
OpenglDemo实例
6, 把SubGLSurfaceView类显示到Activity上
public class OpenglDemo extends Activity {
/** Called when the activity is first created. */
private SubGLSurfaceView m_GLSurfaceView; //声明
@Override
public void onCreate(Bundle savedInstanceState) {
(savedInstanceState);
// setContentView();
m_GLSurfaceView = new SubGLSurfaceView (this);
setContentView(m_GLSurfaceView);
}
}
在OpenglDemo添加一个三角形
这个工作是初始化需要显示的三角形。要在
SubRenderer类中添加一个方法 ,因为
SubRenderer类是负责调用OpenGL画图形
的
首先介绍OpenGL的一些相关术语
在OpenglDemo添加一个三角形
OpenGL的一些相关术语
Vertex 顶点
顶点是3D空间中的一个点,也是许多对象的
基础元素
vertex的复数是vertices
顶点数组 顶点数据组成的数组
在OpenglDemo添加一个三角形
OpenGL的一些相关术语
在OpenGL中可以声明二维坐标(X,Y),三维坐
标(X,Y, Z),或四维(X,Y,Z,W).
w轴是可选的,默认的值是. Z轴也是可选
的,默认值为0.
3D游戏用到3个主要的坐标X,Y,Z(W一般都
是被用来作为占位符)。
在OpenglDemo添加一个三角形
OpenGL的一些相关术语
Triangle 三角形
在OpenGL中,使用3个顶点来创建一个三角
形。
在OpenglDemo添加一个三角形
OpenGL的一些相关术语
Polygon 多边形
在OpenGL中,多边形是至少有3个连接着的
点组成的一个对象。
三角形也是一个多边形。
在OpenglDemo添加一个三角形
OpenGL的一些相关术语
Primitives 图元。
一个Primitive是一个三维的对象,使用三角形
或者多边形创建。
简单来说,一个有10000个顶点的比较精细的
模型是一个Primitive,而一个只有100个顶点
的低模也叫做一个Primitive。
在OpenglDemo添加一个三角形
OpenGL的一些相关术语
一个Primitive或多个Primitives就构成了一帧
3D图
在OpenglDemo添加一个三角形并
下面的工作是在OpenglDemo添加一个三角形
在OpenglDemo添加一个三角形并
下面开始在OpenglDemo添加一个三角形
在SubRenderer类中添加一个画三角形方法
首先要声明一些画三角形对象的变量 ,这是Java知识
这里要引入包(new I/O)
包中定义了作为数据容器的缓冲区(buffer),可以把
这个缓冲区看做为内存中的一个大的数组,用来存储同一
类型的数据
包提供了API访问这个缓冲区,如Clear其中的内容,
支持读写这个缓冲区
在OpenglDemo添加一个三角形
例如,可以使用字节,字符,整数,浮点型等缓冲区类型
字节缓冲区类型举例如下
import ; //引入包
import ; //引入包
ByteBuffer vbb; //声明字节缓冲区类型
ByteBuffer ibb ; //声明字节缓冲区类型
vbb = (4*12); //分配4*12个字节空间的缓冲区
(()); //保证java虚拟机缓冲区字节顺序符合要求
//nativeOrder()获得java虚拟机运行的硬件的本机字节顺序
//order(ByteOrder bo) 修改此缓冲区的字节顺序
ibb = (2*3); //分配2*3个字节空间的缓冲区
(());
在OpenglDemo添加一个三角形
整数和浮点类型缓冲区类型举例如下
import ; //引入包
import ; //引入包
FloatBuffer _vertexBuffer;
//声明浮点类型缓冲区 float has 4 bytes,为三角形保存坐标
ShortBuffer _indexBuffer;
//声明整数类型缓冲区 short has 2 bytes,保存_vertexBuffer的索引
_vertexBuffer = ();
_vertexBuffer = (); //分配4*12个字节空间的缓冲区见上页的定义
_indexBuffer = (); //分配2*3个字节空间的缓冲区见上页的定义
在OpenglDemo添加一个三角形
整数缓冲区的赋值
short[] _indicesArray = {0, 1, 2};
//声明short数组并初始化
(_indicesArray);
// put(short [] src) 把_indicesArray赋值到缓冲区,即索引为0, 1, 2
(0);
//position 读/写操作的当前下标,操作完成后,buffer会更新下标值
//buffer设置position为0.
在OpenglDemo添加一个三角形
浮点类型缓冲区的赋值
float[ ] coords = { //声明float数组并初始化
, , 0f, // (x1, y1, z1)
, , 0f, // (x2, y2, z2)
0f, , 0f // (x3, y3, z3)
};
(coords);
// put(float [] src) 把coords赋值到缓冲区
(0);
//buffer设置position为0.
在OpenglDemo添加一个三角形
在SubRenderer类中添加一个画三角形
调用glEnableClientState(int array)设置OpenGL使用vertex数组来画。
import ;
函数原型:
public abstract void glEnableClientState (int array) ;
enable or disable client-side capability
a r r a y 参数指定了需要启用的数组。a r r a y 参数可以使用下面这些符号常量:
GL_VERTEX_ARRAY、 //使用vertex数组
GL_COLOR_ARRAY、 //RBGA颜色
GL_SECONDARY_COLOR_ARRAY、 //辅助颜色
GL_INDEX_ARRAY、 //颜色索引
GL_NORMAL_ARRAY、 //表面法线
GL_FOG_COORDINATE_ARRAY、 //雾坐标
GL_TEXTURE_COORD_ ARRAY //纹理坐标
GL_EDGE_FLAG_ARRAY。 //多边形的边界标志
//public abstract void glDisableClientState (int array) 可以禁用vertex数组
在OpenglDemo添加一个三角形
调用glEnableClientState(int array)设置OpenGL
使用vertex数组来画。要在画前设置
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// Do nothing special.
(_VERTEX_ARRAY);
}
在OpenglDemo添加一个三角形
stride Specifies the byte offset between consecutive vertices.
If stride is 0, the vertices are understood to be tightly packed
in the array. The initial value is 0.
pointer Specifies a pointer to the first coordinate of the first vertex in the
array. The initial value is 0.
例如:
(3, _FLOAT, 0,
_vertexBuffer);
此例中,数据以3个数一组,类型都是GL_FLOAT,
跨度为0表示数据紧密排列,指针自然指向刚才分配
的顶点数组数据。
在OpenglDemo添加一个三角形
glDrawElements render primitives from array data
用指定顶点数组的数据画一个图元。
void glDrawElements( GLenum mode,
GLsizei count,
GLenum type,
const GLvoid * indices);
Parameters
mode Specifies what kind of primitives to render.
Symbolic constants
GL_POINTS,GL_LINE_STRIP,GL_LINE_LOOP,
GL_LINES,GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN,
GL_TRIANGLES, GL_QUAD_STRIP, GL_QUADS,
and GL_POLYGON are accepted.
在OpenglDemo添加一个三角形
count Specifies the number of elements to be
rendered.
Type Specifies the type of the values in indices. Must be
one of
GL_UNSIGNED_BYTE,
GL_UNSIGNED_SHORT, or
GL_UNSIGNED_INT.
Indices (pl of Index) Specifies a pointer to the location
where the indices are stored.
在OpenglDemo添加一个三角形
例如:
(_TRIANGLES, _nrOfVertices,
_UNSIGNED_SHORT, _indexBuffer);
此例中,画的图元是三角形,图元有三个元素中,索
引值类型_UNSIGNED_SHORT
第一个参数定义了什么样的图元将被画出来
。第二个参数定义有多少个元素,第三个是
indices使用的数据类型。最后一个是绘制顶点
使用的索引缓冲。
在OpenglDemo添加一个三角形
设定当前色,采用RGBA
A alpha透明代表透明度
例如:
(, 0f, 0f, );
这个是半透明
在OpenglDemo添加一个三角形
画三角型的过程
(, 0f, 0f, );
(3, _FLOAT, 0,
_vertexBuffer);
(_TRIANGLES,
_nrOfVertices,
_UNSIGNED_SHORT, _indexBuffer);
//类推可以画多边形
在OpenglDemo旋转三角形
这个工作是旋转上一节中显示的三角形。
效果图
看程序
在OpenglDemo旋转三角形
在在SubRenderer类中实现旋转三角形
float _angle; //旋转的角度
public void setAngle(float angle) {
_angle = angle;
}
在OpenglDemo旋转三角形
在在SubRenderer类中实现旋转三角形
()方法在glColor4f()之前被
onDrawFrame()调用.
(_angle, 0f, 1f, 0f);
//绕y轴旋转 ,如果需要改变轴旋转,只需要改
变glRotate()方法中的0f。这个参数中的值表示
一个向量,标志三角形绕着旋转的坐标轴。
在OpenglDemo旋转三角形
在在SubRenderer类中实现旋转三角形
希望能对旋转进行更多的控制。为此,在每次
调用onDrawFrame()方法的时候都会重置这个
矩阵。这会重设三角形的角度以便其总是可以
旋转到给定的角度。
// reset the matrix - good to fix the rotation to a
static angle
();
在OpenglDemo旋转三角形
在SubGLSurfaceView类的onTouchEvent函
数中完成设置旋转的角度值,添加一个调用
(());
在OpenglDemo给三角形添加颜色
这个工作是旋转上一节中显示的三角形上添加颜色
在OpenglDemo给三角形添加颜色
这个工作是旋转上一节中显示的三角形上添加
颜色
保存颜色信息创建一个新的buffer。这个
_colorBuffer是一个对象变量,但是我们需要
在initVertexBuffer ()方法中定义颜色并填充这
个buffer.
// a raw buffer to hold the colors
private FloatBuffer _colorBuffer;
在OpenglDemo给三角形添加颜色
// float has 4 bytes, 4 colors (RGBA) *
number of vertices * 4 bytes
ByteBuffer cbb = (4 *
_nrOfVertices * 4);
(());
_colorBuffer = ();
在OpenglDemo给三角形添加颜色
float[] colors = {
1f, 0f, 0f, 1f, // point 1
0f, 1f, 0f, 1f, // point 2
0f, 0f, 1f, 1f, // point 3
};
(colors);
(0);
在OpenglDemo给三角形添加颜色
我们开始告诉OpenGL ES使用我们的颜色数组。这通过glEnableClientState(),以及
glColorPointer()来完成,和vertexBuffer类似。
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// preparation
(_VERTEX_ARRAY);
(_COLOR_ARRAY);
initTriangle();
}
@Override
public void onDrawFrame(GL10 gl) {
// code snipped
// (, 0f, 0f, );
(3, _FLOAT, 0, _vertexBuffer);
(4, _FLOAT, 0, _colorBuffer);
(_TRIANGLES, _nrOfVertices,
_UNSIGNED_SHORT, _indexBuffer);
}
//参数4表示RGBA(RGBA刚好是四个值)
我们注释掉了15行,因为我们使用的是color mode,所以不再需要glColor4f。它会覆盖,所以
我们可以注注释掉
习题:
。
第11讲3D游戏编程
主讲介绍:
本讲学习目标
3D游戏基础
3D游戏基础
3D游戏基础
3D游戏基础
3D游戏基础
3D游戏基础
3D游戏基础
3D游戏基础
3D游戏基础
3D游戏基础
3D游戏基础
3D游戏基础
3D游戏基础
opengl 3D 绘图
opengl 3D绘图
opengl 3D 绘图
opengl 3D 绘图
opengl 3D 绘图
GLSurfaceView 类
GLSurfaceView 类
GLSurfaceView 类
GLSurfaceView 类
Renderer接口
Renderer接口
Renderer接口
Renderer接口
Renderer接口
Renderer接口
Renderer接口
Renderer接口
OpenglDemo实例
OpenglDemo实例
OpenglDemo实例
OpenglDemo实例
OpenglDemo实例
OpenglDemo实例
OpenglDemo实例
OpenglDemo实例
OpenglDemo实例
OpenglDemo实例
OpenglDemo实例
在OpenglDemo添加一个三角形
在OpenglDemo旋转三角形
在OpenglDemo旋转三角形
在OpenglDemo旋转三角形
在OpenglDemo旋转三角形
在OpenglDemo旋转三角形
习题: