NeHe OpenGL教程 第九课 在3D空间中移动位图

 

欢迎来到第九课。到现在你应该已经对OpenGL很了解了。你已经学会了设置一个OpenGL窗口和当使用光照和混合的时候给一个旋转的物体进行纹理映射的所有东西。下面将是第一课高级课程。你将会学到下面的内容:以3D的方式在屏幕里移动位图,取出位图周围的黑色像素点(使用混合),为一个黑白纹理添加颜色,最后你将学会如何通过把不同颜色的纹理混合在一起来创建一个多彩的,有简单动画效果的物体。

在这一课中,我们将修改第一课中的代码。我们首先在程序的开始部分添加一些新的变量。我将重写这部分的全部代码,以便你可以清楚地看到变化的部分。

#include <windows.h>            // Windows头文件
#include <stdio.h>                  // 标准输入/输出头文件

#include <gl\gl.h>                   // OpenGL32 库头文件
#include <gl\glu.h>                 // GLu32 库头文件
#include <gl\glaux.h>            // The GLaux 库头文件
HDC hDC=NULL;                  // 私有GDI 设备上下文
HGLRC hRC=NULL;             // 固定的渲染上下文
HWND hWnd=NULL;            // 持有我们的窗口句柄

HINSTANCE hInstance;       // 应用程序实例

bool keys[256];                    // 键盘事件使用的数组

bool active=TRUE;               // 窗口活动标签,默认设置为TRUE

bool fullscreen=TRUE;         // 全屏标签,默认设置为全屏


下面的代码是新添加的。twinkle 和 tp都是BOOL型变量,只能取TRUE或FALSE值。twinkle将用来监视闪烁效果是否启用。tp用来检查'T'键是按下还是抬起。(按下时tp=TRUE,抬起时tp=FALSE)

BOOL twinkle; // 闪烁的星星

BOOL tp; // 'T' 键是否按下

num变量将用来监视有多少星星绘制到屏幕上。它被定义为一个常量。意味着在代码中它将不会被改变。我们把它定义为常量的原因是你不能重定义一个数组。因此如果我们设置一个50个星星的数组,我们想要在代码中增加num到51,数组不能增长到51,因此会产生一个错误。你只可以在这行代码中把num的值改为你想要的数字。不要尝试在代码中修改它,否则将会出错。

const num=50; // 绘制星星的数量

现在我们创建一个结构体。结构体这个词听起来很吓人,但实际上并不是那样。一个结构体是一组简单的数据(例如,变量)代表一个更大的相似的组。翻译过来就是:我们知道我们在跟踪星星。下面代码的第七行就是stars;我们知道每一个星星有三个颜色值,所有的这些值都是整型值。第三行代码int r,g,b定义了三个整型值。一个代表红色(r),一个代表蓝色(b),一个代表绿色(g)。我们知道每一个星星离屏幕中心的距离都是不同的,可以沿中心旋转360度。注意第四行代码,我们设置了一个dist的浮点型变量。它将监视星星距离中心的距离。第五行代码设置了一个angle的浮点型变量。它将监视星星的旋转角度。

所以现在我们用这个结构体来描述一个屏幕上的星星的颜色,距离和角度。很不幸我们有很多星星需要监视。我们创建一个叫做star的数组,代替创建50个红色值,50个蓝色值,50个绿色值,50个距离,50个角度。star数组中的每一个元素保存我们stars结构体的所有信息。我们在第八行创建这个star数组。如果我们分解第八行代码

stars star[num]。我们能够看到。数组元素的类型是stars。stars是一个结构体。所以这个数组中的元素可以保存所有结构体中的信息。数组的名字是star。数组的大小是num。因为num = 50,我们现在有了一个叫做star的数组。我们的数组存储stars结构体元素。相对于用分离的变量监视每一个星星,这种方法方便了很多。比较愚蠢的是,我们不同通过改变num的值来增加移动星星的数量。

typedef struct      // 为Star创建一个结构体
{
int r, g, b;     // Stars 的颜色
GLfloat dist; // Stars 距离屏幕中心的距离

GLfloat angle; // Stars 当前的旋转角度

}
stars; // 结构体的名字是Stars
stars star[num];    // 创建一个stars结构体的数组star

下面我们设置星星离观察者的距离(zoom),我们观察星星的角度(tilt)。我们定义一个叫做spin的变量来让闪烁的星星在z轴上旋转,让它们看起来像在自己的当前位置旋转一样。loop变量是我们在程序中绘制所有50个星星时使用的,texture[1]用来存储一个我们加载进来的黑白纹理。如果你想用多个纹理,可以把1改为你想要使用的纹理的数目。

GLfloat zoom=-15.0f;         // 观察者距离星星的距离

GLfloat tilt=90.0f;               // 倾斜视图的角度

GLfloat spin;                      // 旋转闪烁的星星

GLuint loop;                       // 通用的循环变量
GLuint texture[1];               // 存储一个纹理

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // 声明WndProc

紧接着上面这部分代码,我们添加加载我们纹理的代码。这部分代码我不会解释的很详细。它和我们在6,7,8课中使用的加载纹理的代码是一样的。我们这次加载的位图叫做star.bmp。我们使用glGenTextures(1, &texture[0])产生唯一的一个纹理。纹理我们采用线性过滤。

AUX_RGBImageRec *LoadBMP(char *Filename) // 加载一个位图图像

{
FILE *File=NULL;     // 文件句柄
if (!Filename)      // 确认文件的名字已经获得

{
return NULL;      // 如果没有文件名字,返回NULL
}
File=fopen(Filename,"r"); // 检查文件是否存在

if (File) // 文件是否存在

{
fclose(File); // 关闭文件句柄
return auxDIBImageLoad(Filename); // 加载位图,返回一个指针

}
return NULL; // 如果加载失败,返回NULL
}


下面是加载位图部分的代码(调用上面的代码),然后把它转换成纹理。Status变量用来监视纹理是否加载和创建成功。

int LoadGLTextures() // 加载bitmap,然后把它转换成纹理
{
int Status=FALSE; // Status 标识位
AUX_RGBImageRec *TextureImage[1]; // 为纹理创建存储空间
memset(TextureImage,0,sizeof(void *)*1); // 设置指针为NULL
// 加载bitmap,检查是否出错,如果bitmap没有找到,退出
if (TextureImage[0]=LoadBMP("Data/Star.bmp"))
{
Status=TRUE; // Status 设置为 TRUE

glGenTextures(1, &texture[0]); // 创建一个纹理

// 创建Linear 过滤器纹理
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB,
GL_UNSIGNED_BYTE, TextureImage[0]->data);
}
if (TextureImage[0]) // 如果纹理存在

{
if (TextureImage[0]->data) // 如果纹理图像存在 
{
free(TextureImage[0]->data); // 释放纹理图像内存 
}
free(TextureImage[0]); // 释放图像结构体 
}
return Status; // 返回Status 变量
}



 

 

 

 

 

未完待续!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值