我们试着用OpengGL来画一个坐标系,方便我们知道我们的模型当前的位置和方向。做好的坐标系类似下面的效果(中间的停顿效果是因为绘图程序是用主程序的空余时间来画的,如果鼠标按住标题栏,标题栏重绘的时候,就不会处理绘图程序了)。
OpenGL除了能画3D模型,渲染外,也可以画线。下面是一段画坐标箭头的代码,供参考。
首先要加载数据到缓存区
//箭头数据,每两个点为一组,画一条线段
glm::vec3 box[34] = {
{ 0, 0, 0.f },
{ 1, 0, 0.f },
{ 1, 0, 0.f },
{ 0.7, 0.1, 0.f },
{ 1, 0, 0.f },
{ 0.7, -0.1, 0.f },
{ 1.2, 0.1, 0.f },
{ 1.3, -0.1, 0.f },
{ 1.2, -0.1, 0.f },
{ 1.3, 0.1, 0.f },
{ 0, 0, 0.f },
{ 0, 1, 0.f },
{ 0, 1, 0.f },
{ 0.1, 0.7, 0.f },
{ 0, 1, 0.f },
{ -0.1, 0.7, 0.f },
{ 0.05, 1.3, 0.f },
{ 0, 1.2, 0.f },
{ -0.05, 1.3, 0.f },
{ 0, 1.2, 0.f },
{ 0, 1.2, 0.f },
{ 0, 1.1, 0.f },
{ 0, 0, 0.0f },
{ 0, 0, 1.0f },
{ 0, 0, 1.0f },
{ 0.1, 0.0, 0.7f },
{ 0, 0, 1.0f },
{ -0.1, 0.0, 0.7f },
{ -0.05, 0, 1.2f },
{ 0.05, 0, 1.2f },
{ 0.05, 0, 1.2f },
{ -0.05, 0.0, 1.1f },
{ -0.05, 0, 1.1f },
{ 0.05, 0.0, 1.1f }
};
std::vector<float> pvalues;
for(int i=0;i<sizeof(box);i++)
{
pvalues.push_back(box[i][0]);
pvalues.push_back(box[i][1]);
pvalues.push_back(box[i][2]);
}
glGenVertexArrays(1,vao);
glGenBuffers(1,vbo);
//绑定到vao
glBindVertexArray(vao[0]);
glBindBuffer(GL_ARRAY_BUFFER,vbo[0]);
//缓存数据
glBufferData(GL_ARRAY_BUFFER,pvalues.size()*4,&pvalues[0],GL_STATIC_DRAW);
//指定数据格式
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,0);
glEnableVertexAttribArray(0);
//松绑
glBindVertexArray(0);
绘图代码如下:
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);
glDepthFunc(GL_LEQUAL);
/获取统一变量地址
scene.mvLoc=glGetUniformLocation(renderingProgram,"mv_matrix");
scene.vMat=glm::translate(glm::mat4(1.0f),glm::vec3(-camera.camerax,-camera.cameray,-camera.cameraz)); scene.mMat=glm::translate(glm::mat4(1.0f),glm::vec3(mytorus.locx,mytorus.locy,mytorus.locz));
scene.mMat*= glm::rotate(glm::mat4(1.0f), (float)(mytorus.rotateangle),glm::vec3(1.0f,1.0f,0.0f));
scene.mvMat=scene.vMat*scene.mMat;
glUniformMatrix4fv(scene.mvLoc,1,GL_FALSE,glm::value_ptr(scene.mvMat));
glBindVertexArray(vao[0]);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glColor3f(0.f, 1.f, 1.f);
glLineWidth(5.0f);
glDrawArrays(GL_LINES, 0, 34);
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
glBindVertexArray(0);
效果图如下
也可以添加线条做成网格
结合圆环的绘制和变换矩阵,可以得到下面的动画效果:
熟悉GLSL的可以通过增加一个变量,将纹理颜色和普通颜色区分出来,就可以得到下面的结果。
顶点着色器代码:
#version 430
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 tex_coord;
layout (location = 2) in vec4 dcolor;
out vec2 tc;
out vec4 dc;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
layout (binding=0) uniform sampler2D s;
void main(void)
{ gl_Position = proj_matrix * mv_matrix * vec4(position,1.0);
tc = tex_coord;
dc=dcolor;
}
片段着色器代码:
#version 430
in vec2 tc;
in vec4 dc;
out vec4 color;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
layout (binding=0) uniform sampler2D s;
void main(void)
{
if(dc[3]==1.0f)
{
color=dc;
}else
{
color = texture(s,tc);
}
}
最后贴出整个主程序的代码(绘图代码有点啰嗦,懂vao的自己简化下):
#include <windows.h>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <gl/gl.h>
#include "Globalv.h"
using namespace std;
void LoadAxle(void)
{
glm::vec3 box[54] = {
//x轴
{ 0.0f, 0.0f, 0.0f },
{ 5.0f, 0.0f, 0.0f },
{ 5.0f, 0.0f, 0.0f },
{ 4.7f, 0.1f, 0.0f },
{ 5.0f, 0.0f, 0.0f },
{ 4.7f, -0.1f, 0.0f },
{ 5.2f, 0.1f, 0.0f },
{ 5.3f, -0.1f, 0.0f },
{ 5.2f, -0.1f, 0.0f },
{ 5.3f, 0.1f, 0.0f },
//y轴
{ 0.0f, 0.0f, 0.0f }, //10
{ 0.0f, 5.0f, 0.0f },
{ 0.0f, 5.0f, 0.0f },
{ 0.1f, 4.7f, 0.0f },
{ 0.0f, 5.0f, 0.0f },
{ -0.1f, 4.7f, 0.0f },
{ 0.05f, 5.3f, 0.0f },
{ 0.0f, 5.2f, 0.0f },
{ -0.05f, 5.3f, 0.0f },
{ 0.0f, 5.2f, 0.0f },
{ 0.0f, 5.2f, 0.0f },
{ 0.0f, 5.1f, 0.0f },
//z轴
{ 0.0f, 0.0f, 0.0f }, //22
{ 0.0f, 0.0f, 5.0f },
{ 0.0f, 0.0f, 5.0f },
{ 0.1f, 0.0f, 4.7f },
{ 0.0f, 0.0f, 5.0f },
{ -0.1f, 0.0f, 4.7f },
{ -0.05f, 0.0f, 5.2f },
{ 0.05f, 0.0f, 5.2f },
{ 0.05f, 0.0f, 5.2f },
{ -0.05f, 0.0f, 5.1f },
{ -0.05f, 0.0f, 5.1f },
{ 0.05f, 0.0f, 5.1f },
//网格横线
{ 0.0f, 0.0f, 0.0f }, //34
{ 0.0f, 4.0f, 0.0f },
{ 1.0f, 0.0f, 0.0f },
{ 1.0f, 4.0f, 0.0f },
{ 2.0f, 0.0f, 0.0f },
{ 2.0f, 4.0f, 0.0f },
{ 3.0f, 0.0f, 0.0f },
{ 3.0f, 4.0f, 0.0f },
{ 4.0f, 0.0f, 0.0f },
{ 4.0f, 4.0f, 0.0f },
//网格竖线
{ 0.0f, 0.0f, 0.0f }, //44
{ 4.0f, 0.0f, 0.0f },
{ 0.0f, 1.0f, 0.0f },
{ 4.0f, 1.0f, 0.0f },
{ 0.0f, 2.0f, 0.0f },
{ 4.0f, 2.0f, 0.0f },
{ 0.0f, 3.0f, 0.0f },
{ 4.0f, 3.0f, 0.0f },
{ 0.0f, 4.0f, 0.0f },
{ 4.0f, 4.0f, 0.0f }
};
std::vector<float> pvalues;
std::vector<float> dvalues;
glm::vec4 dcolor={0.0f,0.0f,1.0f,1.0f};
glm::vec4 ecolor={1.0f,0.0f,0.0f,1.0f};
glm::vec4 fcolor={0.0f,1.0f,0.0f,1.0f};
glm::vec4 gcolor={1.0f,1.0f,0.0f,1.0f};
for(int i=0;i<sizeof(box);i++)
{
pvalues.push_back(box[i][0]);
pvalues.push_back(box[i][1]);
pvalues.push_back(box[i][2]);
if(i<=9 or i==44 or i==45)
{
dvalues.push_back(dcolor[0]);
dvalues.push_back(dcolor[1]);
dvalues.push_back(dcolor[2]);
dvalues.push_back(dcolor[3]);
}else if(i<=21 or i==34 or i==35)
{
dvalues.push_back(ecolor[0]);
dvalues.push_back(ecolor[1]);
dvalues.push_back(ecolor[2]);
dvalues.push_back(ecolor[3]);
}else if(i<=33)
{
dvalues.push_back(fcolor[0]);
dvalues.push_back(fcolor[1]);
dvalues.push_back(fcolor[2]);
dvalues.push_back(fcolor[3]);
}else
{
dvalues.push_back(gcolor[0]);
dvalues.push_back(gcolor[1]);
dvalues.push_back(gcolor[2]);
dvalues.push_back(gcolor[3]);
}
}
glBindVertexArray(vao[0]);
glBindBuffer(GL_ARRAY_BUFFER,vbo[0]);
glBufferData(GL_ARRAY_BUFFER,pvalues.size()*4,&pvalues[0],GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER,vbo[1]);
glBufferData(GL_ARRAY_BUFFER,dvalues.size()*4,&dvalues[0],GL_STATIC_DRAW);
glBindVertexArray(0);
}
void LoadBuffer(void)
{
std::vector<int> ind=mytorus.getIndices();
std::vector<glm::vec3> vert =mytorus.getVertices();
std::vector<glm::vec2> tex=mytorus.getTexCoords();
std::vector<glm::vec3> norm=mytorus.getNormals();
std::vector<float> pvalues;
std::vector<float> tvalues;
std::vector<float> nvalues;
std::vector<float> dvalues;
int numVertices=mytorus.getNumVertices();
for(int i=0;i<numVertices;i++)
{
pvalues.push_back(vert[i].x);
pvalues.push_back(vert[i].y);
pvalues.push_back(vert[i].z);
tvalues.push_back(tex[i].s);
tvalues.push_back(tex[i].t);
nvalues.push_back(norm[i].x);
nvalues.push_back(norm[i].y);
nvalues.push_back(norm[i].z);
dvalues.push_back(0.0f);
dvalues.push_back(0.0f);
dvalues.push_back(0.0f);
dvalues.push_back(0.0f);
}
glBindVertexArray(vao[1]);
glBindBuffer(GL_ARRAY_BUFFER,vbo[2]);
glBufferData(GL_ARRAY_BUFFER,pvalues.size()*4,&pvalues[0],GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER,vbo[3]);
glBufferData(GL_ARRAY_BUFFER,tvalues.size()*4,&tvalues[0],GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER,vbo[4]);
glBufferData(GL_ARRAY_BUFFER,nvalues.size()*4,&nvalues[0],GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER,vbo[5]);
glBufferData(GL_ARRAY_BUFFER,dvalues.size()*4,&dvalues[0],GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER,ebo);
glBufferData(GL_ARRAY_BUFFER,ind.size()*4,&ind[0],GL_STATIC_DRAW);
glBindVertexArray(0);
}
void InitOpenGL(void)
{
//1.0 初始化数据
camera.camerax=2.0f;camera.cameray=1.0f;camera.cameraz=8.5f;
camera.rotateangle=0.1f;
mytorus.locx=0.0f;mytorus.locy=0.0f;mytorus.locz=0.0f;
mytorus.rotateangle=0.1f;
//1.1B 编译并使用纹理可编程管线
renderingProgram =mycorelib.createShaderProgram("vert.glsl", "frag.glsl");
//1.2B 选择指定的管线
glUseProgram(renderingProgram);
//1.3B 透视矩阵设置
scene.projLoc=glGetUniformLocation(renderingProgram,"proj_matrix");
scene.aspect=(float)scene.screenWidth/(float)scene.screenHeight;
scene.pMat=glm::perspective(1.0472f,scene.aspect,0.1f,1000.0f);
//1.0472radians=60degree
glUniformMatrix4fv(scene.projLoc,1,GL_FALSE,glm::value_ptr(scene.pMat));
glGenVertexArrays(2,vao);
glGenBuffers(6,vbo);
glGenBuffers(1, &ebo);
LoadAxle();
//1.4B
LoadBuffer();
//加载图片,制作纹理,贴图;除了这里加载图片外,还要在下面计算出贴图坐标,将其传到着色器里
int width,height,nrChannels;
glGenTextures(1, &texture);
unsigned char *data1=stbi_load("brick.jpg",&width,&height,&nrChannels,0);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data1);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(data1);
}
void DrawModel(float theta)
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);
glDepthFunc(GL_LEQUAL);
scene.mvLoc=glGetUniformLocation(renderingProgram,"mv_matrix");
scene.vMat=glm::translate(glm::mat4(1.0f),glm::vec3(-camera.camerax,-camera.cameray,-camera.cameraz));
glUniformMatrix4fv(scene.mvLoc,1,GL_FALSE,glm::value_ptr(scene.vMat));
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glColor3f(0.0f, 1.0f, 1.0f);
glLineWidth(2.0f);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(2);
glDrawArrays(GL_LINES, 0, 54);
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
glBindVertexArray(0);
scene.mMat=glm::translate(glm::mat4(1.0f),glm::vec3(mytorus.locx,mytorus.locy,mytorus.locz));
scene.mMat*=glm::rotate(glm::mat4(1.0f), (float)(mytorus.rotateangle),glm::vec3(1.0f,0.0f,0.0f));
scene.mvMat=scene.vMat*scene.mMat;
glUniformMatrix4fv(scene.mvLoc,1,GL_FALSE,glm::value_ptr(scene.mvMat));
//第一步,先保存原始位置到栈里
mvStack.push(scene.mvMat);
int mvsize=mvStack.size();
glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo[3]);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, vbo[5]);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glDrawElements(GL_TRIANGLES, mytorus.getNumIndices(), GL_UNSIGNED_INT, 0);
//在前面旋转的圆环的基础上,平移一个距离
mvStack.top()*=glm::translate(glm::mat4(1.0f), glm::vec3(0.0f,1.0f,0.0f));
glUniformMatrix4fv(scene.mvLoc,1,GL_FALSE,glm::value_ptr(mvStack.top()));
glDrawElements(GL_TRIANGLES, mytorus.getNumIndices(), GL_UNSIGNED_INT, 0);
mvStack.pop();
mvsize=mvStack.size();
}
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HWND hwnd;
HDC hDC;
HGLRC hRC;
MSG msg;
BOOL bQuit = FALSE;
if(myform.RegistWinform(hInstance)==0)
return 0;
/* create main window */
hwnd = CreateWindowEx(0,"GLSample","OpenGL Sample",
WS_OVERLAPPEDWINDOW,
360,200,683,384,
NULL,NULL,hInstance,NULL);
ShowWindow(hwnd, nCmdShow);
/* enable OpenGL for the window */
mycorelib.EnableOpenGL(hwnd, &hDC, &hRC);
InitOpenGL();
/* program main loop */
while (!bQuit)
{
/* check for messages */
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
myform.WatchMessage(msg,&bQuit);
}
else
{
DrawModel(mytorus.rotateangle);
SwapBuffers(hDC);
mytorus.rotateangle += 0.01f;
Sleep (20);
}
}
/* shutdown OpenGL */
mycorelib.DisableOpenGL(hwnd, hDC, hRC);
/* destroy the window explicitly */
DestroyWindow(hwnd);
return msg.wParam;
}
上传文件用于测试效果,附件链接: