正方形渲染.png
本章的主要内容:
- 固定着色器下渲染一个正方形
- 用户键盘可操作正方形移动的2种方法
- 坐标更新
- 矩阵
关于环境搭建可参考上一篇文章: OpenGL 环境搭建
一、正方形的渲染
正方形的渲染流程和上一章三角形的渲染流程基本是一样的,包括环境搭建、初始化准备工作、设置数据及连接方式、渲染几个过程,下面是渲染流程图:
正方形渲染.png
正方形与三角形渲染的不同点:
- 数据不同
正方形有四个顶点数据
GLfloat blockSize = 0.1f;
GLfloat vVerts[] = {
-blockSize,-blockSize,0.0,
blockSize,-blockSize,0.0,
blockSize, blockSize,0.0,
-blockSize, blockSize,0.0,
};
- 建立连接方式不同
triangleBatch.Begin(GL_TRIANGLE_FAN, 4);
三角形的连接方式为 GL_TRIANGLES, 正方形则是 GL_TRIANGLE_FAN,另外 OpenGL 还有如下几个基本连接方式,可自行尝试:
GL_POINTS 每个顶点在屏幕上都是单独点
GL_LINES 每一对顶点定义一个线段
GL_LINE_STRIP 一个从第一个顶点依次经过每一个后续顶点而绘制的线条
GL_LINE_LOOP 和GL_LINE_STRIP相同,但是最后一个顶点和第一个顶点连接起来了
GL_TRIANGLES 每3个顶点定义一个新的三角形
GL_TRIANGLE_STRIP 共用一个条带(strip)上的顶点的一组三角形
GL_TRIANGLE_FAN 以一个圆点为中心呈扇形排列,共用相邻顶点的一组三角形
整体代码如下:
#include "GLShaderManager.h"
#include "GLTools.h"
#include <GLUT/GLUT.h>
GLShaderManager shaderManager;
GLBatch triangleBatch;
GLfloat blockSize = 0.1f;
GLfloat vVerts[] = {
-blockSize,-blockSize,0.0,
blockSize,-blockSize,0.0,
blockSize, blockSize,0.0,
-blockSize, blockSize,0.0,
};
void changeSize (int w,int h) {
glViewport(0, 0, w, h);
}
void RenderScene (void) {
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
GLfloat vRed[] = {0.0,1.0,0.0,1.0};
shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);
triangleBatch.Draw();
glutSwapBuffers();
}
void setupRC() {
glClearColor(0.8, 0.2, 0.5, 1.0);
shaderManager.InitializeStockShaders();
triangleBatch.Begin(GL_TRIANGLE_FAN, 4);
triangleBatch.CopyVertexData3f(vVerts);
triangleBatch.End();
}
int main(int argc, char * argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
glutInitWindowSize(500, 500);
glutCreateWindow("正方形");
glutReshapeFunc(changeSize);
glutDisplayFunc(RenderScene);
GLenum status = glewInit();
if (GLEW_OK != status) {
return 1;
}
setupRC();
glutMainLoop();
return 0;
}
二、键盘操作移动正方形
如果让正方形动起来,就需要用在准备工作里面新注册一个特殊函数,通过键盘上下左右来控制移动。
glutSpecialFunc()
在准备工作里面注册该特殊函数,添加回调,可以在操作键盘的时候进行回调。
glutSpecialFunc(SpecialKeys);
整体操作流程如下:
键盘移动正方形.png
操作键盘上下左右时回调方法 SpecialKeys(int key, int x, int y),具体的实现有两种方式:
- 坐标点更新方式
以正方形的一个点为坐标点,这个点移动后,跟新其它三个点坐标,如下图所示:
正方形坐标移动.png
以 B 点为起始点,设定坐标为 (blockX, blockY),B 点移动后,更新其它三个点坐标,代码实现如下:
void SpecialKeys (int key, int x, int y){
GLfloat stepSize = 0.025f;
GLfloat blockX = vVerts[3];
GLfloat blockY = vVerts[4];
//点击上下左右移动步数坐标计算
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;
}
//防止正方形移动出屏幕
if (blockX > 1.0) {
blockX = 1.0f;
}
if (blockX < -1.0 + blockSize*2) {
blockX = -1.0 + blockSize*2;
}
if (blockY < -1.0) {
blockY = -1.0f;
}
if (blockY > 1.0 - blockSize*2 ) {
blockY = 1.0 - blockSize*2;
}
//根据B点坐标,计算ACD坐标
vVerts[0] = blockX - blockSize * 2;
vVerts[1] = blockY;
printf("开始A坐标-(%f,%f)",vVerts[0],vVerts[1]);
vVerts[3] = blockX;
vVerts[4] = blockY;
printf("开始B坐标-(%f,%f)",vVerts[3],vVerts[4]);
vVerts[6] = blockX;
vVerts[7] = blockY + blockSize * 2;
printf("开始C坐标-(%f,%f)",vVerts[6],vVerts[7]);
vVerts[9] = blockX - blockSize * 2;
vVerts[10] = blockY + blockSize * 2;
printf("开始D坐标-(%f,%f)",vVerts[9],vVerts[10]);
//切记 切记 移动后重新copy数据到容器内!!!!
triangleBatch.CopyVertexData3f(vVerts);
glutPostRedisplay();
}
切记:获取到新坐标后,需要重新拷贝数据到批次类容器,然后调起函数重新渲染。
这是四边形,如果是更多坐标点的话,那代码要长好多,下面就提供更便捷的方式矩阵。
- 矩阵方式
设定中心点坐标为 (xPos, yPos) ,xPos = 0.0f, yPos = 0.0f. 以正方形的中心为坐标点,进行移动,如下图所示:
矩阵.png
代码实现如下:
void SpecialKeys (int key, int x, int y){
GLfloat stepSize = 0.025f;
//操作键盘移动步数
if (key == GLUT_KEY_UP) {
yPos += stepSize;
}
if (key == GLUT_KEY_DOWN) {
yPos -= stepSize;
}
if (key == GLUT_KEY_LEFT) {
xPos -= stepSize;
}
if (key == GLUT_KEY_RIGHT) {
xPos += stepSize;
}
//防止移动出屏幕判断
if (xPos > 1.0 - blockSize) {
xPos = 1.0 - blockSize;
}
if (xPos < -1 + blockSize) {
xPos = -1 + blockSize;
}
if (yPos > 1.0 - blockSize) {
yPos = 1.0 - blockSize;
}
if (yPos < -1.0 + blockSize) {
yPos = -1.0 + blockSize;
}
//调起渲染
glutPostRedisplay();
}
此时,对应的渲染回调方法也要做对应修改,为着色器添加矩阵参数:
M3DMatrix44f mTransfromMatrix;
m3dTranslationMatrix44(mTransfromMatrix, xPos, yPos, 0.0);
shaderManager.UseStockShader(GLT_SHADER_FLAT,mTransfromMatrix,vRed);
矩阵方式正方形移动渲染整体代码如下:
#include "GLShaderManager.h"
#include "GLTools.h"
#include <GLUT/GLUT.h>
GLShaderManager shaderManager;
GLBatch triangleBatch;
GLfloat blockSize = 0.1f;
GLfloat vVerts[] = {
-blockSize,-blockSize,0.0,
blockSize,-blockSize,0.0,
blockSize, blockSize,0.0,
-blockSize, blockSize,0.0,
};
GLfloat xPos = 0.0f;
GLfloat yPos = 0.0f;
void changeSize (int w,int h) {
glViewport(0, 0, w, h);
}
void RenderScene (void) {
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
GLfloat vRed[] = {0.0,1.0,0.0,1.0};
M3DMatrix44f mTransfromMatrix;
m3dTranslationMatrix44(mTransfromMatrix, xPos, yPos, 0.0);
shaderManager.UseStockShader(GLT_SHADER_FLAT,mTransfromMatrix,vRed);
triangleBatch.Draw();
glutSwapBuffers();
}
void setupRC() {
glClearColor(0.8, 0.2, 0.5, 1.0);
shaderManager.InitializeStockShaders();
triangleBatch.Begin(GL_TRIANGLE_FAN, 4);
triangleBatch.CopyVertexData3f(vVerts);
triangleBatch.End();
}
void SpecialKeys (int key, int x, int y){
GLfloat stepSize = 0.025f;
if (key == GLUT_KEY_UP) {
yPos += stepSize;
}
if (key == GLUT_KEY_DOWN) {
yPos -= stepSize;
}
if (key == GLUT_KEY_LEFT) {
xPos -= stepSize;
}
if (key == GLUT_KEY_RIGHT) {
xPos += stepSize;
}
if (xPos > 1.0 - blockSize) {
xPos = 1.0 - blockSize;
}
if (xPos < -1 + blockSize) {
xPos = -1 + blockSize;
}
if (yPos > 1.0 - blockSize) {
yPos = 1.0 - blockSize;
}
if (yPos < -1.0 + blockSize) {
yPos = -1.0 + blockSize;
}
glutPostRedisplay();
}
int main(int argc, char * argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
glutInitWindowSize(500, 500);
glutCreateWindow("正方形");
glutReshapeFunc(changeSize);
glutDisplayFunc(RenderScene);
glutSpecialFunc(SpecialKeys);
GLenum status = glewInit();
if (GLEW_OK != status) {
return 1;
}
setupRC();
glutMainLoop();
return 0;
}
最终实现效果如下:
效果图.gif