openGL之API学习(一)gl_Position

本文详细解析了gl_Position在顶点着色器中的应用,它作为输入和输出参数,负责将顶点坐标转换到裁剪空间,确保在[-1,1]区间内的片元能够被正确绘制。

默认是归一化的裁剪空间坐标(xyz各个维度的范围为-1到1)

仅能在顶点着色器中使用,既是输入也是输出

gl_Position赋值范围就是float的取值范围(32位),只不过只有[-1,1]区间的片元被绘制

它是vec4类型的,不能重声明为dvec4等类型

#include <windows.h> #include <GL/gl.h> #include <GL/glu.h> #include <stdio.h> #include<math.h> // 窗口过程函数 LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, msg, wParam, lParam); } return 0; } // 设置像素格式 BOOL SetupPixelFormat(HDC hdc) { PIXELFORMATDESCRIPTOR pfd; int pixelformat; ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR)); pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 32; pfd.cDepthBits = 24; pfd.iLayerType = PFD_MAIN_PLANE; pixelformat = ChoosePixelFormat(hdc, &pfd); if (pixelformat == 0) { return FALSE; } if (SetPixelFormat(hdc, pixelformat, &pfd) == FALSE) { return FALSE; } return TRUE; } // 加载纹理 GLuint loadTexture() { GLuint textureID; glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); // 简单的纹理设置,这里可以替换为实际的纹理加载 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); unsigned char data[] = {255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255}; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); return textureID; } // 绘制方块 void drawCube() { glBegin(GL_QUADS); // 前面 glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5f, -0.5f, 0.5f); glTexCoord2f(1.0f, 0.0f); glVertex3f(0.5f, -0.5f, 0.5f); glTexCoord2f(1.0f, 1.0f); glVertex3f(0.5f, 0.5f, 0.5f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5f, 0.5f, 0.5f); // 后面 glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5f, -0.5f, -0.5f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5f, 0.5f, -0.5f); glTexCoord2f(1.0f, 1.0f); glVertex3f(0.5f, 0.5f, -0.5f); glTexCoord2f(1.0f, 0.0f); glVertex3f(0.5f, -0.5f, -0.5f); // 顶面 glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5f, 0.5f, -0.5f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5f, 0.5f, 0.5f); glTexCoord2f(1.0f, 1.0f); glVertex3f(0.5f, 0.5f, 0.5f); glTexCoord2f(1.0f, 0.0f); glVertex3f(0.5f, 0.5f, -0.5f); // 底面 glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5f, -0.5f, -0.5f); glTexCoord2f(1.0f, 0.0f); glVertex3f(0.5f, -0.5f, -0.5f); glTexCoord2f(1.0f, 1.0f); glVertex3f(0.5f, -0.5f, 0.5f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5f, -0.5f, 0.5f); // 左面 glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5f, -0.5f, -0.5f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5f, -0.5f, 0.5f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.5f, 0.5f, 0.5f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.5f, 0.5f, -0.5f); // 右面 glTexCoord2f(0.0f, 0.0f); glVertex3f(0.5f, -0.5f, -0.5f); glTexCoord2f(1.0f, 0.0f); glVertex3f(0.5f, 0.5f, -0.5f); glTexCoord2f(1.0f, 1.0f); glVertex3f(0.5f, 0.5f, 0.5f); glTexCoord2f(0.0f, 1.0f); glVertex3f(0.5f, -0.5f, 0.5f); glEnd(); } // 玩家位置和视角 float playerX = 0.0f; float playerY = 1.0f; float playerZ = 5.0f; float playerYaw = 0.0f; float playerPitch = 0.0f; // 处理键盘输入 void handleKeyboardInput() { if (GetAsyncKeyState(VK_UP) & 0x8000) { playerX += sinf(playerYaw * 3.1415926f / 180.0f) * 0.1f; playerZ -= cosf(playerYaw * 3.1415926f / 180.0f) * 0.1f; } if (GetAsyncKeyState(VK_DOWN) & 0x8000) { playerX -= sinf(playerYaw * 3.1415926f / 180.0f) * 0.1f; playerZ += cosf(playerYaw * 3.1415926f / 180.0f) * 0.1f; } if (GetAsyncKeyState(VK_LEFT) & 0x8000) { playerYaw -= 1.0f; } if (GetAsyncKeyState(VK_RIGHT) & 0x8000) { playerYaw += 1.0f; } } // 处理鼠标输入 void handleMouseInput(HWND hwnd) { POINT mousePos; GetCursorPos(&mousePos); ScreenToClient(hwnd, &mousePos); int centerX = 800 / 2; int centerY = 600 / 2; int dx = mousePos.x - centerX; int dy = mousePos.y - centerY; playerYaw += dx * 0.1f; playerPitch += dy * 0.1f; // 限制视角 if (playerPitch > 89.0f) playerPitch = 89.0f; if (playerPitch < -89.0f) playerPitch = -89.0f; SetCursorPos(centerX, centerY); } // 初始化光照 void initLighting() { GLfloat light_position[] = {1.0f, 1.0f, 1.0f, 0.0f}; GLfloat light_diffuse[] = {1.0f, 1.0f, 1.0f, 1.0f}; GLfloat light_specular[] = {1.0f, 1.0f, 1.0f, 1.0f}; glLightfv(GL_LIGHT0, GL_POSITION, light_position); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("MinecraftLike"); HWND hwnd; MSG msg; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, TEXT("Minecraft Like Project"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); HDC hdc = GetDC(hwnd); if (!SetupPixelFormat(hdc)) { MessageBox(hwnd, TEXT("Failed to set pixel format!"), TEXT("Error"), MB_OK | MB_ICONERROR); return 0; } HGLRC hglrc = wglCreateContext(hdc); wglMakeCurrent(hdc, hglrc); // OpenGL 初始化 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f, 800.0f / 600.0f, 0.1f, 100.0f); glMatrixMode(GL_MODELVIEW); // 加载纹理 GLuint textureID = loadTexture(); // 初始化光照 initLighting(); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); handleKeyboardInput(); handleMouseInput(hwnd); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); // 设置视角 glRotatef(-playerPitch, 1.0f, 0.0f, 0.0f); glRotatef(-playerYaw, 0.0f, 1.0f, 0.0f); glTranslatef(-playerX, -playerY, -playerZ); // 绑定纹理 glBindTexture(GL_TEXTURE_2D, textureID); // 绘制方块 for (int x = -5; x < 5; ++x) { for (int z = -5; z < 5; ++z) { glPushMatrix(); glTranslatef(x, 0.0f, z); drawCube(); glPopMatrix(); } } SwapBuffers(hdc); } wglMakeCurrent(NULL, NULL); wglDeleteContext(hglrc); ReleaseDC(hwnd, hdc); return msg.wParam; } 有什么问题
最新发布
08-30
以下是给定的使用 Windows APIOpenGL 编写的类 Minecraft 项目代码可能存在的问题: ### 纹理相关问题 - **纹理坐标设置**:纹理坐标用于指定纹理图像中每个顶点对应的位置。在 `drawCube` 函数中,纹理坐标设置可能存在错误,导致只有个面显示纹理,其他面显示异常。虽然代码中纹理坐标设置看起来正确,但可能由于其他因素影响,如纹理加载失败或纹理参数设置不当,导致纹理显示异常。 ```c // 绘制方块 void drawCube() { glBegin(GL_QUADS); // 前面 glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5f, -0.5f, 0.5f); glTexCoord2f(1.0f, 0.0f); glVertex3f(0.5f, -0.5f, 0.5f); glTexCoord2f(1.0f, 1.0f); glVertex3f(0.5f, 0.5f, 0.5f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5f, 0.5f, 0.5f); // 其他面... glEnd(); } ``` - **纹理加载**:在 `loadTexture` 函数中,使用了简单的纹理数据进行测试。如果要加载实际的纹理图像,需要使用更复杂的纹理加载方法,如使用第三方库(如 SOIL)来加载纹理文件。当前的纹理数据可能过于简单,导致显示效果不佳。 ```c // 加载纹理 GLuint loadTexture() { GLuint textureID; glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); // 简单的纹理设置,这里可以替换为实际的纹理加载 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); unsigned char data[] = {255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255}; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); return textureID; } ``` ### 光照相关问题 - **法线设置**:光照模型依赖于表面法线来计算光照效果。在 `drawCube` 函数中,没有为每个面设置法线,可能导致只有部分面被照亮,看起来只有个彩色面。需要为每个面设置正确的法线。 ```c // 绘制方块 void drawCube() { // 前面 glBegin(GL_QUADS); glNormal3f(0.0f, 0.0f, 1.0f); // 设置前面的法线 glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5f, -0.5f, 0.5f); glTexCoord2f(1.0f, 0.0f); glVertex3f(0.5f, -0.5f, 0.5f); glTexCoord2f(1.0f, 1.0f); glVertex3f(0.5f, 0.5f, 0.5f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5f, 0.5f, 0.5f); glEnd(); // 其他面... } ``` - **光照参数设置**:在 `initLighting` 函数中,光照参数的设置可能不够合理,导致光照效果不佳。例如,光照的位置、颜色和强度等参数可能需要调整。 ```c // 初始化光照 void initLighting() { GLfloat light_position[] = {1.0f, 1.0f, 1.0f, 0.0f}; GLfloat light_diffuse[] = {1.0f, 1.0f, 1.0f, 1.0f}; GLfloat light_specular[] = {1.0f, 1.0f, 1.0f, 1.0f}; glLightfv(GL_LIGHT0, GL_POSITION, light_position); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); } ``` ### 视角和旋转问题 - **视角设置**:在主循环中,视角的设置和旋转操作可能会影响物体的最终显示效果。如果旋转角度过大或视角设置不当,可能会使其他面被遮挡。需要调整视角和旋转参数,确保能够看到所有面。 ```c // 设置视角 glRotatef(-playerPitch, 1.0f, 0.0f, 0.0f); glRotatef(-playerYaw, 0.0f, 1.0f, 0.0f); glTranslatef(-playerX, -playerY, -playerZ); ``` - **旋转控制**:在 `handleKeyboardInput` 和 `handleMouseInput` 函数中,旋转控制可能过于灵敏或不精确,导致视角旋转不稳定。需要调整旋转的步长,使视角旋转更加平滑。 ```c // 处理键盘输入 void handleKeyboardInput() { if (GetAsyncKeyState(VK_UP) & 0x8000) { playerX += sinf(playerYaw * 3.1415926f / 180.0f) * 0.1f; playerZ -= cosf(playerYaw * 3.1415926f / 180.0f) * 0.1f; } if (GetAsyncKeyState(VK_DOWN) & 0x8000) { playerX -= sinf(playerYaw * 3.1415926f / 180.0f) * 0.1f; playerZ += cosf(playerYaw * 3.1415926f / 180.0f) * 0.1f; } if (GetAsyncKeyState(VK_LEFT) & 0x8000) { playerYaw -= 1.0f; // 调整旋转步长 } if (GetAsyncKeyState(VK_RIGHT) & 0x8000) { playerYaw += 1.0f; // 调整旋转步长 } } ``` ### 深度缓冲问题 - **深度缓冲启用和清除**:虽然代码中启用了深度测试并在每帧开始时清除了深度缓冲,但可能由于其他因素影响,如深度缓冲的精度设置不当,导致深度测试出现问题。需要确保深度缓冲的精度设置正确。 ```c // 初始化时启用深度测试 glEnable(GL_DEPTH_TEST); // 每帧开始时清除深度缓冲和颜色缓冲 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); ``` ### 面剔除问题 - **面剔除设置**:OpenGL 可以进行面剔除操作,默认情况下,背面(顺时针顶点顺序的面)会被剔除。如果立方体的某些面的顶点顺序设置错误,可能会导致这些面被剔除,从而只有个面可见。需要确保所有面的顶点顺序为逆时针。 ```c // 绘制方块 void drawCube() { // 确保每个面的顶点顺序为逆时针 glBegin(GL_QUADS); // 前面 glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5f, -0.5f, 0.5f); glTexCoord2f(1.0f, 0.0f); glVertex3f(0.5f, -0.5f, 0.5f); glTexCoord2f(1.0f, 1.0f); glVertex3f(0.5f, 0.5f, 0.5f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5f, 0.5f, 0.5f); // 其他面... glEnd(); } ``` ### 性能问题 - **绘制效率**:在主循环中,使用 `glBegin` 和 `glEnd` 进行绘制,这种方式的绘制效率较低。可以考虑使用更高效的绘制方式,如顶点数组对象(VAO)和顶点缓冲对象(VBO)。 ```c // 示例:使用 VBO 绘制立方体 GLuint vbo; glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 绘制时 glBindBuffer(GL_ARRAY_BUFFER, vbo); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); glDrawArrays(GL_QUADS, 0, 24); glDisableVertexAttribArray(0); ``` ### 资源管理问题 - **纹理和上下文管理**:在程序结束时,需要正确释放纹理和 OpenGL 上下文资源,避免内存泄漏。代码中已经对 OpenGL 上下文进行了释放,但可以添加对纹理资源的释放操作。 ```c // 释放纹理资源 glDeleteTextures(1, &textureID); wglMakeCurrent(NULL, NULL); wglDeleteContext(hglrc); ReleaseDC(hwnd, hdc); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值