Main.cpp
#include
#include
#include
#include
#include
#include
#include "misc.h"
#include "model.h"
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glew32.lib")
#pragma comment(lib, "winmm.lib")
LRESULT CALLBACK GLWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_LBUTTONDOWN:
break;
case WM_LBUTTONUP:
break;
case WM_MOUSEMOVE:
break;
case WM_RBUTTONDOWN:
break;
case WM_RBUTTONUP:
break;
case WM_KEYDOWN:
break;
case WM_KEYUP:
break;
case WM_CLOSE:
PostQuitMessage(0);
break;
default:
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
INT WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
//注册窗口
WNDCLASSEX wndclass;
wndclass.cbClsExtra = 0;
wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.cbWndExtra = 0;
wndclass.hbrBackground = NULL;
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hIcon = NULL;
wndclass.hIconSm = NULL;
wndclass.hInstance = hInstance;
wndclass.lpfnWndProc = GLWindowProc;
wndclass.lpszClassName = L"GLWindow";
wndclass.lpszMenuName = NULL;
wndclass.style = CS_VREDRAW | CS_HREDRAW;
ATOM atom = RegisterClassEx(&wndclass);
if (!atom) {
return -1;
}
RECT rect;
rect.left = 0;
rect.right = 1280;
rect.top = 0;
rect.bottom = 720;
AdjustWindowRect(&rect, WS_EX_OVERLAPPEDWINDOW, NULL);
//创建窗口
HWND hwnd = CreateWindowEx(NULL, L"GLWindow", L"OpenGL Window", WS_OVERLAPPEDWINDOW,
100, 100, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, hInstance, NULL);
GetClientRect(hwnd, &rect);
int viewportWidth = rect.right - rect.left;
int viewportHeight = rect.bottom - rect.top;
//创建OpenGL渲染窗口
//create opengl render context
HDC dc = GetDC(hwnd);
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nVersion = 1;
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.cColorBits = 32;
pfd.cDepthBits = 24;
pfd.cStencilBits = 8;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.iLayerType = PFD_MAIN_PLANE;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
int pixelFormat = ChoosePixelFormat(dc, &pfd);
SetPixelFormat(dc, pixelFormat, &pfd);
HGLRC rc = wglCreateContext(dc);
wglMakeCurrent(dc, rc); // setup OpenGL context complete
glewInit();
GLuint program = CreateGPUProgram("res/shader/sample.vs", "res/shader/sample.fs");
GLint posLocation, texcoordLocation, normalLocation, MLocation, VLocation, PLocation;
posLocation = glGetAttribLocation(program, "pos");
texcoordLocation = glGetAttribLocation(program, "texcoord");
normalLocation = glGetAttribLocation(program, "normal");
MLocation = glGetUniformLocation(program, "M");
VLocation = glGetUniformLocation(program, "V");
PLocation = glGetUniformLocation(program, "P");
//load obj model: vertexes, vertex count, indexes, index count
unsigned int *indexes = nullptr;
int vertexCount = 0, indexCount = 0;
VertexData*vertexes = LoadObjModel("res/model/niutou.obj", &indexes, vertexCount, indexCount);
if (vertexes == nullptr)
{
printf("load obj model fail");
}
//obj model -> vbo & ibo
GLuint vbo = CreateBufferObject(GL_ARRAY_BUFFER, sizeof(VertexData) * vertexCount, GL_STATIC_DRAW, vertexes);
GLuint ibo = CreateBufferObject(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * indexCount, GL_STATIC_DRAW, indexes);
printf("vetex count %d index count %d", vertexCount, indexCount);
//显示窗口
glViewport(0, 0, viewportWidth, viewportHeight);
glClearColor(41.f / 255.f, 71.f / 255.f, 121.f / 255.f, 1.0f); //set "clear color" for background
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
glm::mat4 identity = glm::mat4(1.0f);
glm::mat4 model;
model = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, -0.5f, -4.0f)); //平移
model = glm::rotate(model, glm::radians(-90.0f), glm::vec3(0.f, 1.f, 0.f)); //旋转
model = glm::scale(model, glm::vec3(0.01f, 0.01f, 0.01f)); //缩放
glm::mat4 projection = glm::perspective(45.f, (float)viewportWidth / (float)viewportHeight, 0.1f, 1000.f);
static float sTimeSinceStartUp = timeGetTime() / 1000.0f;
MSG msg;
while (true)
{
if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
//draw scene
//计算两帧之间的时间
float currentTime = timeGetTime() / 1000.0f;
float timeElapse = currentTime - sTimeSinceStartUp;
sTimeSinceStartUp = currentTime;
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
glUniformMatrix4fv(MLocation, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(VLocation, 1, GL_FALSE, glm::value_ptr(identity));
glUniformMatrix4fv(PLocation, 1, GL_FALSE, glm::value_ptr(projection));
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableVertexAttribArray(posLocation);
glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void*)0);
glEnableVertexAttribArray(texcoordLocation);
glVertexAttribPointer(texcoordLocation, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void*)(sizeof(float) * 3));
glEnableVertexAttribArray(normalLocation);
glVertexAttribPointer(normalLocation, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void*)(sizeof(float) * 5));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glUseProgram(0);
//printf("time elapse since last frame: %f\n", timeElapse);
//present scene
SwapBuffers(dc);
}
return 0;
}
通用工具封装
misc.h
#pragma once
#include
GLuint CreateBufferObject(GLenum bufferType, GLsizeiptr size, GLenum usage, void* data=nullptr);
char *LoadFileContent(const char* path);
GLuint CompileShader(GLenum shaderType, const char* shaderPath);
GLuint CreateGPUProgram(const char *vsShaderPath, const char *fsShaderPath);
misc.cpp
#include "misc.h"
#include
GLuint CreateBufferObject(GLenum bufferType, GLsizeiptr size, GLenum usage, void * data)
{
GLuint object;
glGenBuffers(1, &object);
glBindBuffer(bufferType, object);
glBufferData(bufferType, size, data, usage);//内存数据到显卡
glBindBuffer(bufferType, 0);
return object;
}
char * LoadFileContent(const char * path)
{
FILE *pFile = fopen(path, "rb");
if (pFile)
{
fseek(pFile, 0, SEEK_END);
int nLen = ftell(pFile);
char*buffer = nullptr;
if (nLen != 0)
{
buffer = new char[nLen + 1];
rewind(pFile);
fread(buffer, nLen, 1, pFile);
buffer[nLen] = '\0';
}
else
{
printf("load file fail %s content len is 0 \n", path);
}
fclose(pFile);
return buffer;
}
else
{
printf("open file %s fail \n", path);
}
fclose(pFile);
return nullptr;
}
GLuint CompileShader(GLenum shaderType, const char* shaderPath)
{
GLuint shader = glCreateShader(shaderType);
if (shader == 0)
{
printf("glCreateShader fail\n");
return 0;
}
const char* shaderCode = LoadFileContent(shaderPath);
if (shaderCode == nullptr)
{
printf("Load shader code from file: %s fail\n", shaderPath);
glDeleteShader(shader);
return 0;
}
glShaderSource(shader, 1, &shaderCode, nullptr);
glCompileShader(shader);
GLint compileResult = GL_TRUE;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
if (compileResult == GL_FALSE)
{
char szLog[1024] = {0};
GLsizei logLen = 0;
glGetShaderInfoLog(shader, 1024, &logLen, szLog);
printf("Compile Shader fail error log:\n%s \nshader code:\n%s\n", szLog, shaderCode);
glDeleteShader(shader);
shader = 0;
}
delete shaderCode;
return shader;
}
//编译链接gpu程序
GLuint CreateGPUProgram(const char *vsShaderPath, const char *fsShaderPath)
{
GLuint vsShader = CompileShader(GL_VERTEX_SHADER, vsShaderPath);
GLuint fsShader = CompileShader(GL_FRAGMENT_SHADER, fsShaderPath);
GLuint program = glCreateProgram();
glAttachShader(program, vsShader);
glAttachShader(program, fsShader);
glLinkProgram(program);
glDetachShader(program, vsShader);
glDetachShader(program, fsShader);
glDeleteShader(vsShader);
glDeleteShader(fsShader);
GLint linkResult = GL_TRUE;
glGetProgramiv(program, GL_LINK_STATUS, &linkResult);
if (linkResult == GL_FALSE)
{
char szLog[1024] = { 0 };
GLsizei logLen = 0;
glGetProgramInfoLog(program, 1024, &logLen, szLog);
printf("Link program fail error log:\n%s \nvs: %s\nfs: %s\n", szLog, vsShaderPath, fsShaderPath);
glDeleteProgram(program);
program = 0;
}
return program;
}
模型解析类
model.h
#pragma once
struct VertexData
{
float position[3];
float texcoord[2];
float normal[3];
};
VertexData*LoadObjModel(const char*filePath, unsigned int **indexes, int &vertexCount, int &indexCount);
model.cpp
#include "model.h"
#include
#include
#include
#include "misc.h"
#include
VertexData * LoadObjModel(const char *filePath, unsigned int **indexes, int &vertexCount, int &indexCount)
{
char *fileContent = LoadFileContent(filePath);
if (fileContent != nullptr)
{
//obj model decode
struct VertexInfo
{
float v[3];
};
struct VertexDefine
{
int positionIndex;
int texcoordIndex;
int normalIndex;
};
std::vector<VertexInfo> positions;
std::vector<VertexInfo> texcoords;
std::vector<VertexInfo> normals;
std::vector<unsigned int> objIndexes; //-> OpenGL indexes
std::vector<VertexDefine> vertices; //-> OpenGL vertexes
std::stringstream ssObjFile(fileContent);
char szOneLine[256];
std::string temp;
while (!ssObjFile.eof())
{
memset(szOneLine, 0, 256);
ssObjFile.getline(szOneLine, 256);
if (strlen(szOneLine) > 0)
{
std::stringstream ssOneLine(szOneLine);
if (szOneLine[0] == 'v')
{
if (szOneLine[1] == 't')
{
//vertex coord
ssOneLine >> temp;
VertexInfo vi;
ssOneLine >> vi.v[0];
ssOneLine >> vi.v[1];
texcoords.push_back(vi);
}
else if (szOneLine[1] == 'n')
{
//normal
ssOneLine >> temp;
VertexInfo vi;
ssOneLine >> vi.v[0];
ssOneLine >> vi.v[1];
ssOneLine >> vi.v[2];
normals.push_back(vi);
}
else
{
//position
ssOneLine >> temp;
VertexInfo vi;
ssOneLine >> vi.v[0];
ssOneLine >> vi.v[1];
ssOneLine >> vi.v[2];
positions.push_back(vi);
}
}
else if (szOneLine[0] == 'f')
{
//face
ssOneLine >> temp;
std::string vertexStr;
for (int i = 0; i < 3; i++)
{
ssOneLine >> vertexStr;
size_t pos1 = vertexStr.find_first_of('/');
std::string positionIndexStr = vertexStr.substr(0, pos1);
size_t pos2 = vertexStr.find_first_of('/', pos1 + 1);
std::string texcoordIndexStr = vertexStr.substr(pos1 + 1, pos2 - pos1 - 1);
std::string normalIndexStr = vertexStr.substr(pos2 + 1, vertexStr.length() - pos2 - 1);
VertexDefine vd;
vd.positionIndex = atoi(positionIndexStr.c_str()) - 1;
vd.texcoordIndex = atoi(texcoordIndexStr.c_str()) - 1;
vd.normalIndex = atoi(normalIndexStr.c_str()) - 1;
//check if exist
int nCurrentIndex = -1;//indexes
size_t nCurrentVerticeCount = vertices.size();
for (size_t j = 0; j < nCurrentVerticeCount; j++)
{
if (vertices[j].positionIndex == vd.positionIndex &&
vertices[j].texcoordIndex == vd.texcoordIndex &&
vertices[j].normalIndex == vd.normalIndex)
{
//
nCurrentIndex = j;
break;
}
}
if (nCurrentIndex == -1)
{
//create new vertice
nCurrentIndex = vertices.size();
vertices.push_back(vd);//vertexes define
}
objIndexes.push_back(nCurrentIndex);
}
}
}
}
//printf("face count %u\n", objIndexes.size() / 3);
//objIndexes -> indexes buffer -> ibo
indexCount = (int)objIndexes.size();
*indexes = new unsigned int[indexCount];
for (int i = 0; i < indexCount; i++)
{
(*indexes)[i] = objIndexes[i];
}
//vertices -> vertexes -> vbo
vertexCount = (int)vertices.size();
VertexData *vertexes = new VertexData[vertexCount];
for (int i = 0; i < vertexCount; i++)
{
memcpy(vertexes[i].position, positions[vertices[i].positionIndex].v, sizeof(float) * 3);
memcpy(vertexes[i].texcoord, texcoords[vertices[i].texcoordIndex].v, sizeof(float) * 2);
memcpy(vertexes[i].normal, normals[vertices[i].normalIndex].v, sizeof(float) * 3);
}
return vertexes;
}
return nullptr;
}
shader.vs
attribute vec3 pos;
attribute vec2 texcoord;
attribute vec3 normal;
uniform mat4 M;
uniform mat4 V;
uniform mat4 P;
varying vec4 V_Color;
void main()
{
gl_Position=P*V*M*vec4(pos,1.0);
}
shader.fs
void main()
{
gl_FragColor=vec4(1.0);
}