[OpenGL ES 04]3D变换实践篇:平移,旋转,缩放

20 篇文章 0 订阅
8 篇文章 6 订阅

[OpenGL ES 04]3D变换实践篇:平移,旋转,缩放

罗朝辉 (http://blog.csdn.net/kesalin)

本文遵循“署名-非商业用途-保持一致”创作公用协议

前言

前文《[OpenGL ES 03]3D变换:模型,视图,投影与Viewport》中已经详细介绍了3D变换相关的数学知识,也讲了基本的模型变换:平移,旋转与缩放,如果你还没有阅读前文或对这些知识还不够明白,务必先弄懂前文再继续。假如你已经准备好继续了,那么在接下来的内容中,我将介绍如何在 OpenGL ES 中运用这些知识,来渲染一个四棱锥,并对它进行平移,旋转与缩放操作,此外本文也演示了如何将 OpenGL View 与 UIView 结合在一起(注意:在实际运用中,不推荐这么做,混合使用 OpenGL View 和 UIView 对效率影响较大)。

本文代码可以从这里获得:点此下载(Tutorial03),最终效果图如下:


 

一,创建工程

1,新建工程

从今天起,我们不再从头开始创建 window 和 view 了,新建一个名为 Tutorial03 的 Single view application 工程:


2,从前面的效果图中可以看到,在这个教程中,我们需要两个 view:OpenGL view 和 UIView。因此打开 MainStoryboard.storyboard,向其中加入两个 view,其中上面那一个用于 OpenGL view,下面那一个用于 control view。调整两个view 的大小与位置,将下面的 view 的背景设置为浅蓝色,以方便区分。


3,拷贝 Tutorial02 教程中的 GLESUtils.h, GLESUtils.m OpenGLView.h, OpenGLView.m 以及 FragmentShader.glsl, VertexShader.glsl 到 Tutorial03 中,并加入到工程中进来,再添加 OpenGLES 以及 QuartzCore framework。


4,在 ViewController.h 中,为这两个view 添加 IBOutlet:

#import "OpenGLView.h"

@interface ViewController : UIViewController

@property (nonatomic, strong) IBOutlet UIView * controlView;
@property (nonatomic, strong) IBOutlet OpenGLView * openGLView;

在 ViewController.m 中 @implementation ViewController 下面的添加

@synthesize controlView, openGLView;

并在 viewDidUnload 中进行清理:

- (void)viewDidUnload
{
    [super viewDidUnload];
    
    [self.openGLView cleanup];
    self.openGLView = nil;
    
    self.controlView = nil;
}

5,回到 MainStoryboard.storyboard,将上面那个 view 的类型设置为 OpenGLView,并关联相关的 IBOutlet:


 

二,描绘四棱锥

1,在 Tutorial02 中只描绘了一个三角形,这回我们来描绘一个真正的 3D 物体:四棱锥。在 OpenGLView.m 中 render() 上面添加如下函数:

- (void)drawTriCone
{
    GLfloat vertices[] = {
        0.5f, 0.5f, 0.0f, 
        0.5f, -0.5f, 0.0f,
        -0.5f, -0.5f, 0.0f,
        -0.5f, 0.5f, 0.0f, 
        0.0f, 0.0f, -0.707f,
    };
    
    GLubyte indices[] = {
        0, 1, 1, 2, 2, 3, 3, 0,
        4, 0, 4, 1, 4, 2, 4, 3
    };
    
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices );
    glEnableVertexAttribArray(_positionSlot);
    
    // Draw lines
    //
    glDrawElements(GL_LINES, sizeof(indices)/sizeof(GLubyte), GL_UNSIGNED_BYTE, indices);
}

这次我们使用顶点索引数组结合 glDrawElements 来渲染,而在 Tutorial02 中,使用的是 glDrawArrays。使用顶点索引数组有什么好处呢?很明显,我们可以减少存储重复顶点的内存消耗。比如在本例的索引表中,我们重复利用了顶点 0,1,2,3,4,它们对应 vertices 数组中5个顶点(三个浮点数组成一个顶点)。

glDrawElements 函数的原型为:

void glDrawElements(    GLenum      mode,
     GLsizei      count,
     GLenum      type,
     const GLvoid *      indices);

第一个参数 mode 为描绘图元的模式,其有效值为:GL_POINTS, GL_LINES, GL_LINE_STRIP,  GL_LINE_LOOP,  GL_TRIANGLES,  GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN。这些模式具体含义下面有介绍。

第二个参数 count 为顶点索引的个数也就是,type 是指顶点索引的数据类型,因为索引始终是正值,索引这里必须是无符号型的非浮点类型,因此只能是 GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT 之一,为了减少内存的消耗,尽量使用最小规格的类型如 GL_UNSIGNED_BYTE。

第三个参数 indices 是存放顶点索引的数组。(indices 是 index 的复数形式,3D 里面很多单词的复数都挺特别的。)

2,使用

修改 render() 函数如下:

- (void)render
{
    glClearColor(0, 1.0, 0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);

    // Setup viewport
    //
    glViewport(0, 0, self.frame.size.width, self.frame.size.height);    
    
    [self drawTriCone];

    [_context presentRenderbuffer:GL_RENDERBUFFER];
}

编译运行程序,你就应该就能看到一个四棱锥了。


也许你会说,怎么看起来不像呢?那是因为你是从四棱锥的正上方朝下俯视它,索引四棱锥的尖顶(就是图中间交叉的那个点)看起来就是平的了。如果我们给程序加入旋转功能,那就会看得非常明显了,在介绍完图元模式之后,我们将加入旋转功能。


三,图元模式介绍:

对于画 line 来说有三种模式:


此外还可以通过函数 glLineWidth(GLfloat width) 来设定线的宽度,要获得当前设置的线宽度可以使用如下代码:

GLfloat lineWidthRange[2];
glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, lineWidthRange);

在 Tutorial02 教程中,我们使用模式 GL_TRIANGLES 描绘了一个三角形。对于三角形来说也有三种模式:


OpenGL ES 还支持描绘点(精灵, sprite)的模式:GL_POINTS,此外还可以通过内建变量 gl_PointSize 来设置点精灵的大小,要获取当前设置的点精灵的大小可以使用如下代码:

GLfloat pointSizeRange[2]; 
glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);

 

四,平移

1,添加控件

为了加入平移控制,我们需要在下面的 view 上面添加滑块对平移的距离进行调节。为此,打开 MainStoryboard.storyboard,在下面浅蓝色背景的 UIView 上添加一个 UILabel 和 UISlider。


并设置滑块的最大值 3,最小值 -3 和当前值 0 :


2,加入控件关联代码

在 ViewController.h 中加入滑块的 IBOutlet 和 IBAction,并将它与 UISlider 关联起来。

@property (nonatomic, strong) IBOutlet UISlider * posXSlider;

- (IBAction)xSliderValueChanged:(id)sender;

在 ViewController.m 中加入:

@synthesize posXSlider;

- (IBAction)xSliderValueChanged:(id)sender
{
    UISlider * slider = (UISlider *)sender;
    float currentValue = [slider value];

    NSLog(@" >> current x is %f", currentValue);
}

这时,如果你拖动滑块,就能输出滑块当前的值。不要忘记在 viewDidUnload 清理该滑块:

self.posXSlider = nil;

 

3,加入平移代码

为了让我们的三棱锥可以在 x 轴上移动,打开 OpenGLView.h,在 @interface 中加入:

float _posX;

然后再加入属性:

@property (nonatomic, assign) float posX;

打开 OpenGLView.m,加入:

@synthesize posX = _posX;

 

4,修改顶点着色器代码

打开 VertexShader.glsl,修改其内容如下:

uniform mat4 projection;
uniform mat4 modelView;
attribute vec4 vPosition; 
 
void main(void)
{
    gl_Position = projection * modelView * vPosition;
}

在上面的代码中,我们对输入顶点进行了自定义的投影和模型视图变换,还记得在前文中介绍的内容么?尤其是左乘,在这里,顶点先进行模型视图变换,然后再进行投影变换。

5,增加实现 Transform 代码

回到 OpenGLView.h 中,加入对应的投影矩阵与模型视图矩阵:

    KSMatrix4 _modelViewMatrix;
    KSMatrix4 _projectionMatrix;

KSMatrix4 是定义在数学辅助库 GLESMath 中用 4 * 4 的二维数组表示的矩阵,你可以在这里获取 GLESMath.h 和 GLESMath.c,并将它们加入工程中。这个数学辅助库中包含了常见的一些 3D 计算,后面还会提到它。

在 OpenGLView.m 中,在 setupProgram 的最后加入获取模型视图矩阵以及投影矩阵变量的槽位:

    // Get the attribute position slot from program
    //
    _positionSlot = glGetAttribLocation(_programHandle, "vPosition");
    
    // Get the uniform model-view matrix slot from program
    //
    _modelViewSlot = glGetUniformLocation(_programHandle, "modelView");
    
    // Get the uniform projection matrix slot from program
    //
    _projectionSlot = glGetUniformLocation(_programHandle, "projection");

 在OpenGLView 的匿名 category 中加入以下两个函数声明:

- (void)setupProjection;

- (void)updateTransform;

然后在 @implemetion 中实现它们:

-(void)setupProjection
{
    // Generate a perspective matrix with a 60 degree FOV
    //
    float aspect = self.frame.size.width / self.frame.size.height;
    ksMatrixLoadIdentity(&_projectionMatrix);
    ksPerspective(&_projectionMatrix, 60.0, aspect, 1.0f, 20.0f);
    
    // Load projection matrix
    glUniformMatrix4fv(_projectionSlot, 1, GL_FALSE, (GLfloat*)&_projectionMatrix.m[0][0]);
}

上面的代码中,ksMatrixLoadIdentity 是 GLESMath 中的一个数学函数,用来将指定矩阵重置为单位矩阵,而 ksPerspective 与前文中讲到的 gluPersoective 作用一样。在这里,我们设置视锥体的近裁剪面到观察者的距离为 1, 远裁剪面到观察者的距离为 20,视角为 60度,然后装载投影矩阵。默认的观察者位置在原点,视线朝向 -Z 方向,因此近裁剪面其实就在 z = -1 这地方,远裁剪面在 z = -20 这地方,z 值不在(-1, -20) 之间的物体是看不到的。不要忘记在初始化代码中调用该函数:

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self setupLayer];        
        [self setupContext];
        [self setupProgram];
        [self setupProjection];
    }

    return self;
}

下面的代码是更新模型视图矩阵,以响应用户的控制。

- (void)updateTransform
{
    // Generate a model view matrix to rotate/translate/scale
    //
    ksMatrixLoadIdentity(&_modelViewMatrix);
    
    // Translate away from the viewer
    //
    ksTranslate(&_modelViewMatrix, self.posX, 0.0, -5.5);
    
    // Rotate the triangle
    //
    ksRotate(&_modelViewMatrix, 0.0, 1.0, 0.0, 0.0);
    
    // Scale the triangle
    ksScale(&_modelViewMatrix, 1.0, 1.0, 1.0);
    
    // Load the model-view matrix
    glUniformMatrix4fv(_modelViewSlot, 1, GL_FALSE, (GLfloat*)&_modelViewMatrix.m[0][0]);
}

上面的代码中,ksTranslate,ksRotate,ksScale 也是 GLESMath 中的数学函数,作用与 glTranslate,glRotate,glScale 相同,分别用于平移,绕轴旋绕以及缩放。在这里,设置在 x 方向上平移,平移量将由 self.posX 控制,而这个属性最终是由滑块控制的,从而达到用户移动物体的目的;将 z 设置为 -5.5 (介于 (-1, -20) 之间,前面有讲);此外还设置绕 x 轴旋绕 0 度,在 x,y,z三个方向上缩放 1 倍,这两个函数的调用是为下一步的旋转和缩放控制准备的。最后,装载模型视图矩阵。

由于需要在 posX 的值变化时,及时更新模型视图矩阵,并重新描绘,以便能及时看到效果,我们得自己实现属性 posX 的 setter 和 getter 方法:

- (void)setPosX:(float)x
{
    _posX = x;
    
    [self updateTransform];
    [self render];
}

- (float)posX
{
    return _posX;
}

6,至此,下层的控制代码就绪了,我们来实现上层 UI 的响应代码,修改 ViewController.m 中的 xSliderValueChanged 方法如下:

- (IBAction)xSliderValueChanged:(id)sender
{
    UISlider * slider = (UISlider *)sender;
    float currentValue = [slider value];
    
    openGLView.posX = currentValue;

    NSLog(@" >> current x is %f", currentValue);
}

7,编译运行,滑动滑块你就能够控制四棱锥在 x 方向上来回移动了(还记得前面限制了 x 的位置只能在 (-3, 3) 之间么,这是为了不让四棱锥跑到屏幕外边去)。聪明的你,应该很容易实现如何控制在 y 和 z 方向的移动了。在实现的过程中要注意,y 滑块的取值范围也为(-3, 3),默认值为0,而 z 滑块的取值范围为(-10, -1),默认值居中为-5.5。这样的设置可以确保物体不会完全跑出视锥体所圈定的范围,因为视锥体之外的物体是不可见的。比如下图中四棱锥的尖顶部分就跑到视锥体的近裁剪面外面去了,所以尖顶就被裁剪了。



五,旋绕,缩放

1,实现下层控制代码

有了控制平移的基础,我们也很容易就能控制旋转与缩放。我们还是从下层开始,修改 OpenGLView.h 中的代码(我将在 y 和 z 方向平移的代码放在这里了,希望你是自己实现它的):

    float _posX;
    float _posY;
    float _posZ;
    
    float _rotateX;
    float _scaleZ;
}

@property (nonatomic, assign) float posX;
@property (nonatomic, assign) float posY;
@property (nonatomic, assign) float posZ;

@property (nonatomic, assign) float scaleZ;
@property (nonatomic, assign) float rotateX;

修改 OpenGLView.m 中的代码:

@synthesize posX = _posX;
@synthesize posY = _posY;
@synthesize posZ = _posZ;
@synthesize scaleZ = _scaleZ;
@synthesize rotateX = _rotateX;

前面说过,我们需要自己实现这些属性的 setter 和 getter 方法,在这里就不一一列出了, 它们与 setPosX 和 posX 的实现是类似的。我们需要让这些属性来控制模型视图矩阵,因此还要更新 updateTransform 方法如下:

- (void)updateTransform
{
    // Generate a model view matrix to rotate/translate/scale
    //
    ksMatrixLoadIdentity(&_modelViewMatrix);
    
    // Translate away from the viewer
    //
    ksTranslate(&_modelViewMatrix, self.posX, self.posY, self.posZ);
    
    // Rotate the triangle
    //
    ksRotate(&_modelViewMatrix, self.rotateX, 1.0, 0.0, 0.0);
    
    // Scale the triangle
    ksScale(&_modelViewMatrix, 1.0, 1.0, self.scaleZ);
    
    // Load the model-view matrix
    glUniformMatrix4fv(_modelViewSlot, 1, GL_FALSE, (GLfloat*)&_modelViewMatrix.m[0][0]);
}

这样四棱锥就能绕 x 轴旋转 rotateX 角度,并在 z 方向上缩放 scaleZ 倍。注意:属性 scaleZ 默认值为 0,所以我们需要对它进行初始化,此外为了能方便重置模型视图矩阵,我实现了 resetTransform,该方法在 initWithCoder 方法的最后被调用。

- (void)resetTransform
{
    _posX = 0.0;
    _posY = 0.0;
    _posZ = -5.5;
    
    _scaleZ = 1.0;
    _rotateX = 0.0;
    
    [self updateTransform];
}

2,添加上层控制代码

 打开 MainStoryboard.storyboard,在下方的 control view 中添加滑块与按钮,如图所示:


 然后修改 ViewController.h 为:

@interface ViewController : UIViewController

@property (nonatomic, strong) IBOutlet UIView * controlView;
@property (nonatomic, strong) IBOutlet OpenGLView * openGLView;

@property (nonatomic, strong) IBOutlet UISlider * posXSlider;
@property (nonatomic, strong) IBOutlet UISlider * posYSlider;
@property (nonatomic, strong) IBOutlet UISlider * posZSlider;
@property (nonatomic, strong) IBOutlet UISlider * scaleZSlider;
@property (nonatomic, strong) IBOutlet UISlider * rotateXSlider;

- (IBAction)xSliderValueChanged:(id)sender; 
- (IBAction)ySliderValueChanged:(id)sender; 
- (IBAction)ySliderValueChanged:(id)sender;

- (IBAction)scaleZSliderValueChanged:(id)sender; 
- (IBAction)rotateXSliderValueChanged:(id)sender;

- (IBAction)autoButtonClick:(id)sender;
- (IBAction)resetButtonClick:(id)sender;

@end

在 ViewController.m 中添加属性相关代码:

@synthesize posXSlider, posYSlider, posZSlider;
@synthesize scaleZSlider, rotateXSlider;

- (void)viewDidUnload
{
    [super viewDidUnload];
    
    [self.openGLView cleanup];
    self.openGLView = nil;
    
    self.posXSlider = nil;
    self.posYSlider = nil;
    self.posZSlider = nil;
    self.scaleZSlider = nil;
    self.rotateXSlider = nil;
    self.controlView = nil;
}

以及响应事件的方法:

- (IBAction)ySliderValueChanged:(id)sender
{
    UISlider * slider = (UISlider *)sender;
    float currentValue = [slider value];
    
    openGLView.posY = currentValue;
    
    NSLog(@" >> current y is %f", currentValue);
}

- (IBAction)zSliderValueChanged:(id)sender
{
    UISlider * slider = (UISlider *)sender;
    float currentValue = [slider value];
    
    openGLView.posZ = currentValue;
    
    NSLog(@" >> current z is %f", currentValue);
}

- (IBAction)scaleZSliderValueChanged:(id)sender
{
    UISlider * slider = (UISlider *)sender;
    float currentValue = [slider value];
    
    openGLView.scaleZ = currentValue;
    
    NSLog(@" >> current z scale is %f", currentValue);
}

- (IBAction)rotateXSliderValueChanged:(id)sender
{
    UISlider * slider = (UISlider *)sender;
    float currentValue = [slider value];
    
    openGLView.rotateX = currentValue;
    
    NSLog(@" >> current x rotation is %f", currentValue);   
}

- (IBAction)autoButtonClick:(id)sender
{
}

- (IBAction)resetButtonClick:(id)sender
{
}

上面的代码很简单,基本与平移 x 的代码类似,所以在这里也就不一一讲述了。然后回到 MainStoryboard.storyboard 中,使用拖拽技巧将相关属性和事件与控件关联起来。 

3,编译运行,滑动不同的滑块,体验下 3D 变换的效果。

 

六,自动旋转与重置

1,重置恢复默认状态

还记得在前面我提到有一个重置模型视图矩阵的方法么,如果想让物体恢复默认状态,只要调用此方法,再重新描绘即可。因此,resetButtonClick 实现如下:

- (void)resetControls
{
    [posXSlider setValue:self.openGLView.posX];
    [posYSlider setValue:self.openGLView.posY];
    [posZSlider setValue:self.openGLView.posZ];
    
    [scaleZSlider setValue:self.openGLView.scaleZ];
    [rotateXSlider setValue:self.openGLView.rotateX];
}

- (IBAction)resetButtonClick:(id)sender
{
    [openGLView resetTransform];
    [openGLView render];
    
    [self resetControls];
}

在 Tutorial02 教程中 render 方法是私有方法,在这里,需要把它修改为公开方法。resetControls 是用来设置控件的默认值,以保持模型矩阵与控件的相关值同步,记得在 viewDidLoad 中调用此函数。编译运行,无论你做了多么复杂的变换,只要按下 Reset 按钮,一切都恢复原样了。

2,自动旋转

下面来添加点好玩的,让物体自动绕 X 轴旋转。这通常是通过 timer 来实现的,但苹果为我们提供了更好的办法:CADisplayLink(其实它内部也是使用的 timer),它可以让我们的应用程序与屏幕的刷新率保持同步,每当屏幕刷新时,就会调用我们提供的回调函数。下面我们来使用它,在 OpenGLView.m 中的匿名 category 中添加成员变量:

@interface OpenGLView()
{
    CADisplayLink * _displayLink;
}

并添加回调函数声明:

- (void)displayLinkCallback:(CADisplayLink*)displayLink;

然后在下面的 @implemetion 中实现此回调,屏幕没刷新一次就让四棱锥绕 x 轴旋转一定的角度:

- (void)displayLinkCallback:(CADisplayLink*)displayLink
{
    self.rotateX += displayLink.duration * 90;
}

在 OpenGLView.h 中添加公开方法:

- (void)toggleDisplayLink;

然后在 OpenGLView.m 中实现之:

- (void)toggleDisplayLink
{
    if (_displayLink == nil) {
        _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkCallback:)];
        [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    }
    else {
        [_displayLink invalidate];
        [_displayLink removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        _displayLink = nil;
    }
}

在上面的代码中,我们实现了一个 toggle 开关方法,如果没有自动旋转,那么就启动自动旋转;如果已经在自动旋转了,那么就停止它。CADisplayLink 的使用很简单,创建一个对象,设置它的 target 和回调函数,然后将它加入 NSRunLoop 中开始运行;如果要停止它,首先调用 invalidate 方法,然后将它从 NSRunLoop 中移除。

最后,我们在按钮的响应方法中添加对 toggleDisplayLink 的调用:

- (IBAction)autoButtonClick:(id)sender
{
    [openGLView toggleDisplayLink];
    
    UIButton * button = (UIButton *)sender;
    NSString * text = button.titleLabel.text;
    if ([text isEqualToString:@"Auto"]) {
        [button setTitle: @"Stop" forState: UIControlStateNormal];
    }
    else {
        [button setTitle: @"Auto" forState: UIControlStateNormal];
    }
}

编译运行代码,点击 Auto 就能让四棱锥自动旋转了,再次点击就能让它停止自动旋转,很妙吧?

 

七,总结

在这一篇文章中,介绍了如何通过 3D 变换来实现平移,旋转和缩放,以更好地理解前文中介绍的理论知识;同时也实现了如何通过 UIControl 来控制 OpenGL View 中的物体;此外还详细介绍了描绘图元的模式以及顶点索引模式。在文章的最后,介绍了如何使用 CADisplayLink 来实现动画效果。

最后,四棱锥看起来有点丑陋,来个水立方怎么样?(长方体),这个任务就交给看官你了,相信你一定可以实现的。

 

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 17
    评论
第1章 新一代的王者——android概览 1 1.1 智能手机市场现状 1 1.1.1 五大智能手机操作系统 1 1.1.2 智能手机市场的新星 2 1.2 android平台的特点及未来的趋势 3 1.2.1 全新理念带来的体验风暴 3 1.2.2 中国手机市场的主导性作用 4 1.2.3 手机3d游戏和应用增长迅速 4 1.3 如何搭建android开发环境 4 1.3.1 sdk的安装及环境配置 5 1.3.2 eclipse集成开发环境的搭建 7 1.3.3 创建并启动模拟器 9 1.4 hello android应用程序的开发 11 1.4.1 第一个android应用程序 12 1.4.2 android应用程序的项目结构 14 1.4.3 android应用程序的调试 16 1.4.4 实际设备的联机调试 18 1.5 android应用程序运行的机制 19 1.5.1 应用程序的系统架构 19 .1.5.2 应用程序框架 20 1.5.3 android运行时 20 1.5.4 系统库 21 1.5.5 底层linux内核 21 1.6 本章小结 22 第2章 游戏开发相关android基础知识 23 2.1 游戏中的音效 23 2.1.1 游戏中的即时音效 23 2.1.2 即时音效的一个案例 24 2.1.3 背景音乐播放技术 27 2.1.4 简易音乐播放器的实现 29 2.2 简单数据的存储——preferences 33 2.2.1 preferences简介 33 2.2.2 preferences实现访问时间的记录 33 2.3 手机自带数据库——sqlite 34 2.3.1 初识sqlite 35 2.3.2 sqlite数据库的基本操作 35 2.3.3 sqlite数据库的简单案例 37 2.3.4 使用contentprovider组件共享数据 40 2.3.5 使用contentresolver获取分享数据 42 2.4 文件i/o 43 2.4.1 访问sd卡中的文件 44 2.4.2 访问手机中的文件夹 46 2.4.3 读取assets文件夹下的内容 48 2.5 2d动画的开发 50 2.5.1 surfaceview用法简介 50 2.5.2 使用surfaceview实现2d动画 50 2.6 socket网络通信 56 2.6.1 socket开发基本知识 56 2.6.2 服务器端 57 2.6.3 客户端 58 2.7 蓝牙通信 59 2.7.1 蓝牙通信的基本知识 60 2.7.2 聊天案例概览 60 2.7.3 聊天案例的开发过程 62 2.8 本章小结 75 第3章 初识opengl es 2.0 77 3.1 opengl es 2.0概览 77 3.1.1 opengl es 2.0简介 77 3.1.2 初识opengl es 2.0应用程序 80 3.2 着色器与渲染管线 89 3.2.1 opengl es 1.x的渲染管线 89 3.2.2 opengl es 2.0的渲染管线 94 3.2.3 opengl es中立体物体的构建 97 3.3 主流android手机gpu大pk 98 3.3.1 手机gpu四大家族对比 99 3.3.2 主流gpu的性能参数比较 103 3.4 本章小结 104 第4章 着色语言shading language 105 4.1 着色语言概述 105 4.2 着色语言基础 106 4.2.1 数据类型概述 106 4.2.2 数据类型的基本使用 110 4.2.3 运算符 112 4.2.4 类型转换 114 4.2.5 限定符 115 4.2.6 流程控制 119 4.2.7 函数的声明与使用 121 4.2.8 片元着色器中浮点变量精度的指定 122 4.2.9 程序的基本结构 123 4.3 特殊的内建变量 123 4.3.1 顶点着色器中的内建变量 124 4.3.2 片元着色器中的内建变量 124 4.4 着色语言的内置函数 125 4.4.1 角度转换与三角函数 126 4.4.2 指数函数 127 4.4.3 常见函数 127 4.4.4 几何函数 130 4.4.5 矩阵函数 132 4.4.6 向量关系函数 133 4.4.7 纹理采样函数 134 4.4.8 微分函数 135 4.5 本章小结 135 第5章 投影及各种变换 136 5.1 摄像机的设置 136 5.2 两种投影方式 137 5.2.1 正交投影 137 5.2.2 透视投影 145 5.3 各种变换 148 5.3.1 基本变换的相关数学知识 148 5.3.2 平移变换 148 5.3.3 旋转变换 152 5.3.4 缩放变换 153 5.3.5 基本变换的实质 155 5.4 绘制方式 156 5.4.1 各种绘制方式概览 156 5.4.2 点与线段绘制方式 157 5.4.3 三角形条带与扇面绘制方式 159 5.4.4 顶点法与索引法 165 5.5 设置合理的视角 167 5.6 卷绕和背面剪裁 173 5.6.1 基本知识 173 5.6.2 一个简单的案例 174 5.7 本章小结 176 第6章 光照 177 6.1 曲面物体的构建 177 6.1.1 球体构建的基本原理 177 6.2.2 案例效果概览 178 6.2.3 开发步骤 179 6.2 基本光照效果 182 6.2.1 光照的基本模型 182 6.2.2 环境光 183 6.2.3 散射光 185 6.2.4 镜面光 190 6.2.5 三种光照通道的合成 194 6.3 定位光与定向光 196 6.4 点法向量和面法向量 199 6.5 光照的每顶点计算与每片元计算 202 6.6 本章小结 204 第7章 纹理映射 205 7.1 初识纹理映射 205 7.1.1 基本原理 205 7.1.2 纹理映射的简单案例 206 7.2 纹理拉伸 212 7.2.1 两种拉伸方式概览 212 7.2.2 不同拉伸方式的案例 214 7.3 纹理采样 217 7.3.1 纹理采样概述 217 7.3.2 最近点采样 218 7.3.3 线性纹理采样 219 7.3.4 min与mag采样 220 7.3.5 不同纹理采样方式的案例 221 7.4 mipmap纹理技术 226 7.5 多重纹理与过程纹理 227 7.5.1 案例概览 227 7.5.2 将2d纹理映射到球面上的策略 228 7.5.3 案例的场景结构 229 7.5.4 开发过程 230 7.6 本章小结 238 第8章 3d基本形状的构建 239 8.1 圆柱体 239 8.1.1 顶点原始位置的生成 239 8.1.2 案例的开发 241 8.2 圆锥体 244 8.2.1 顶点原始位置的生成 244 8.2.2 案例的开发 246 8.3 圆环体 248 8.3.1 顶点原始位置的生成 248 8.3.2 案例的开发 249 8.4 螺旋管 251 8.4.1 顶点原始位置的生成 252 8.4.2 案例的开发 252 8.5 几何球 253 8.5.1 顶点原始位置的生成 254 8.5.2 案例的开发 255 8.6 足球碳分子模型的搭建 262 8.6.1 搭建的基本原理 262 8.6.2 案例的开发 264 8.7 贝塞尔曲线及旋转面 270 8.7.1 三维旋转曲面的生成 270 8.7.2 贝塞尔曲线 270 8.7.3 bezier曲线生成工具 272 8.7.4 印度古典建筑场景的开发 274 8.8 本章小结 276 第9章 3d模型加载 277 9.1 obj模型文件概览 277 9.1.1 obj文件的格式 277 9.1.2 用3dmax设计3d模型 278 9.2 加载obj文件 279 9.2.1 加载仅有顶点坐标与面数据的obj文件 279 9.2.2 加载后自动计算面法向量 283 9.2.3 加载后自动计算平均法向量 286 9.2.4 加载纹理坐标 289 9.3 本章小结 292 第10章 混合与雾 293 10.1 混合技术 293 10.1.1 混合基本知识 293 10.1.2 源因子和目标因子 294 10.1.3 简单混合效果案例 295 10.2 地月系云层效果的实现 297 10.3 雾 300 10.3.1 雾的原理与优势 300 10.3.2 雾的简单实现 301 10.4 本章小结 304 第11章 常用3d开发技巧 305 11.1 标志板 305 11.1.1 案例效果与基本原理 305 11.1.2 开发步骤 306 11.2 灰度图地形 310 11.2.1 基本原理 311 11.2.2 普通灰度图地形 311 11.2.3 过程纹理地形 314 11.2.4 mipmap地形 317 11.3 天空盒与天空穹 318 11.3.1 天空盒 318 11.3.2 天空穹 320 11.3.3 天空盒与天空穹的使用技巧 321 11.4 镜像技术 322 11.4.1 镜像基本原理 322 11.4.2 基本效果案例 322 11.4.3 升级效果案例 325 11.5 动态文本输出 327 11.5.1 案例效果与基本原理 327 11.5.2 具体开发步骤 328 11.6 非真实感绘制 330 11.6.1 案例效果与基本原理 330 11.6.2 具体开发步骤 331 11.7 本章小结 332 第12章 几种剪裁与测试 333 12.1 剪裁测试 333 12.1.1 基本原理与核心代码 333 12.1.2 一个主次视角的简单案例 334 12.2 alpha测试 335 12.2.1 alpha测试基本原理 335 12.2.2 一个椭圆窗口的案例 335 12.3 模板测试 337 12.3.1 基本原理 337 12.3.2 一个简单的案例 340 12.4 任意剪裁平面 341 12.4.1 基本原理 341 12.4.2 茶壶被任意平面剪裁的案例 342 12.5 本章小结 344 第13章 顶点着色器的妙用 345 13.1 飘扬的旗帜 345 13.1.1 基本原理 345 13.1.2 开发步骤 346 13.2 扭动的软糖 349 13.2.1 基本原理 349 13.2.2 开发步骤 350 13.3 风吹椰林场景的开发 351 13.3.1 椰子树随风摇摆的基本原理 351 13.3.2 开发步骤 352 13.4 展翅飞翔的雄鹰 356 13.4.1 基本原理 356 13.4.2 开发步骤 357 13.5 二维扭曲 359 13.5.1 基本原理 359 13.5.2 开发步骤 360 13.6 opengl es 1.x与opengl es 2.0实现方案的对比 363 13.7 本章小结 364 第14章 片元着色器的妙用 365 14.1 程序纹理技术 365 14.1.1 砖块着色器 365 14.1.2 沙滩球着色器 367 14.2 数字图像处理 368 14.2.1 卷积的基本知识 369 14.2.2 平滑过滤 369 14.2.3 边缘检测 371 14.2.4 锐化处理 372 14.2.5 浮雕效果 373 14.2.6 图像渐变 374 14.3 分形着色器 375 14.3.1 曼德布罗集简介 375 14.3.2 曼德布罗集着色器的实现 376 14.3.3 将曼德布罗集纹理应用到实际物体上 378 14.3.4 茱莉亚集着色器的实现 379 14.4 本章小结 380 第15章 真实光学环境的模拟 381 15.1 投影贴图 381 15.1.1 案例效果与基本原理 381 15.1.2 开发步骤 382 15.2 反射环境模拟 385 15.2.1 案例效果与基本原理 385 15.2.2 开发步骤 386 15.3 折射环境模拟 388 15.3.1 案例效果与基本原理 388 15.3.2 开发步骤 390 15.4 色散效果的模拟 391 15.4.1 案例效果与基本原理 391 15.4.2 开发步骤 392 15.5 菲涅尔效果的模拟 393 15.5.1 案例效果与基本原理 393 15.5.2 开发步骤 394 15.6 凹凸映射 395 15.6.1 案例效果与基本原理 395 15.6.2 法向量纹理图的生成 396 15.6.3 案例的开发 399 15.7 平面阴影 404 15.7.1 案例效果与基本原理 405 15.7.2 开发步骤 406 15.8 阴影映射 409 15.8.1 案例效果与基本原理 409 15.8.2 距离纹理图的生成 411 15.8.3 阴影场景的绘制 417 15.9 光线跟踪 419 15.9.1 案例效果与基本原理 419 15.9.2 开发步骤 423 15.10 本章小结 436 第16章 游戏开发中的物理学 437 16.1 碰撞检测基本技术 437 16.1.1 aabb包围盒的基本原理 437 16.1.2 aabb包围盒的计算 438 16.1.3 aabb包围盒的碰撞检测 440 16.1.4 一个aabb包围盒的案例 442 16.1.5 旋转后的aabb包围盒 444 16.1.6 aabb包围盒的使用要点 448 16.1.7 obb包围盒 448 16.2 穿透效应 449 16.2.1 案例的运行效果与基本原理 449 16.2.2 具体开发步骤 450 16.3 粒子系统 450 16.3.1 案例运行效果与基本原理 451 16.3.2 cpu版案例的开发 452 16.3.3 gpu版案例开发步骤 453 16.4 弹簧质点模型 455 16.4.1 案例运行效果与基本原理 455 16.4.2 具体开发步骤 457 16.5 本章小结 462 第17章 游戏的心脏——物理引擎 463 17.1 物理引擎很重要 463 17.1.1 什么是物理引擎 463 17.1.2 常见的物理引擎 463 17.2 jbullet物理引擎 466 17.2.1 基本的物理学概念 466 17.2.2 jbullet中常用类的介绍 468 17.3 箱子相互碰撞的案例 475 17.3.1 案例运行效果及准备工作 476 17.3.2 案例的基本框架结构 476 17.3.3 常量类——constant 477 17.3.4 3d场景渲染类——mysurfaceview 478 17.3.5 水平地面——texfloor类 480 17.3.6 箱子——texcube类 481 17.4 复合碰撞形状的使用 483 17.4.1 案例运行效果 483 17.4.2 立方体圆柱复合形状——cubecylinder类 483 17.5 凹凸地形的案例 486 17.5.1 案例运行效果 486 17.5.2 地形类——landform 486 17.6 任意形状物体的碰撞 488 17.6.1 案例运行效果 488 17.6.2 加载物体类——loadedobjectvertexnormal 488 17.6.3 加载物体刚体类——loadrigidbody 490 17.7 铰链关节 491 17.7.1 铰链关节的基本知识 491 17.7.2 案例的运行效果 492 17.7.3 铰链关节旋转角速度的计算 493 17.7.4 3d界面渲染类——mysurfaceview 494 17.8 滑动关节 496 17.8.1 滑动关节的基本知识 496 17.8.2 案例效果图 497 17.8.3 3d界面渲染类——mysurfaceview 498 17.9 六自由度关节 502 17.9.1 六自由度关节的基本知识 502 17.9.2 案例的运行效果 503 17.9.3 人偶类——doll 503 17.9.4 拾取时采用的点对点关节 505 17.10 本章小结 509 第18章 传感器应用的开发 510 18.1 基本的开发流程 510 18.2 加速度传感器 512 18.2.1 加速度传感器简介 513 18.2.2 案例的开发 514 18.3 磁场传感器 514 18.3.1 磁场传感器简介 514 18.3.2 案例的开发 514 18.4 光传感器 516 18.4.1 光传感器简介 516 18.4.2 案例的开发 516 18.5 温度传感器 518 18.5.1 温度传感器简介 518 18.5.2 案例的开发 518 18.6 接近传感器 519 18.6.1 接近传感器简介 519 18.6.2 案例的开发 520 18.7 姿态传感器 521 18.7.1 姿态传感器简介 521 18.7.2 案例的开发 522 18.8 本章小结 528 第19章 游戏开发小贴士 529 19.1 3d拾取技术 529 19.1.1 案例效果与基本原理 529 19.1.2 开发步骤 531 19.2 多点触控 537 19.2.1 案例效果与基本原理 537 19.2.2 开发步骤 538 19.3 多键监听 541 19.3.1 案例效果与基本原理 541 19.3.2 开发步骤 542 19.4 本章小结 544 第20章 bn赛艇 545 20.1 游戏背景及功能概述 545 20.1.1 背景概述 545 20.1.2 功能介绍 545 20.2 游戏的策划及准备工作 547 20.2.1 游戏的策划 547 20.2.2 android平台下游戏的准备工作 548 20.3 游戏的架构 552 20.3.1 各个类简要介绍 553 20.3.2 游戏框架简介 558 20.4 主控制类myactivity 559 20.5 2d界面相关类 563 20.5.1 欢迎界面类welcomeview 563 20.5.2 2d界面父类mysfview 565 20.5.3 主菜单类menuview 565 20.5.4 2d界面绘制类viewfordraw 566 20.5.5 数据库工具类dbutil 568 20.5.6 android系统版本对话框androidversiondialog 570 20.6 选船界面相关类 570 20.6.1 着色器管理类shadermanager 571 20.6.2 围墙类colorlightrect 571 20.6.3 选船房间类housefordraw 573 20.6.4 展台类displaystation 575 20.6.5 赛艇类boat 576 20.6.6 选船界面xcsurfaceview 576 20.7 游戏界面相关类 582 20.7.1 进度条类process 583 20.7.2 3d物体父类bndrawer 584 20.7.3 3d物体控制类tdobjectforcontrol 584 20.7.4 赛艇类boat 585 20.7.5 可碰撞物体父类kzbjdrawer 586 20.7.6 可碰撞物体控制类kzbjforcontr
OpenGL是一种开放源代码的图形库,用于开发二维和三维图形应用程序。其支持光照、平移旋转缩放等功能。 光照是在OpenGL中实现逼真和真实感的一个重要方面。通过对物体表面的光照进行计算和模拟,可以模拟出光线在真实世界中的表现。OpenGL提供了多种光照模型和光源类型,如平行光照、点光源和聚光灯等。通过设置光源的属性,如位置、颜色和强度,可以控制光照的效果。同时,还可以设置材质的属性,如漫反射、镜面反射和环境光反射等,以使物体表面具有不同的反射特性。 平移旋转缩放是控制物体在OpenGL中位置、方向和大小的重要操作。通过平移(Translation),可以改变物体的位置。通过旋转(Rotation),可以改变物体的方向。通过缩放(Scaling),可以改变物体的大小。这些操作可以通过设置模型视图矩阵来实现,将物体的顶点坐标进行相应的变换平移旋转缩放都可以相对于世界坐标系进行,也可以相对于物体自身坐标系进行。 在OpenGL中,可以通过矩阵操作来实现平移旋转缩放平移可以通过将物体的位置矩阵与一个平移矩阵相乘来实现。旋转可以通过将物体的方向矩阵与一个旋转矩阵相乘来实现。缩放可以通过将物体的大小矩阵与一个缩放矩阵相乘来实现。通过改变这些矩阵的数值,可以控制物体在空间中的位置、方向和大小。 总结来说,OpenGL提供了一系列的函数和接口,可以实现光照、平移旋转缩放等操作,使得开发者可以自由控制物体的表现和行为。这些功能在图形应用程序中非常重要,可以帮助开发者创建出逼真和动态的图形效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值