计算机图形学 —— OpenGL绘制模型

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);
}

你可能感兴趣的:(计算机图形学)