30.opengl高级光照

一、原理介绍

HDR:High Dynamic Range, 高动态范围
LDR: Low Dynamic Range, 低动态范围

1. 为什么有HDR?

过度曝光

屏幕显示颜色会约束到[0,1]之间,如果场景中有很多超过1的color值,比如10、15、100都会约束到1,体现不出真实的纹理。

HDR技术通过一个颜色映射,把大范围的值缩放到一个小范围内。尽量体现场景中高亮度和低亮度的纹理细节。HDR映射有很多算法,没有绝对的优劣,只有侧重,有的侧重高亮细节,有的侧重灰暗细节

HDR映射

2. 实现流程
  • 把场景渲染到自定义的帧缓冲,帧缓冲可以设置color的取值范围,默认的窗口缓冲不支持设置精度,默认是一个字节8位,自定义缓冲可以设置16或32位浮点类型。另外,即使默认的缓冲支持设置数据类型,最好也通过自定义帧缓冲生成一张2维纹理,最后只需要针对2维纹理做映射计算,性能上有数量级的提升
  • 切回到默认缓冲,把帧缓冲渲染到默认窗口,同时,在shader中增加Reinhard(混合渲染)色调映射算法,调整颜色范围
3.核心代码说明,完整代码在文末

3.1 设计一个拉长的立方体,注意法线要朝里边,因为我们要从里面观察纹理

1 // render tunne; 2 model = glm::mat4(1.0f); 3 model = glm::translate(model, glm::vec3(0.0f,0.0f, 25.0)); 4// 按原教程的缩放有点问题 5// model = glm::scale(model, glm::vec3(5.0f, 5.0f, 55.0f)); 6 model = glm::scale(model, glm::vec3(2.5f, 2.5f, 27.5f)); 7 shader.setMat4("model", model); 8 shader.setBool("inverse_normals", true);

3.2 渲染到帧缓冲,帧缓冲的代码不复杂,但是有点啰嗦,这里不贴了,参看文末代码,有一点注意,原教程中没有设置纹理为“0”,看起来默认为0的纹理,不用设置?

1// shader.use(); 2// shader.setInt("diffuseTexture", 0); 3// hdrShader.use(); 4// hdrShader.setInt("hdrBuffer", 0);

3.3 绘制到默认窗口,也不复杂:略
3.4 渲染到默认窗口的着色器中,有个最简单的算法,把所有颜色约束到[0,1]之间,突出低亮度部分,兼顾高亮度部分

1 // reinhard 2 vec3 result = hdrColor / (hdrColor + vec3(1.0));

算法函数

4. 实现效果

HDR效果

二、曝光算法

通过曝光度来控制映射曲线

上面讲的混合渲染算法简单通用,但是没有个特性化的参数调整,比如,我就想整体偏亮一点,想曝光高一点呢。实现算法在片段着色其中,算法公式:

曝光函数

曝光度越大,映射曲线越陡峭,场景越亮,缺点是在非常高亮的点非常接近,体现不出纹理的细节差别,真实的摄影后期处理中,要根据个人需求的侧重点,不断调参。

曝光度= 1

曝光度 = 6

实现效果

代码改动量不大,基于上面的混合渲染,修改下片段着色器中的color result计算即可

曝光度变化

1void main() 2{ 3 const float gamma = 2.2; 4 vec3 hdrColor = texture(hdrBuffer, TexCoords).rgb; 5 6 // reinhard 7 //vec3 result = hdrColor / (hdrColor + vec3(1.0)); 8 9 vec3 result = vec3(1.0) - exp(-hdrColor * exposure); 10 // also gamma correct while we're at it 11 result = pow(result, vec3(1.0 / gamma)); 12 color = vec4(result, 1.0f); 13}

三、完整代码

HDR .vs
1#version 330 core 2layout (location = 0) in vec3 position; 3layout (location = 1) in vec2 texCoords; 4 5out vec2 TexCoords; 6 7void main() 8{ 9 gl_Position = vec4(position, 1.0f); 10 TexCoords = texCoords; 11}
HDR .fs
1#version 330 core 2out vec4 color; 3in vec2 TexCoords; 4 5uniform sampler2D hdrBuffer; 6uniform float exposure; 7uniform bool hdr; 8 9void main() 10{ 11 const float gamma = 2.2; 12 vec3 hdrColor = texture(hdrBuffer, TexCoords).rgb; 13 14 // reinhard 15 vec3 result = hdrColor / (hdrColor + vec3(1.0)); 16 17 // vec3 result = vec3(1.0) - exp(-hdrColor * exposure); 18 // also gamma correct while we're at it 19 result = pow(result, vec3(1.0 / gamma)); 20 color = vec4(result, 1.0f); 21}
默认窗口的渲染 .vs 没有特殊逻辑
1#version 330 core 2layout (location = 0) in vec3 position; 3layout (location = 1) in vec2 texCoords; 4 5out vec2 TexCoords; 6 7void main() 8{ 9 gl_Position = vec4(position, 1.0f); 10 TexCoords = texCoords; 11}
默认窗口的渲染 .fs 最核心的逻辑
1#version 330 core 2out vec4 color; 3in vec2 TexCoords; 4 5uniform sampler2D hdrBuffer; 6uniform float exposure; 7uniform bool hdr; 8 9void main() 10{ 11 const float gamma = 2.2; 12 vec3 hdrColor = texture(hdrBuffer, TexCoords).rgb; 13 14 // reinhard 15 vec3 result = hdrColor / (hdrColor + vec3(1.0)); 16 17 // vec3 result = vec3(1.0) - exp(-hdrColor * exposure); 18 // also gamma correct while we're at it 19 result = pow(result, vec3(1.0 / gamma)); 20 color = vec4(result, 1.0f); 21}
主程序
1#include <glad/glad.h> 2#include <GLFW/glfw3.h> 3#define STB_IMAGE_IMPLEMENTATION 4#include "stb_image.h" 5 6#include <glm/glm.hpp> 7#include <glm/gtc/matrix_transform.hpp> 8#include <glm/gtc/type_ptr.hpp> 9 10#include "Shader.h" 11#include "camera.h" 12#include "model.h" 13 14#include <iostream> 15 16void framebuffer_size_callback(GLFWwindow* window, int width, int height); 17void mouse_callback(GLFWwindow* window, double xpos, double ypos); 18void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); 19void processInput(GLFWwindow *window); 20unsigned int loadTexture(const char *path); 21unsigned int loadCubemap(vector<std::string> faces); 22void renderScene (const Shader &shader); 23void renderCube(); 24void RenderQuad(); 25 26// settings 27const unsigned int SCR_WIDTH = 800; 28const unsigned int SCR_HEIGHT = 600; 29bool blinn = false; 30bool blinnKeyPressed = false; 31bool gammaEnabled = true; 32bool gammaKeyPressed = false; 33 34// camera 35Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); 36float lastX = (float)SCR_WIDTH / 2.0; 37float lastY = (float)SCR_HEIGHT / 2.0; 38bool firstMouse = true; 39 40// timing 41float deltaTime = 0.0f; 42float lastFrame = 0.0f; 43 44bool hdr = true; //change with 'space' 45float exposure = 1.0f; // change with Q and E 46 47unsigned int woodTexture; 48 49int main() 50{ 51 // glfw: initialize and configure 52 // ------------------------------ 53 glfwInit(); 54 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 55 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 56 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 57 58#ifdef __APPLE__ 59 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 60#endif 61 62 // glfw window creation 63 // -------------------- 64 GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "天哥学opengl", NULL, NULL); 65 if (window == NULL) 66 { 67 std::cout << "Failed to create GLFW window" << std::endl; 68 glfwTerminate(); 69 return -1; 70 } 71 glfwMakeContextCurrent(window); 72 glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); 73 glfwSetCursorPosCallback(window, mouse_callback); 74 glfwSetScrollCallback(window, scroll_callback); 75 76 // tell GLFW to capture our mouse 77// glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); 78 79 // glad: load all OpenGL function pointers 80 // --------------------------------------- 81 if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) 82 { 83 std::cout << "Failed to initialize GLAD" << std::endl; 84 return -1; 85 } 86 87// glPolygonMode(GL_FRONT_AND_BACK ,GL_LINE ); 88 89 // configure global opengl state 90 // ----------------------------- 91 glEnable(GL_DEPTH_TEST); 92 93 // build and compile shaders 94 // ------------------------- 95 Shader shader("1.lighting.vs", "1.lighting.fs"); 96 Shader hdrShader("1.colors.vs", "1.colors.fs"); 97 98 // Light sources 99 // Positions 100 std::vector<glm::vec3> lightPositions; 101 lightPositions.push_back(glm::vec3(0.0f, 0.0f, 49.5f)); //back light 102 lightPositions.push_back(glm::vec3(-1.4f, -1.9f, 9.0f)); 103 lightPositions.push_back(glm::vec3(0.0f, -1.8f, 4.0f)); 104 lightPositions.push_back(glm::vec3(0.8f, -1.7f, 6.0f)); 105 106 // -Colors 107 std::vector<glm::vec3> lightColors; 108 lightColors.push_back(glm::vec3(200.0f, 200.0f, 200.0f)); 109 lightColors.push_back(glm::vec3(0.1f, 0.0f, 0.0f)); 110 lightColors.push_back(glm::vec3(0.0f, 0.0f, 0.2f)); 111 lightColors.push_back(glm::vec3(0.0f, 0.1f, 0.0f)); 112 113 // Load textures 114 woodTexture = loadTexture("resource/wood.png"); 115 116 unsigned int hdrFBO; 117 glGenFramebuffers(1, &hdrFBO); 118 119 unsigned int colorBuffer; 120 glGenTextures(1, &colorBuffer); 121 glBindTexture(GL_TEXTURE_2D, colorBuffer); 122 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGBA, GL_FLOAT, NULL); 123 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 124 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 125 126 // create depth buffer (renderbuffer) 127 unsigned int rboDepth; 128 glGenRenderbuffers(1, &rboDepth); 129 glBindRenderbuffer(GL_RENDERBUFFER, rboDepth); 130 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, SCR_WIDTH, SCR_HEIGHT); 131 // - Attach buffers 132 glBindFramebuffer(GL_FRAMEBUFFER, hdrFBO); 133 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBuffer,0); 134 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboDepth); 135 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { 136 std::cout << "Framebuffer not complete!" << std::endl; 137 } 138 glBindFramebuffer(GL_FRAMEBUFFER, 0); 139 140 glClearColor(0.1f, 0.1f, 0.1f, 1.0f); 141 142// shader.use(); 143// shader.setInt("diffuseTexture", 0); 144// hdrShader.use(); 145// hdrShader.setInt("hdrBuffer", 0); 146 147 // render loop 148 // ----------- 149 while (!glfwWindowShouldClose(window)) 150 { 151 float currentFrame = glfwGetTime(); 152 deltaTime = currentFrame - lastFrame; 153 lastFrame = currentFrame; 154 processInput(window); 155 156 glBindFramebuffer(GL_FRAMEBUFFER, hdrFBO); 157 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 158 159 glm::mat4 projection = glm::perspective(camera.Zoom, (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); 160 glm::mat4 view = camera.GetViewMatrix(); 161 glm::mat4 model; 162 163 shader.use(); 164 shader.setMat4("projection", projection); 165 shader.setMat4("view", view); 166 glActiveTexture(GL_TEXTURE0); 167 glBindTexture(GL_TEXTURE_2D, woodTexture); 168 169 // set lighting uniforms 170 for (unsigned int i = 0; i < lightPositions.size(); i++) { 171 shader.setVec3("lights[" + std::to_string(i) + "].Position", lightPositions[i]); 172 shader.setVec3("lights[" + std::to_string(i) + "].Color", lightColors[i]); 173 } 174 175 shader.setVec3("viewPos", camera.Position); 176 177 // render tunne; 178 model = glm::mat4(1.0f); 179 model = glm::translate(model, glm::vec3(0.0f,0.0f, 25.0)); 180// model = glm::scale(model, glm::vec3(5.0f, 5.0f, 55.0f)); 181 model = glm::scale(model, glm::vec3(2.5f, 2.5f, 27.5f)); 182 183 shader.setMat4("model", model); 184 shader.setBool("inverse_normals", true); 185 renderCube(); 186 glBindFramebuffer(GL_FRAMEBUFFER, 0); 187 188 // 2. Now render floating point colorbuffer to 2D quad and tonemap HDR colors to default framebuffer's (clamped) color range 189 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 190 hdrShader.use(); 191 glActiveTexture(GL_TEXTURE0); 192 glBindTexture(GL_TEXTURE_2D, colorBuffer); 193 hdrShader.setInt("hdr", hdr); 194 hdrShader.setFloat("exposure", exposure); 195 RenderQuad(); 196// std::cout << "exposure: " << exposure << std::endl; 197 198 // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) 199 // ------------------------------------------------------------------------------- 200 glfwSwapBuffers(window); 201 glfwPollEvents(); 202 } 203 204 // optional: de-allocate all resources once they've outlived their purpose: 205 // ------------------------------------------------------------------------ 206 glfwTerminate(); 207 return 0; 208} 209 210// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly 211// --------------------------------------------------------------------------------------------------------- 212 213bool startRecord = false; 214 215void processInput(GLFWwindow *window) 216{ 217 if (glfwGetKey(window, GLFW_KEY_B) == GLFW_PRESS && !gammaKeyPressed) 218 { 219 gammaEnabled = !gammaEnabled; 220 gammaKeyPressed = true; 221 } 222 if (glfwGetKey(window, GLFW_KEY_B) == GLFW_RELEASE) 223 { 224 gammaKeyPressed = false; 225 } 226 if (glfwGetKey(window, GLFW_KEY_Y)) 227 { 228 std::cout << "Y" << std::endl; 229 startRecord = true; 230 firstMouse = true; 231 } 232 233 if (glfwGetKey(window, GLFW_KEY_N)) 234 { 235 std::cout << "N" << std::endl; 236 237 startRecord = false; 238 } 239 240 if (startRecord) { 241 return; 242 } 243 244 if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) 245 glfwSetWindowShouldClose(window, true); 246 247 if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) 248 camera.ProcessKeyboard(FORWARD, deltaTime); 249 if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) 250 camera.ProcessKeyboard(BACKWARD, deltaTime); 251 if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) 252 camera.ProcessKeyboard(LEFT, deltaTime); 253 if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) 254 camera.ProcessKeyboard(RIGHT, deltaTime); 255 if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS) 256 exposure -= 0.5 * deltaTime; 257 if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS) 258 exposure += 0.5 * deltaTime; 259 260 if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS && !gammaKeyPressed) 261 { 262 hdr = !hdr; 263 gammaKeyPressed = true; 264 } 265 if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_RELEASE) 266 { 267 gammaKeyPressed = false; 268 } 269} 270 271// glfw: whenever the window size changed (by OS or user resize) this callback function executes 272// --------------------------------------------------------------------------------------------- 273void framebuffer_size_callback(GLFWwindow* window, int width, int height) 274{ 275 // make sure the viewport matches the new window dimensions; note that width and 276 // height will be significantly larger than specified on retina displays. 277 glViewport(0, 0, width, height); 278} 279 280// glfw: whenever the mouse moves, this callback is called 281// ------------------------------------------------------- 282void mouse_callback(GLFWwindow* window, double xpos, double ypos) 283{ 284// std::cout << "xpos : " << xpos << std::endl; 285// std::cout << "ypos : " << ypos << std::endl; 286 287 if (startRecord) { 288 return; 289 } 290 291 if (firstMouse) 292 { 293 lastX = xpos; 294 lastY = ypos; 295 firstMouse = false; 296 } 297 298 float xoffset = xpos - lastX; 299 float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top 300 301 lastX = xpos; 302 lastY = ypos; 303 304// std::cout << "xoffset : " << xoffset << std::endl; 305// std::cout << "yoffset : " << yoffset << std::endl; 306 307 camera.ProcessMouseMovement(xoffset, yoffset); 308} 309 310// glfw: whenever the mouse scroll wheel scrolls, this callback is called 311// ---------------------------------------------------------------------- 312void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) 313{ 314 camera.ProcessMouseScroll(yoffset); 315} 316 317// utility function for loading a 2D texture from file 318// --------------------------------------------------- 319unsigned int loadTexture(char const * path) 320{ 321 unsigned int textureID; 322 glGenTextures(1, &textureID); 323 324 int width, height, nrComponents; 325 unsigned char *data = stbi_load(path, &width, &height, &nrComponents, 0); 326 if (data) 327 { 328 GLenum format; 329 if (nrComponents == 1) 330 format = GL_RED; 331 else if (nrComponents == 3) 332 format = GL_RGB; 333 else if (nrComponents == 4) 334 format = GL_RGBA; 335 336 glBindTexture(GL_TEXTURE_2D, textureID); 337 glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); 338 glGenerateMipmap(GL_TEXTURE_2D); 339 340 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 341 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 342 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 343 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 344 345 stbi_image_free(data); 346 } 347 else 348 { 349 std::cout << "Texture failed to load at path: " << path << std::endl; 350 stbi_image_free(data); 351 } 352 353 return textureID; 354} 355 356 357unsigned int loadCubemap(vector<std::string> faces) 358{ 359 unsigned int textureID; 360 glGenTextures(1, &textureID); 361 glBindTexture(GL_TEXTURE_CUBE_MAP, textureID); 362 363 int width, height, nrChannels; 364 for (unsigned int i = 0; i < faces.size(); i++) { 365 unsigned char *data = stbi_load(faces[i].c_str(), &width, &height, &nrChannels, 0); 366 367 if (data) 368 { 369 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); 370 stbi_image_free(data); 371 } 372 else 373 { 374 std::cout << "Cubemap texture failed to load at path: " << faces[i] << std::endl; 375 stbi_image_free(data); 376 } 377 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 378 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 379 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 380 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 381 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 382 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); 383 } 384 385 return textureID; 386} 387 388void renderScene(const Shader &shader) 389{ 390 // room cube 391 glm::mat4 model = glm::mat4(1.0f); 392 model = glm::scale(model, glm::vec3(5.0f)); 393 shader.setMat4("model", model); 394 glDisable(GL_CULL_FACE); // note that we disable culling here since we render 'inside' the cube instead of the usual 'outside' which throws off the normal culling methods. 395 shader.setInt("reverse_normals", 1); // A small little hack to invert normals when drawing cube from the inside so lighting still works. 396 renderCube(); 397 shader.setInt("reverse_normals", 0); // and of course disable it 398 glEnable(GL_CULL_FACE); 399 // cubes 400 model = glm::mat4(1.0f); 401 model = glm::translate(model, glm::vec3(4.0f, -3.5f, 0.0)); 402 model = glm::scale(model, glm::vec3(0.5f)); 403 shader.setMat4("model", model); 404 renderCube(); 405 model = glm::mat4(1.0f); 406 model = glm::translate(model, glm::vec3(2.0f, 3.0f, 1.0)); 407 model = glm::scale(model, glm::vec3(0.75f)); 408 shader.setMat4("model", model); 409 renderCube(); 410 model = glm::mat4(1.0f); 411 model = glm::translate(model, glm::vec3(-3.0f, -1.0f, 0.0)); 412 model = glm::scale(model, glm::vec3(0.5f)); 413 shader.setMat4("model", model); 414 renderCube(); 415 model = glm::mat4(1.0f); 416 model = glm::translate(model, glm::vec3(-1.5f, 1.0f, 1.5)); 417 model = glm::scale(model, glm::vec3(0.5f)); 418 shader.setMat4("model", model); 419 renderCube(); 420 model = glm::mat4(1.0f); 421 model = glm::translate(model, glm::vec3(-1.5f, 2.0f, -3.0)); 422 model = glm::rotate(model, glm::radians(60.0f), glm::normalize(glm::vec3(1.0, 0.0, 1.0))); 423 model = glm::scale(model, glm::vec3(0.75f)); 424 shader.setMat4("model", model); 425 renderCube(); 426} 427 428 429// renderCube() renders a 1x1 3D cube in NDC. 430// ------------------------------------------------- 431unsigned int cubeVAO = 0; 432unsigned int cubeVBO = 0; 433void renderCube() 434{ 435 // initialize (if necessary) 436 if (cubeVAO == 0) 437 { 438 float vertices[] = { 439 // back face 440 -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left 441 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right 442 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, // bottom-right 443 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right 444 -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left 445 -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, // top-left 446 // front face 447 -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left 448 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, // bottom-right 449 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right 450 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right 451 -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // top-left 452 -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left 453 // left face 454 -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right 455 -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-left 456 -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left 457 -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left 458 -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-right 459 -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right 460 // right face 461 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left 462 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right 463 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-right 464 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right 465 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left 466 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-left 467 // bottom face 468 -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right 469 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, // top-left 470 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left 471 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left 472 -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, // bottom-right 473 -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right 474 // top face 475 -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top-left 476 1.0f, 1.0f , 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right 477 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top-right 478 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right 479 -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top-left 480 -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f // bottom-left 481 }; 482 glGenVertexArrays(1, &cubeVAO); 483 glGenBuffers(1, &cubeVBO); 484 // fill buffer 485 glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); 486 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 487 // link vertex attributes 488 glBindVertexArray(cubeVAO); 489 glEnableVertexAttribArray(0); 490 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); 491 glEnableVertexAttribArray(1); 492 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); 493 glEnableVertexAttribArray(2); 494 glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); 495 glBindBuffer(GL_ARRAY_BUFFER, 0); 496 glBindVertexArray(0); 497 } 498 // render Cube 499 glBindVertexArray(cubeVAO); 500 glDrawArrays(GL_TRIANGLES, 0, 36); 501 glBindVertexArray(0); 502} 503 504// RenderQuad() Renders a 1x1 quad in NDC 505unsigned int quadVAO = 0; 506unsigned int quadVBO; 507 508void RenderQuad() 509{ 510 if (quadVAO == 0) 511 { 512 GLfloat quadVertices[] = { 513 // Positions // Texture Coords 514 -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 515 -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 516 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 517 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 518 }; 519 // Setup plane VAO 520 glGenVertexArrays(1, &quadVAO); 521 glGenBuffers(1, &quadVBO); 522 glBindVertexArray(quadVAO); 523 glBindBuffer(GL_ARRAY_BUFFER, quadVBO); 524 glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW); 525 glEnableVertexAttribArray(0); 526 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0); 527 glEnableVertexAttribArray(1); 528 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); 529 } 530 glBindVertexArray(quadVAO); 531 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 532 glBindVertexArray(0); 533}

本文同步分享在 博客“天叔”(JianShu)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

java将前端的json数组字符串转换为列表

记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang