<3>OpenGL入门知识介绍

Opengl最大的特点莫过于坚持做到在加入新特性的同时尽量少地与旧代码发生冲突。
1.API特性
(1)数据类型
GL开头表示OpengL,函数后面使它们的最小位宽和相关描述。
注意OpenGL并没有对指针和数组做特殊的考虑,我们可以像下面这样声明一个包含10个GLshort变量的数组:

GLshort shorts[10]

而下面这行代码则声明了一个长度为10的指向GLdouble类型变量的指针数组。

GLdouble * doubles[10];

(2)OpenGL错误
OpenGL在内部保留了一组错误标志,其中每一个标志都代表一种不同类型的错误。当一个错误发生的时候,与这个错误相应的状态就会被设置。为了观察哪些标志被设置,可以调用:

Glenum glGetError(void);

该函数被调用的时候,这个值随后被删除。然后在glGetError再次被调用的时候将返回一个错误标志或者GL_NO _ERROR。

GL_INVALID_ENUM:枚举参数超出范围。
GL_INVALID_VALUE:数值参数超出范围。
GL_INVALID_OPERATION:在当前状态操作非法。
GL_OUT_OF_MEMORY:没有足够的内存执行命令。
GL_NO_ERROR:没有错误出现。

(3)确认版本

const GLubyte* glGetString(GLenum name);

这个函数返回一个静态的字符串,描述GL函数库中所请求的信息。

(4)使用glHint获取线索
gHint函数允许我们指定偏重视觉质量还是速度,以适应各种不同类型的操作需求。

void glHint(GLnum target, GLenum mode);

target: 希望进行修改的行为类型。mode参数告诉OpenGL我们最为关心的是什么。

(5)Opengl状态机
我们把这类变量的集合成为管线的状态,状态机是一个抽象的模型,表示一组状态变量的集合。每个状态变量可以有不同的值,或者只能可以打开或者关闭。
为了打开这类型的状态变量,可以使用下面这个Opengl函数:

void glEnable(GLenum capability);

可以使用下面这个对应的函数,把这些变量的状态设置为关闭。

void glDisable(GLenum capability);

如果希望对一个状态变量进行测试,以判断它是否已经被打开,OpenGL还提供了一种方便的机制:

Glboolean glIsEnabled(GLenum capability);

但是并不是所有的状态变量都只是简单的打开和关闭。许多OpenGL函数专门用于设置变量值。所以需要对其进行查询的话需要以下函数:

void glGetBolleanv(GLenum pname,GLboolean *params);
void glGetDoublev(GLenum pname,GLdouble *params);
void glGetFloatv(GLenum pname,GLfloat *params);
void glGetIntegerv(GLenum pname,GLinteger *params);

以上函数都会返回单个值,或者返回一个数组把一些值存入我们指定的地址当中。

Opengl示例程序:来说明基础的框架。


//Opengl所需要包含的引用
#pragma comment(lib,"GLTools.lib")
#include <GLTools.h>
#include <GLShaderManager.h>
#include <GL\freeglut.h>

GLBatch triangleBatch;
//使用一些简单的着色器。可以用着色器管理器进行管理。
GLShaderManager shaderManager;


//由于在不同的环境下窗口大小变化的检测和处理方式不同。
//使用glutReshapeFunc注册一个回调,供glut库在窗口维度改变的时候使用。
void ChangeSize(int w, int h)
{
    glViewport(0, 0, w, h);
    // 四个参数:x,y,width,height。

}


//设置当前的渲染环境
void SetupRC()
{
    // 用来进行窗口清除的颜色。
    glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
    //着色器管理器需要编译和链接他自己的着色器。
    shaderManager.InitializeStockShaders();

    // 其中一个简单的GLToole封装类会将三角形顶点批次进行封装。
    GLfloat vVerts[] = { -0.5f, 0.0f, 0.0f,
        0.5f, 0.0f, 0.0f,
        0.0f, 0.5f, 0.0f };
    //建立了一个三角形批次,仅仅包含三个顶点。
    triangleBatch.Begin(GL_TRIANGLES, 3);
    triangleBatch.CopyVertexData3f(vVerts);
    triangleBatch.End();
}



//真正的渲染。
void RenderScene(void)
{
    // 清除一个或者一组特定的缓冲区。
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    //设置一组浮点表示颜色,并且将它传递到存储着色器GLT_SHADER_IDENTITY。
    GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
    triangleBatch.Draw();
    //前面的GLUT_DOUBLE
    // 指定要一个双缓冲区渲染环境,意味在后台缓冲区进行渲染,然后在结束的时候交换到前台。  
    //这种形式能够防止观察者看到可能伴随着动画帧与动画帧之间闪烁的渲染过程。
    glutSwapBuffers();
}


///////////////////////////////////////////////////////////////////////////////  
// Main entry point for GLUT based programs  
int main(int argc, char* argv[])
{
    gltSetWorkingDirectory(argv[0]);//设置当前工作目录。非必要。默认就是程序可执行程序相同的目录。

    glutInit(&argc, argv);//传输命令行参数并且初始化GLUT库。
    //创建窗口的时候需要使用哪种类型的显示模式。
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    //GLUT_DOUBLE:双缓冲窗口,绘图命令实际上是在离屏缓冲区执行的,然后迅速转换成窗口视图。
    //GLUT_DEPTH:将一个深度缓冲区分配为显示的一部分。这种方式用来生成动画效果。
    glutInitWindowSize(800, 600);//设置窗口大小

    glutCreateWindow("Triangle");//设置窗口的表头。


    //GLUT内部运行一个本地消息循环,拦截适当的信息。然后调用我们为不同时间注册的回调函数。
    //这里必须为改变窗口大小设置一个回调函数。
    glutReshapeFunc(ChangeSize);
    //注册一个函数以包含OPENGL渲染代码。
    glutDisplayFunc(RenderScene);


    //以下代码需要解决两件事情:初始化GLEW库。重新调用GLEW初始化OPENGL驱动程序。
    //以确保Opengl的API对我们完全可用。
    //还要检查确定驱动程序的初始化过程中有没有出现任何问题。
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }

    SetupRC();//这是一个运行中的Opengl状态机的句柄。在任何Opengl函数起作用
    //前必须创建一个渲染环境。

    glutMainLoop();//开始主消息循环并且结束main函数。
    return 0;
}

针对上面的程序,继续修改一些位置,完成可以使用上下左右键来完成对一个正方体的控制。并且控制其碰撞检测。同时总是更新其点的位置。

//Opengl所需要包含的引用
#pragma comment(lib,"GLTools.lib")
#include <GLTools.h>
#include <GLShaderManager.h>
#include <GL\freeglut.h>

GLBatch squareBatch;
//使用一些简单的着色器。可以用着色器管理器进行管理。
GLShaderManager shaderManager;

//注意公开声明当前点。
GLfloat blockSize = 0.1f;
GLfloat vVerts[] =
{ -blockSize, -blockSize, 0.0f,
blockSize, -blockSize, 0.0f,
blockSize,  blockSize, 0.0f,
-blockSize,  blockSize, 0.0f };


//由于在不同的环境下窗口大小变化的检测和处理方式不同。
//使用glutReshapeFunc注册一个回调,供glut库在窗口维度改变的时候使用。
void ChangeSize(int w, int h)
{
    glViewport(0, 0, w, h);
    // 四个参数:x,y,width,height。

}


//设置当前的渲染环境
void SetupRC()
{
    // 用来进行窗口清除的颜色。
    glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
    //着色器管理器需要编译和链接他自己的着色器。
    shaderManager.InitializeStockShaders();


    //建立了一个正方形批次。包含四个点。
    squareBatch.Begin(GL_TRIANGLE_FAN, 4);
    squareBatch.CopyVertexData3f(vVerts);
    squareBatch.End();
}



//真正的渲染。
void RenderScene(void)
{
    // 清除一个或者一组特定的缓冲区。
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    //设置一组浮点表示颜色,并且将它传递到存储着色器GLT_SHADER_IDENTITY。
    GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
    squareBatch.Draw();
    //前面的GLUT_DOUBLE
    // 指定要一个双缓冲区渲染环境,意味在后台缓冲区进行渲染,然后在结束的时候交换到前台。  
    //这种形式能够防止观察者看到可能伴随着动画帧与动画帧之间闪烁的渲染过程。
    glutSwapBuffers();
}

//用箭头控制操纵正方形在屏幕范围移动
void SpecialKeys(int key, int x, int y)
{
    GLfloat stepSize = 0.025f;

    GLfloat blockX = vVerts[0];
    GLfloat blockY = vVerts[7];

    //基本移动方式
    if (key == GLUT_KEY_UP)
    {
        blockY += stepSize;
    }
    if (key == GLUT_KEY_DOWN)
    {
        blockY -= stepSize;
    }
    if (key==GLUT_KEY_LEFT)
    {
        blockX -= stepSize;
    }
    if (key == GLUT_KEY_RIGHT)
    {
        blockX += stepSize;
    }

    //碰撞检测,注意其正方形点的设置,所以设置成 1.0f - blockSize * 2
    if (blockX < -1.0f) blockX = -1.0f;
    if (blockX > (1.0f - blockSize * 2)) blockX = 1.0f - blockSize * 2;
    if (blockY < -1.0f + blockSize * 2)  blockY = -1.0f + blockSize * 2;
    if (blockY > 1.0f) blockY = 1.0f;

    //对正方体点的重新计算。
    //注意其中的第三个坐标为z轴坐标
    //并没有什么用,所以忽略掉。
    vVerts[0] = blockX;
    vVerts[1] = blockY - blockSize * 2;

    vVerts[3] = blockX + blockSize * 2;
    vVerts[4] = blockY - blockSize * 2;

    vVerts[6] = blockX + blockSize * 2;
    vVerts[7] = blockY;

    vVerts[9] = blockX;
    vVerts[10] = blockY;

    //注意该函数调用两次。
    squareBatch.CopyVertexData3f(vVerts);

    glutPostRedisplay();

}

注意最后一个SpecialKey函数的最后一行当中的glutPostRedisplay函数。
默认情况下,在窗口创建,改变大小或者需要重新绘制的时候,GLUT通过RenderScene更新窗口。只要窗口最小化,恢复,最大化,覆盖或者重新显示等变化,就会产生更新。或者可以使用glutPostRedisplay函数手动更新。能够对其进行手动渲染。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值