在底部编辑我添加了源文件
我只是渲染三角形的程序可以正常工作,但是当我使用glviewport
函数将其设置为x和y的创建窗口尺寸(即640和640)并在两台不同的计算机上运行相同的程序时(我的笔记本电脑)和我的桌面)
它导致我的桌面计算机上的三角形在屏幕上移动了一定百分比,而它在我的笔记本电脑上正确呈现,我不再在屏幕上显示完整的三角形,而是一个比屏幕大小更大的三角形所以a它的一部分是mising(有点在顶部,有点在右边)
我知道这与设备单元有一些关系,而opengl使用像素
所以我该如何纠正这个?
当我从程序中删除glviewport
函数时,它会正确呈现
那么需要做些什么来纠正这个问题呢?
从编辑到问题
正如你所看到的那样,当我请求glViewport与头文件中创建窗口的屏幕大小和宽度相同时(你可以通过取消注释来尝试它),它会给出三角形缺失的结果一部分,但是当它被注释掉并且没有glViewport函数请求与它工作的createWindow维度相同的宽度和高度时,它会给出正确的结果,我要重申的问题是为什么会发生这种情况以及如何解决它< / p>
以下源文件:
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
答案 0 :(得分:1)
据推测,您创建了带有标题和边框的窗口。但CreateWindow
的大小用于整个窗口,包括边框。要解决此问题,您必须使用客户区的大小(即除边框之外的窗口区域)作为glViewport
调用的参数。要获取窗口的客户区,请使用GetClientRect
函数。这将为您提供一个小于的视口您在CreateWindow
中指定的大小。如果您真的想根据特定的客户区大小设置窗口的大小,那么您应该使用AdjustWindowRect
函数调整大小。