在底部编辑我已经添加了源文件

我的仅渲染三角形的程序可以正常工作,但是当我使用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函数调整大小。

08-19 12:33