在底部编辑我已经添加了源文件
我的仅渲染三角形的程序可以正常工作,但是当我使用glviewport
函数将其设置为x和y的createwindow尺寸即640和640并在两台不同的计算机(我的笔记本电脑和台式机)上运行相同的程序时
它会导致三角形在台式机上正常显示时在台式计算机上以一定百分比出现在屏幕外,我不再在屏幕上看到完整的三角形,而是一个比屏幕大的三角形,所以它的一部分错了(在顶部有点在右边)
我知道这与设备单元有关,而opengl使用像素
那我该如何纠正呢?
当我从程序中删除glviewport
函数时,它将正确呈现
所以需要做些什么才能纠正这个问题?
从编辑到问题
如您所见,当我要求glViewport与头文件中创建窗口的屏幕具有相同的大小和宽度时(可以通过取消注释将其尝试),它给出的结果是三角形缺少一部分,但是当注释掉它并让其运行时,glViewport函数请求的宽度和高度与它起作用的createWindow尺寸相同,它将给出正确的结果,我要重申的问题是为什么会这样以及如何解决它
下面的源文件:
mainWin.c
#include "mainWin.h"
//main function, point of entry for windows application
//must be present in a windows application
//pass argument hInstance to delcare an instnace of application created
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
MSG Msg; //variable for storing messages retrieved from operating system by using GetMessage
WNDCLASS WndCls;
//initialize window class must be initialized no default class
initWinClass(&WndCls, hInstance);
//Register the application must register application to make it available to other controls
RegisterClass(&WndCls);
//setup dummy context and initialize glew to get function pointers
setupDummyContext(hInstance);
//initialize our real window and setup some context state settings i.e glViewport
initGL(hInstance);
//same basic data(triangle) loading to server side(graphics memory)
loadTri();
//creating shaders and uploading to server side i.e grahics card
createShaders();
//setting context settings
glUseProgram(program);
glClearColor(0.0f, 1.0f, 0.0f, 0.0f);
while (true)
{
while (PeekMessage (&Msg, NULL, 0, 0, PM_REMOVE) > 0) //Or use an if statement
{
TranslateMessage (&Msg);
DispatchMessage (&Msg);
}
if(Msg.message == WM_QUIT){
break;
}
//Here is were all the "animation that isn't used when the user does something" code will go.
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 3); // Starting from vertex 0; 3 vertices total -> 1 triangle
SwapBuffers(hDC);
}
//if quit correctly i.e PostQuitMessage(wParam) this value should be wparam = 0
return Msg.wParam;
}
mainWin.h
#define true 1
#define false 0
#define WIDTH 128
#define HEIGHT 128
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/wglew.h>
#include <GL/gl.h>
GLuint vertex_shader;
GLuint fragment_shader;
GLuint program;
//string concatenation occurs and becomes all one string
char const * vertShad =
//[VERTEX SHADER]
"#version 330 core\n"
"layout(location = 0)in vec3 pos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(pos, 1.0);\n"
"}\n";
char const * fragShad =
//[FRAGMENT SHADER]
"#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(1.0, 0.0, 0.0, 0.7);\n"
"}\n"
;
LPCTSTR ClsName = "OpenGL App";
LPCTSTR WndName = "My Game";
//global variables
HDC hDC;
HGLRC hRC;
HWND hWndMain;
void createShaders();
void loadTri();
void setupPixelFormat(HDC hDC);
void initGlew();
void setupPixelFormatARB();
LRESULT CALLBACK WndProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void setupDummyContext(HINSTANCE hInstance){
HWND hWndF = CreateWindow(ClsName, "FAKE" ,WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_CLIPSIBLINGS,
0, 0, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
//printf("in setup dummy context %x\n", hWndF);
//create a dummy context
HDC hDC = GetDC(hWndF);
//get the device context for window
//An application can only set the pixel format of a window one time.
//note that the pixel format can be set only once for a window,
//so if you decide to change it, you must destroy and re-create the window using createWindow function
//Once a window's pixel format is set, it cannot be changed
setupPixelFormat(hDC); //call our pixel format setup function
//in order to use ARB context creation you create a dummy rendering context
HGLRC tempContext = wglCreateContext(hDC);
wglMakeCurrent(hDC, tempContext);
//only once a dummy context has been created can you load function pointers
initGlew();
wglMakeCurrent(NULL,NULL);
wglDeleteContext(tempContext);
DestroyWindow(hWndF);
}
void initGL(HINSTANCE hInstance){
//adjust the screen to the required size accounting for including borders/styles
RECT r = {0,0,WIDTH,HEIGHT};
DWORD dwstyle = WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_CLIPSIBLINGS;
AdjustWindowRect(&r, dwstyle, false );
printf("width needed for %d client area is %ld ,height needed for %d client area is %ld\n",WIDTH, r.right-r.left, HEIGHT,r.bottom-r.top );
//to create windowless and borderless set style (third option) to WS_BORDER and then use SetWindowLong(hWndMain, GWL_STYLE, 0); //remove all window styles, check MSDN for details
hWndMain = CreateWindow(ClsName, WndName ,dwstyle/*(WS_BORDER )*/,
0, 0, r.right-r.left, r.bottom-r.top, NULL, NULL, hInstance, NULL);
//SetWindowLong(hWndMain, GWL_STYLE, 0); //remove all window styles, check MSDN for details
//printf("in initGL now %x\n", hWndMain);
// Display the window to the user
ShowWindow(hWndMain, SW_SHOW);
//??? not sure yet its use not compulsory
UpdateWindow(hWndMain);
hDC = GetDC(hWndMain);
setupPixelFormatARB();
// If everything went OK
if(hRC) wglMakeCurrent(hDC, hRC);
//printf("client size of window is width %ld and height %ld\n",r.right - r.left, r.bottom - r.top);
printf("OpenGL version string is %s\n", glGetString(GL_VERSION));
GLint OpenGLVersion[3];
glGetIntegerv(GL_MAJOR_VERSION, &OpenGLVersion[0]);
glGetIntegerv(GL_MINOR_VERSION, &OpenGLVersion[1]);
printf("GL Major version %d\nGL Minor Version %d\n", OpenGLVersion[0], OpenGLVersion[1]);
printf("GLSL version is %s \nVendor of OpenGL is %s \nRenderer version is %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION),
glGetString(GL_VENDOR) ,glGetString(GL_RENDERER));
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glViewport(0,0,WIDTH,HEIGHT);
}
void initGlew(){
//set experimental value to true so that all functions can be used
glewExperimental = GL_TRUE;
//initialize glew and get result , check result is not a failure
GLenum err = glewInit();
if(err!=GLEW_OK){
printf("glew failed!!!....");
}
printf("Glew version is %s\n", glewGetString(GLEW_VERSION));
//glClearColor(0,0,0,0); default
}
void initWinClass(PWNDCLASS WndCls, HINSTANCE hInstance){
// Create the application window
//WndCls.cbSize = sizeof(WNDCLASSEX); wndclassex
WndCls->style = CS_HREDRAW | CS_VREDRAW |CS_OWNDC;
//the style member variable specifies the primary operations applied on the window class
//if user moves or changes its size, you would need the window redrawn to get its characteristics
//CS_HREDRAW CS_VREDRAW draw the window vertically and horizontally
WndCls->lpfnWndProc = WndProcedure;
WndCls->cbClsExtra = 0;
WndCls->cbWndExtra = 0;
WndCls->hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndCls->hCursor = LoadCursor(NULL, IDC_ARROW);
WndCls->hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); //cast to HBRUSH
WndCls->lpszMenuName = NULL;
WndCls->lpszClassName = ClsName;
WndCls->hInstance = hInstance;
//WndCls.hIconSm = LoadIcon(NULL, IDI_APPLICATION); wndclassex
}
void setupPixelFormat(HDC hDC){
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize= sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 32;
pfd.iLayerType = PFD_MAIN_PLANE;
int nPixelFormat;
/* Choose best matching format*/
nPixelFormat = ChoosePixelFormat(hDC, &pfd);
if (nPixelFormat == 0) printf("Error in choose pixel format\n");
/* Set the pixel format to the device context of the window which cannot be changed afterwards*/
BOOL bResult = SetPixelFormat(hDC, nPixelFormat, &pfd);
if (!bResult) printf("Error in set pixel format\n");
}
//uses extension function which require a opengl context to be present either default or dummy
void setupPixelFormatARB(){
PIXELFORMATDESCRIPTOR pfd;
//framebuffer pixel format attribs
const int attribList[] =
{
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_COLOR_BITS_ARB, 32,
WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8,
0, //End
};
//context attribs
int attribs[] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
WGL_CONTEXT_PROFILE_MASK_ARB,
WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
//WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
0
};
int pixelFormat;
UINT numFormats;
wglChoosePixelFormatARB(hDC, attribList, NULL, 1, &pixelFormat, &numFormats);
SetPixelFormat(hDC, pixelFormat, &pfd); //pfd is redundant here not used but must be present in function
hRC = wglCreateContextAttribsARB(hDC, 0, attribs);
}
void loadTri(){
// An array of 3 vectors which represents 3 vertices
static const GLfloat verticies[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// This will identify our vertex buffer
GLuint vbo;
// Generate 1 buffer, put the resulting identifier in vertexbuffer
glGenBuffers(1, &vbo);
// The following commands will talk about our 'vertexbuffer' buffer
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// Give our vertices to OpenGL.
glBufferData(GL_ARRAY_BUFFER, sizeof(verticies), verticies, GL_STATIC_DRAW);
// 1st attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
//glDisableVertexAttribArray(0);
}
void createShaders(){
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vertex_shader, 1, &vertShad, NULL);
glShaderSource(fragment_shader, 1, &fragShad, NULL);
glCompileShader(vertex_shader);
//get compilation results
GLint success = -1;
GLint maxLength = 0;
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
if(success==GL_FALSE){
printf("error in vertex shader\n");
maxLength = 0;
glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &maxLength);
char infoLog[maxLength];
glGetShaderInfoLog(vertex_shader, maxLength, &maxLength, &infoLog[0]);
printf("%s", infoLog);
}
success = -1;
glCompileShader(fragment_shader);
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
if(success==GL_FALSE){
printf("error in fragment shader\n");
maxLength = 0;
glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &maxLength);
char infoLog2[maxLength];
glGetShaderInfoLog(fragment_shader, maxLength, &maxLength, &infoLog2[0]);
printf("%s", infoLog2);
}
//if(glGetShaderiv(fragment_shader,GL_COMPILE_STATUS)!=GL_TRUE)
// printf("error in fragment shader");
//get compilation results with glGetShaderiv(GL_COMPILE_STATUS) if GL_TRUE returned then successfull compilation
//If the compilation
//failed, you can determine what the error was by retrieving the compilation
//log. glGetShaderInfoLog() will return an implementation-specific set of
//messages describing the compilation errors. The current size of the error
//log can be queried by calling glGetShaderiv() with an argument of
//GL_INFO_LOG_LENGTH
program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
GLint isLinked = 0;
glGetProgramiv(program, GL_LINK_STATUS, (int *)&isLinked);
if(isLinked == GL_FALSE){
printf("did not link\n");
}
}
LRESULT CALLBACK WndProcedure(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
//printf("the message %d memory address is %x\n", Msg, hWnd);
//printf("in wnd procedure function\n");
switch(Msg)
{
//this is the favourite message you can use to perform any early processing that you want to make
//sure happens before most things show up you can use this message to initialize anything in your application
//The window procedure of the new window receives this message after the window is created,
//but before the window becomes visible.
//will only run once on creation
case WM_CREATE:
break;
//minimum application needs to deal with:
//wm_destroy message to close window and default case for non registered default messaging processing
//otherwise hanging or not reaching event queue
case WM_DESTROY: //Sent when a window is being destroyed.
//It is sent to the window procedure of the window being destroyed after the window is removed from the screen.
//you can use this message to deconstruct the window once the user requests to destroy the window
//printf("in wnd prcd %x\n", hWnd);
//condition set here make sure which window sent the close message
//make it terminate the main loop by closing of the correct window
//or make it terminate main loop by being any window other then the
//dummy window by keeping a copy of its pointer
if(hWndMain==hWnd){
wglMakeCurrent(hDC,NULL); //deselect rendering context
wglDeleteContext(hRC); //delete rendering context
PostQuitMessage(0);
}
//The PostQuitMessage function posts a WM_QUIT message to the thread's message queue and returns immediately
//send wm_quit message
//Indicates a request to terminate an application, and is generated when the application calls the PostQuitMessage function.
//This message causes the GetMessage function to return zero.
//printf("Window destroyed goodbye...bye\n");
break;
//this must exist to process left over messages or the application will hang or will not go forward through the
//event queue and the while loop will
default:
// Process the left-over messages and messages that are not dealt with
return DefWindowProc(hWnd, Msg, wParam, lParam);
break;
}
// If something was not done, let it go
return 0;
}
编译:
gcc mainWin.c -lopengl32 -lglew32 -lgdi32
最佳答案
大概您创建了带有标题和边框的窗口。但是CreateWindow
使用的大小适用于整个窗口,包括边框。为了克服这个问题,您必须使用客户区域的大小(即窗口的不包括边框的区域)作为glViewport
调用的参数。要获取窗口的客户端区域,请使用GetClientRect
函数。这将使您的视口小于您在CreateWindow
中指定的尺寸。如果您确实要根据特定的客户区域大小设置窗口的大小,则应使用AdjustWindowRect
函数调整大小。