Main.cpp
#include <windows.h>
#include <stdio.h>
#include <GLEW/glew.h>
#include <glm/glm.hpp>
#include <glm/ext.hpp>
#include <glm/ext/matrix_transform.hpp>
#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/specularTexture.vs", "res/shader/specularTexture.fs");
GLint posLocation, texcoordLocation, normalLocation, MLocation, VLocation, PLocation, NMLocation, textureLocation;
posLocation = glGetAttribLocation(program, "pos");
texcoordLocation = glGetAttribLocation(program, "texcoord");
normalLocation = glGetAttribLocation(program, "normal");
MLocation = glGetUniformLocation(program, "M");
VLocation = glGetUniformLocation(program, "V");
PLocation = glGetUniformLocation(program, "P");
NMLocation = glGetUniformLocation(program, "NM");
textureLocation = glGetUniformLocation(program, "U_MainTexture");
//load obj model: vertexes, vertex count, indexes, index count
unsigned int *indexes = nullptr;
int vertexCount = 0, indexCount = 0;
VertexData*vertexes = LoadObjModel("res/model/Sphere.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);
GLuint mainTexture = CreateTextureFromFile("res/image/earth.bmp");
printf("vetex count %d index count %d", vertexCount, indexCount);
glClearColor(0.f, 0.f, 0.f, 1.f);
//显示窗口
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
glEnable(GL_DEPTH_TEST);
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.0f, -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);
glm::mat4 normalMatrix = glm::inverseTranspose(model);
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;
float angle = 0.0f;
angle += 20.0f * timeElapse;
if (angle > 360.0f)
{
angle = 0.0f;
}
model = glm::rotate(model, glm::radians(angle), glm::vec3(0.f, 1.f, 0.f)); //旋转
glm::mat4 normalMatrix = glm::inverseTranspose(model);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_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));
glUniformMatrix4fv(NMLocation, 1, GL_FALSE, glm::value_ptr(normalMatrix));
glBindTexture(GL_TEXTURE_2D, mainTexture);
glUniform1i(textureLocation, 0);
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;
}
mish.h
#pragma once
#include <GLEW/glew.h>
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);
GLuint CreateTextureFromFile(const char*imagePath);
mish.cpp
#include "misc.h"
#include <stdio.h>
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;
}
GLuint CreateTextureFromFile(const char*imagePath)
{
unsigned char* imgData = (unsigned char*)LoadFileContent(imagePath);
if (*((unsigned short*)imgData) != 0x4D42)
{
printf("cannot decode %s\n", imagePath);
delete imgData;
return 0;
}
//decode bmp
int pixelDataOffset = *((int*)(imgData + 10));
int width = *((int*)(imgData + 18));
int height = *((int*)(imgData + 22));
unsigned char*pixelData = (imgData + pixelDataOffset);
for (int i = 0; i < width*height*3; i+=3)
{
//bgr->rgb
unsigned char temp = pixelData[i + 2];
pixelData[i + 2] = pixelData[i];
pixelData[i] = temp;
}
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, pixelData);
glBindTexture(GL_TEXTURE_2D, 0);
delete imgData;
return texture;
}
specularTexture.vs
attribute vec3 pos;
attribute vec2 texcoord;
attribute vec3 normal;
uniform mat4 M;
uniform mat4 V;
uniform mat4 P;
uniform mat4 NM;
uniform sampler2D U_MainTexture;
varying vec3 V_Normal;
varying vec4 V_WorldPos;
varying vec2 V_Texcoord;
void main()
{
V_Normal = mat3(NM) * normal;
V_WorldPos = M*vec4(pos,1.0);
V_Texcoord = texcoord;
gl_Position=P*V*M*vec4(pos,1.0);
}
specularTexture.fs
//uniform vec4 U_AmbientLightColor;
//uniform vec4 U_AmbientMaterial;
uniform sampler2D U_MainTexture;
varying vec3 V_Normal;
varying vec4 V_WorldPos;
varying vec2 V_Texcoord;
void main()
{
vec3 lightPos = vec3(10.0,10.0,0.0);
vec3 L = lightPos;
L = normalize(L);
vec3 n = normalize(V_Normal);
//ambient
vec4 AmbientLightColor = vec4(0.2,0.2,0.2,1.0);
vec4 AmbientMaterial = vec4(0.2,0.2,0.2,1.0);
vec4 ambientColor = AmbientLightColor * AmbientMaterial;
//diffuse
vec4 DiffuseLightColor = vec4(1.0,1.0,1.0,1.0);
vec4 DiffuseMaterial = vec4(0.8,0.8,0.8,1.0);
vec4 diffuseColor = DiffuseLightColor * DiffuseMaterial * max(0.0, dot(L,n));
//specular
vec3 reflectDir = normalize(reflect(-L,n));
vec4 SpecularLightColor = vec4(1.0,1.0,1.0,1.0);
vec4 SpecularMaterial = vec4(0.4,0.4,0.4,1.0);
//inverse view direction
vec3 viewDir = normalize(vec3(0.0) - V_WorldPos.xyz);
vec4 specularColor = SpecularLightColor * SpecularMaterial * pow(max(0.0, dot(viewDir, reflectDir)), 18.0);
if(diffuseColor.r == 0.0)
{
gl_FragColor = ambientColor + texture2D(U_MainTexture, V_Texcoord) * diffuseColor;
}
else{
gl_FragColor = ambientColor + texture2D(U_MainTexture, V_Texcoord) * diffuseColor; //+ specularColor;
}
}