我正在使用 win32 编写一个基本的 opengl 抽象库,并且我一直坚持获取 2d 纹理以渲染为两个三角形四边形。我得到的不是渲染四边形,而是一个空白的黑屏。用其他着色器绘图效果很好,但这个不行。
我认为这一定与纹理有关,但即使尝试使用测试着色器渲染原始几何体,它也不会渲染纹理映射到的两个三角形。尝试使用 glIsShader() 验证着色器返回 GL_FALSE,但我没有从日志中收到任何信息。所以我不知道着色器的问题是什么,或者我做错了什么。 我所有的 gl 函数都是手动加载的,所以 _g 在那里,因为我不能重用它们的名称,因为我使用的是 glext.h。我知道这对我的函数没有任何影响,因为它们都加载了一个有效的函数地址。
这是我的 github 页面: https://github.com/HyperBitGore/g_engine_2d
这是我的着色器编译器 编辑:更改着色器代码
GLuint EngineNewGL::compileShader(const char* vertex_file, const char* fragment_file) {
// Create the shaders
GLuint VertexShaderID = glCreateShader_g(GL_VERTEX_SHADER);
GLuint FragmentShaderID = glCreateShader_g(GL_FRAGMENT_SHADER);
GLint Result = GL_FALSE;
int InfoLogLength;
// Compile Vertex Shader
std::cout << "Compiling vertex shader" << std::endl;
char const* VertexSourcePointer = vertex_file;
glShaderSource_g(VertexShaderID, 1, &VertexSourcePointer, NULL);
glCompileShader_g(VertexShaderID);
// Check Vertex Shader
glGetShaderiv_g(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv_g(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0) {
std::vector<char> VertexShaderErrorMessage(InfoLogLength + 1);
glGetShaderInfoLog_g(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
printf("%s\n", &VertexShaderErrorMessage[0]);
}
// Compile Fragment Shader
std::cout << "Compiling fragment shader" << std::endl;;
char const* FragmentSourcePointer = fragment_file;
glShaderSource_g(FragmentShaderID, 1, &FragmentSourcePointer, NULL);
glCompileShader_g(FragmentShaderID);
// Check Fragment Shader
glGetShaderiv_g(FragmentShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv_g(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0) {
std::vector<char> FragmentShaderErrorMessage(InfoLogLength + 1);
glGetShaderInfoLog_g(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
printf("%s\n", &FragmentShaderErrorMessage[0]);
}
// Link the program
std::cout << "Linking program" << std::endl;
GLuint ProgramID = glCreateProgram_g();
glAttachShader_g(ProgramID, VertexShaderID);
glAttachShader_g(ProgramID, FragmentShaderID);
glLinkProgram_g(ProgramID);
// Check the program
glGetProgramiv_g(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv_g(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0) {
std::vector<char> ProgramErrorMessage(InfoLogLength + 1);
glGetProgramInfoLog_g(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
printf("%s\n", &ProgramErrorMessage[0]);
}
glDetachShader_g(ProgramID, VertexShaderID);
glDetachShader_g(ProgramID, FragmentShaderID);
glDeleteShader_g(VertexShaderID);
glDeleteShader_g(FragmentShaderID);
return ProgramID;
}
这就是我初始化 OpenGL 的方式
EngineNewGL::EngineNewGL(LPCWSTR window_name, int width, int height) {
PIXELFORMATDESCRIPTOR windowPixelFormatDesc = { 0 };
windowPixelFormatDesc.nSize = sizeof(windowPixelFormatDesc);
windowPixelFormatDesc.nVersion = 1;
windowPixelFormatDesc.iPixelType = PFD_TYPE_RGBA;
windowPixelFormatDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
windowPixelFormatDesc.cColorBits = 32;
windowPixelFormatDesc.cAlphaBits = 8;
windowPixelFormatDesc.iLayerType = PFD_MAIN_PLANE;
windowPixelFormatDesc.cDepthBits = 24;
windowPixelFormatDesc.cStencilBits = 8;
//function pointers
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL;
//create window
wind = new Window(window_name, L"ENG1", width, height, 300, 300);
in = new Input();
//getting device context
dc_w = GetDC(wind->getHwnd());
{
// to get WGL functions we need valid GL context, so create dummy window for dummy GL contetx
HWND dummy = CreateWindowExW(
0, L"STATIC", L"DummyWindow", WS_OVERLAPPED,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, NULL, NULL);
Assert(dummy && "Failed to create dummy window");
HDC dc = GetDC(dummy);
Assert(dc && "Failed to get device context for dummy window");
PIXELFORMATDESCRIPTOR desc =
{
desc.nSize = sizeof(desc),
desc.nVersion = 1,
desc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
desc.iPixelType = PFD_TYPE_RGBA,
desc.cColorBits = 32,
};
int format = ChoosePixelFormat(dc, &desc);
if (!format)
{
FatalError("Cannot choose OpenGL pixel format for dummy window!");
}
int ok = DescribePixelFormat(dc, format, sizeof(desc), &desc);
Assert(ok && "Failed to describe OpenGL pixel format");
// reason to create dummy window is that SetPixelFormat can be called only once for the window
if (!SetPixelFormat(dc, format, &desc))
{
FatalError("Cannot set OpenGL pixel format for dummy window!");
}
HGLRC rc = wglCreateContext(dc);
Assert(rc && "Failed to create OpenGL context for dummy window");
ok = wglMakeCurrent(dc, rc);
Assert(ok && "Failed to make current OpenGL context for dummy window");
//now get wgl functions using the dummy context
PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB =
(PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
const char* ext = wglGetExtensionsStringARB(dc);
wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
wglMakeCurrent(NULL, NULL);
wglDeleteContext(rc);
ReleaseDC(dummy, dc);
DestroyWindow(dummy);
}
dc_w = GetDC(wind->getHwnd());
// set pixel format for OpenGL context
{
int attrib[] =
{
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
//WGL_TEXTURE_2D_ARB, GL_TRUE,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
//WGL_TEXTURE_FORMAT_ARB, WGL_TEXTURE_RGBA_ARB,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_COLOR_BITS_ARB, 32,
WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8,
// uncomment for sRGB framebuffer, from WGL_ARB_framebuffer_sRGB extension
// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_framebuffer_sRGB.txt
//WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, GL_TRUE,
// uncomment for multisampeld framebuffer, from WGL_ARB_multisample extension
// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_multisample.txt
//WGL_SAMPLE_BUFFERS_ARB, 1,
//WGL_SAMPLES_ARB, 4, // 4x MSAA
0,
};
int format;
UINT formats;
if (!wglChoosePixelFormatARB(dc_w, attrib, NULL, 1, &format, &formats) || formats == 0)
{
FatalError("OpenGL does not support required pixel format!");
}
PIXELFORMATDESCRIPTOR desc;
desc.nSize = sizeof(desc);
int ok = DescribePixelFormat(dc_w, format, sizeof(desc), &desc);
Assert(ok && "Failed to describe OpenGL pixel format");
if (!SetPixelFormat(dc_w, format, &desc))
{
FatalError("Cannot set OpenGL selected pixel format!");
}
}
//now create opengl context
int attrib[] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
#ifndef NDEBUG
// ask for debug context for non "Release" builds
// this is so we can enable debug callback
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB,
#endif
0,
};
context = wglCreateContextAttribsARB(dc_w, NULL, attrib);
//context = wglCreateContext(dc);
if (!wglMakeCurrent(dc_w, context)) {
std::cerr << "Failed to make context current\n";
}
glEnable(GL_TEXTURE_2D);
//glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
loadFunctions();
//start modern opengl needed stuff like shaders and vertex buffers
glGenVertexArrays_g(1, &VAO_Triangle);
//glBindVertexArray_g(VAO_Triangle);
glGenVertexArrays_g(1, &VAO_Points);
//glBindVertexArray_g(VAO_Points);
glGenVertexArrays_g(1, &VAO_Line);
//glBindVertexArray_g(VAO_Line);
glGenVertexArrays_g(1, &VAO_Img);
//glBindVertexArray_g(VAO_Img);
glGenBuffers_g(1, &uv_buffer);
glBindBuffer_g(GL_ARRAY_BUFFER, uv_buffer);
glGenBuffers_g(1, &vertex_buffer);
glBindBuffer_g(GL_ARRAY_BUFFER, vertex_buffer);
//shader compiles
const char* vertex_shader_img = "#version 330 core\nlayout(location = 0) in vec2 pos;\nlayout(location = 1) in vec2 uv;\nout vec2 tex_coords;\nvoid main(){\n"
"gl_Position = vec4(pos.x, pos.y, 0.0, 1.0);\n"
"tex_coords = vec2(uv.x, uv.y);\n"
"}\0";
const char* fragment_shader_img = "#version 330 core\nin vec2 tex_coords;\nout vec4 color;\nuniform sampler2D image_tex;\nvoid main(){\n"
"color = texture(image_tex, tex_coords);\n}\0";
//"color = vec3(1.0f, 0.2f, 0.2f);\n}\0";
const char* test_shader = "#version 330 core\nlayout(location = 0) in vec2 pos;\nvoid main(){\ngl_Position = vec4(pos.x, pos.y, 0.0, 1.0);\n}\0";
const char* test_frag = "#version 330 core\nout vec4 color;\nvoid main(){\ncolor = vec4(1.0, 0.2, 0.2, 1.0);\n}\0";
shader_img = compileShader(vertex_shader_img, fragment_shader_img);
glValidateProgram_g(shader_img);
int success;
char infoLog[512];
glGetProgramInfoLog_g(shader_img, 512, &success, infoLog);
std::cout << infoLog << "\n";
std::cout << shader_img << "\n";
if (glIsShader_g(shader_img) == GL_TRUE) {
std::cout << "is shader\n";
}
std::cout << std::to_string(glIsShader_g(shader_img)) << "\n";
glUseProgram_g(shader_img);
glBindVertexArray_g(VAO_Img);
GLuint position = glGetAttribLocation_g(shader_img, "pos");
glEnableVertexAttribArray_g(position);
glVertexAttribPointer_g(position, 2, GL_FLOAT, GL_FALSE, sizeof(vec2), (void*)0);
glBindBuffer_g(GL_ARRAY_BUFFER, vertex_buffer);
position = glGetAttribLocation_g(shader_img, "uv");
glEnableVertexAttribArray_g(position);
glVertexAttribPointer_g(position, 2, GL_FLOAT, GL_FALSE, sizeof(vec2), (void*)0);
glBindBuffer_g(GL_ARRAY_BUFFER, uv_buffer);
glBindBuffer_g(GL_ARRAY_BUFFER, 0);
//speed up push_backs
buffer_2d.reserve(1000);
buffer_3d.reserve(1000);
buffer_uv.reserve(1000);
ShowWindow(wind->getHwnd(), SW_SHOW);
}
实际绘图功能
void EngineNewGL::renderImg(IMG img, float x, float y, int w, int h) {
//glEnable(GL_BLEND);
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//triangle 1
buffer_2d.push_back({ x, y });
buffer_2d.push_back({ x + w, y });
buffer_2d.push_back({ x, y + h });
//triangle 2
buffer_2d.push_back({ x + w, y });
buffer_2d.push_back({ x + w, y + h });
buffer_2d.push_back({ x, y + h });
//uv triangle 1
buffer_uv.push_back({ 0, 0 });
buffer_uv.push_back({ 1, 0 });
buffer_uv.push_back({ 0, 1 });
//uv triangle 2
buffer_uv.push_back({ 1, 0 });
buffer_uv.push_back({ 1, 1 });
buffer_uv.push_back({ 0, 1 });
float verts[] = { x, y, x + w, y, x, y + h, x + w, y, x + w, y + h,x, y + h };
float uvs[] = { 0,0,1,0,0,1,1,0,1,1,0,1 };
glUseProgram_g(shader_img);
if (glGetError() == GL_INVALID_VALUE) {
//std::cout << "invalid value\n";
std::cout << glGetError() << "\n";
}
glActiveTexture_g(GL_TEXTURE0);
GLuint texUniformLocation = glGetUniformLocation_g(shader_img, "image_tex");
glUniform1i_g(texUniformLocation, 0);
glBindTexture(GL_TEXTURE_2D, img->tex);
glBindVertexArray_g(VAO_Img);
glBindBuffer_g(GL_ARRAY_BUFFER, vertex_buffer);
glBufferData_g(GL_ARRAY_BUFFER, buffer_2d.size() * sizeof(vec2), &buffer_2d[0], GL_STATIC_DRAW);
glBindBuffer_g(GL_ARRAY_BUFFER, uv_buffer);
glBufferData_g(GL_ARRAY_BUFFER, buffer_uv.size() * sizeof(vec2), &buffer_uv[0], GL_STATIC_DRAW);
glDrawArrays(GL_TRIANGLES, 0, buffer_2d.size());
buffer_2d.clear();
buffer_uv.clear();
glBindVertexArray_g(0);
glBindBuffer_g(GL_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
//glDisable(GL_BLEND);
}
这是我加载函数的方式
//to load new gl functions
void* GetGLFuncAddress(const char* name) {
void* p = (void*)wglGetProcAddress(name);
if (p == 0x0 || p == (void*)0x01 || p == (void*)0x02 || p == (void*)0x03 || p == (void*)-0x1) {
HMODULE module = LoadLibraryA("opengl32.dll");
p = (void*)GetProcAddress(module, name);
}
std::cout << p << "\n";
return p;
}
PFNGLBINDBUFFERPROC glBindBuffer_g;
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays_g;
PFNGLGENBUFFERSPROC glGenBuffers_g;
PFNGLBUFFERDATAPROC glBufferData_g;
PFNGLATTACHSHADERPROC glAttachShader_g;
PFNGLCOMPILESHADERPROC glCompileShader_g;
PFNGLCREATEPROGRAMPROC glCreateProgram_g;
PFNGLCREATESHADERPROC glCreateShader_g;
PFNGLDELETESHADERPROC glDeleteShader_g;
PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray_g;
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray_g;
PFNGLGETPROGRAMIVPROC glGetProgramiv_g;
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog_g;
PFNGLLINKPROGRAMPROC glLinkProgram_g;
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog_g;
PFNGLBINDVERTEXARRAYPROC glBindVertexArray_g;
PFNGLSHADERSOURCEPROC glShaderSource_g;
PFNGLGETSHADERIVPROC glGetShaderiv_g;
PFNGLUSEPROGRAMPROC glUseProgram_g;
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer_g;
PFNGLUNIFORM1IPROC glUniform1i_g;
PFNGLACTIVETEXTUREPROC glActiveTexture_g;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation_g;
PFNGLISSHADERPROC glIsShader_g;
PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation_g;
PFNGLVALIDATEPROGRAMPROC glValidateProgram_g;
void EngineNewGL::loadFunctions() {
glBindBuffer_g = (PFNGLBINDBUFFERPROC)GetGLFuncAddress("glBindBuffer");
glGenVertexArrays_g = (PFNGLGENVERTEXARRAYSPROC)GetGLFuncAddress("glGenVertexArrays");
glGenBuffers_g = (PFNGLGENBUFFERSPROC)GetGLFuncAddress("glGenBuffers");
glBufferData_g = (PFNGLBUFFERDATAPROC)GetGLFuncAddress("glBufferData");
glAttachShader_g = (PFNGLATTACHSHADERPROC)GetGLFuncAddress("glAttachShader");
glCompileShader_g = (PFNGLCOMPILESHADERPROC)GetGLFuncAddress("glCompileShader");
glCreateProgram_g = (PFNGLCREATEPROGRAMPROC)GetGLFuncAddress("glCreateProgram");
glCreateShader_g = (PFNGLCREATESHADERPROC)GetGLFuncAddress("glCreateShader");
glDeleteShader_g = (PFNGLDELETESHADERPROC)GetGLFuncAddress("glDeleteShader");
glDisableVertexAttribArray_g = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)GetGLFuncAddress("glDisableVertexAttribArray");
glEnableVertexAttribArray_g = (PFNGLENABLEVERTEXATTRIBARRAYPROC)GetGLFuncAddress("glEnableVertexAttribArray");
glGetProgramiv_g = (PFNGLGETPROGRAMIVPROC)GetGLFuncAddress("glGetProgramiv");
glGetProgramInfoLog_g = (PFNGLGETPROGRAMINFOLOGPROC)GetGLFuncAddress("glGetProgramInfoLog");
glLinkProgram_g = (PFNGLLINKPROGRAMPROC)GetGLFuncAddress("glLinkProgram");
glGetShaderInfoLog_g = (PFNGLGETSHADERINFOLOGPROC)GetGLFuncAddress("glGetShaderInfoLog");
glBindVertexArray_g = (PFNGLBINDVERTEXARRAYPROC)GetGLFuncAddress("glBindVertexArray");
glShaderSource_g = (PFNGLSHADERSOURCEPROC)GetGLFuncAddress("glShaderSource");
glGetShaderiv_g = (PFNGLGETSHADERIVPROC)GetGLFuncAddress("glGetShaderiv");
glUseProgram_g = (PFNGLUSEPROGRAMPROC)GetGLFuncAddress("glUseProgram");
glVertexAttribPointer_g = (PFNGLVERTEXATTRIBPOINTERPROC)GetGLFuncAddress("glVertexAttribPointer");
glUniform1i_g = (PFNGLUNIFORM1IPROC)GetGLFuncAddress("glUniform1i");
glActiveTexture_g = (PFNGLACTIVETEXTUREPROC)GetGLFuncAddress("glActiveTexture");
glGetUniformLocation_g = (PFNGLGETUNIFORMLOCATIONPROC)GetGLFuncAddress("glGetUniformLocation");
glIsShader_g = (PFNGLISSHADERPROC)GetGLFuncAddress("glIsShader");
glGetAttribLocation_g = (PFNGLGETATTRIBLOCATIONPROC)GetGLFuncAddress("glGetAttribLocation");
glValidateProgram_g = (PFNGLVALIDATEPROGRAMPROC)GetGLFuncAddress("glValidateProgram");
}
以及我如何初始化窗口
Window::Window(LPCWSTR title, LPCWSTR CLASS_NAME, int h, int w, int x, int y)
: m_hinstance(GetModuleHandle(nullptr))
{
class_name = CLASS_NAME;
WNDCLASS wnd = {};
wnd.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wnd.lpszClassName = CLASS_NAME;
wnd.hInstance = m_hinstance;
wnd.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wnd.hCursor = LoadIcon(NULL, IDC_ARROW);
wnd.hbrBackground = 0;
wnd.lpfnWndProc = WindowProc;
RegisterClass(&wnd);
DWORD windStyle = WS_OVERLAPPEDWINDOW | WS_MINIMIZEBOX | WS_SYSMENU;
height = h;
width = w;
RECT rect;
rect.left = x;
rect.top = y;
rect.right = rect.left + width;
rect.bottom = rect.top + height;
AdjustWindowRect(&rect, windStyle, false);
m_hwnd = CreateWindowEx(0, CLASS_NAME,
title,
windStyle,
rect.left,
rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
NULL,
NULL,
m_hinstance,
NULL
);
}