多光源
为了在场景中使用多个光源,我们希望将光照计算封装到GLSL函数中 主要的分类:
平行光,点光源,聚光
GLSL多光源封装 > 平行光、点光源、聚光,
单独计算,累加和```cpp #version 330 core out vec4 FragColor;struct Material { sampler2D diffuse; sampler2D specular; //sampler2D emission; float shininess; }; //平行光 struct DirLight { vec3 direction; vec3 ambient; vec3 diffuse; vec3 specular; }; //点光源 struct PointLight { vec3 position; float constant; float linear; float quadratic; vec3 ambient; vec3 diffuse; vec3 specular; }; //聚光 struct SpotLight { vec3 position; vec3 direction; float cutOff; float outerCutOff; float constant; float linear; float quadratic; vec3 ambient; vec3 diffuse; vec3 specular; }; //限制支持的点光源数量。 #define NR_POINT_LIGHTS 4 in vec3 FragPos; in vec3 Normal; in vec2 TexCoords; uniform vec3 viewPos; uniform DirLight dirLight; uniform PointLight pointLights[NR_POINT_LIGHTS]; uniform SpotLight spotLight; uniform Material material; // function prototypes vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir); vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir); vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir); void main() { // properties vec3 norm = normalize(Normal); vec3 viewDir = normalize(viewPos - FragPos); // == ===================================================== // Our lighting is set up in 3 phases: directional, point lights and an optional flashlight // For each phase, a calculate function is defined that calculates the corresponding color // per lamp. In the main() function we take all the calculated colors and sum them up for // this fragment's final color. // == ===================================================== // phase 1: directional lighting vec3 result = CalcDirLight(dirLight, norm, viewDir); // phase 2: point lights for(int i = 0; i < NR_POINT_LIGHTS; i++) result += CalcPointLight(pointLights[i], norm, FragPos, viewDir); // phase 3: spot light result += CalcSpotLight(spotLight, norm, FragPos, viewDir); FragColor = vec4(result, 1.0); } // calculates the color when using a directional light. vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir) { vec3 lightDir = normalize(-light.direction); // diffuse shading float diff = max(dot(normal, lightDir), 0.0); // specular shading vec3 reflectDir = reflect(-lightDir, normal); float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); // combine results vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords)); vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords)); vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords)); return (ambient + diffuse + specular); } // calculates the color when using a point light. vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir) { vec3 lightDir = normalize(light.position - fragPos); // diffuse shading float diff = max(dot(normal, lightDir), 0.0); // specular shading vec3 reflectDir = reflect(-lightDir, normal); float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); // attenuation float distance = length(light.position - fragPos); float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance)); // combine results vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords)); vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords)); vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords)); ambient *= attenuation; diffuse *= attenuation; specular *= attenuation; return (ambient + diffuse + specular); } // calculates the color when using a spot light. vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir) { vec3 lightDir = normalize(light.position - fragPos); // diffuse shading float diff = max(dot(normal, lightDir), 0.0); // specular shading vec3 reflectDir = reflect(-lightDir, normal); float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); // attenuation float distance = length(light.position - fragPos); float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance)); // spotlight intensity float theta = dot(lightDir, normalize(-light.direction)); float epsilon = light.cutOff - light.outerCutOff; float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0); // combine results vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords)); vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords)); vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords)); ambient *= attenuation * intensity; diffuse *= attenuation * intensity; specular *= attenuation * intensity; return (ambient + diffuse + specular); }```
完整代码
#include <glad/glad.h> #include <GLFW/glfw3.h> #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include <shader_m.h> #include <camera.h> #include <iostream> using namespace std; void framebuffer_size_callback(GLFWwindow* window, int width, int height); void mouse_callback(GLFWwindow* window, double xpos, double ypos); void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); void processInput(GLFWwindow *window); unsigned int loadTexture(const char *path); // settings const int wWidth = 800, wHeight = 600; const char* wName = "LearnOpenGL"; // camera Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); float lastX = wWidth / 2.0f; float lastY = wHeight / 2.0f; bool firstMouse = true; // timing float deltaTime = 0.0f; float lastFrame = 0.0f; // lighting glm::vec3 lightPos(1.2f, 1.0f, 2.0f); int main() { //1. 初始化 if (glfwInit() == GLFW_FALSE) { cout << "init glfw fail"; return 1; } //2. 基本设置 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); #if __APPLE__ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); #endif //3. 创建窗口 GLFWwindow *window = glfwCreateWindow(wWidth, wHeight, wName, nullptr, nullptr); if (window == nullptr) { cout << "Failed to create GLFW window"; goto TERMINATE; //return 1; } //4. 当前主线程上下文窗口 glfwMakeContextCurrent(window); //5. 使用glad管理OpenGL指针。 if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "Failed to initialize GLAD" << std::endl; goto TERMINATE; //return 1; } //6. 设置视口 glViewport(0, 0, wWidth, wHeight); //7. 设置resize回调,对应刷新视口 glfwMakeContextCurrent(window); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); glfwSetCursorPosCallback(window, mouse_callback); glfwSetScrollCallback(window, scroll_callback); // build and compile our shader zprogram // ------------------------------------ Shader lightingShader("res/shaders/lighting_multi.vs", "res/shaders/lighting_multi.fs"); Shader textureShader("res/shaders/texture.vs", "res/shaders/texture1.fs"); Shader lightCubeShader("res/shaders/cube.vs", "res/shaders/white.fs"); float vertices[] = { -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, -0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f }; unsigned int VBO, cubeVAO; glGenVertexArrays(1, &cubeVAO); glGenBuffers(1, &VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBindVertexArray(cubeVAO); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); glEnableVertexAttribArray(2); // second, configure the light's VAO (VBO stays the same; the vertices are the same for the light object which is also a 3D cube) unsigned int lightCubeVAO; glGenVertexArrays(1, &lightCubeVAO); glBindVertexArray(lightCubeVAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); // note that we update the lamp's position attribute's stride to reflect the updated buffer data glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); // load textures (we now use a utility function to keep the code more organized) // ----------------------------------------------------------------------------- unsigned int diffuseMap = loadTexture("./res/textures/container2.png"); unsigned int specularMap = loadTexture("./res/textures/container2_specular.png"); float verticesMMap[] = { //位置 // 基础颜色 // 贴图uv 0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right 0.6f, 0.9f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right 0.9f, 0.9f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left 0.9f, 0.6f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left }; unsigned int indicesMMap[] = { 0, 1, 3, // 第一个三角形 1, 2, 3 // 第二个三角形 }; unsigned int mmapVBO, mmapVAO, mmapEBO; glGenVertexArrays(1, &mmapVAO); glBindVertexArray(mmapVAO); glGenBuffers(1, &mmapVBO); glBindBuffer(GL_ARRAY_BUFFER, mmapVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(verticesMMap), verticesMMap, GL_STATIC_DRAW); glGenBuffers(1, &mmapEBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mmapEBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indicesMMap), indicesMMap, GL_STATIC_DRAW); //1. 指定顶点的顶点属性的结构,顶点 3个float,从0开始,整体每一组数据8个。 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); //2. 指定颜色的顶点属性的结构,三色 3个float,从3开始,整体每一组数据8个。 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); //3. 指定uv的顶点属性的结构,uv 2个float,从6开始,整体每一组数据8个。 glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); glEnableVertexAttribArray(2); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); //指定采样器贴图储存的位置 textureShader.use(); textureShader.setInt("texture1", 0); lightingShader.use(); lightingShader.setInt("material.diffuse", 0); lightingShader.setInt("material.specular", 1); glEnable(GL_DEPTH_TEST); glm::vec3 cubePositions[] = { glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(2.0f, 5.0f, -15.0f), glm::vec3(-1.5f, -2.2f, -2.5f), glm::vec3(-3.8f, -2.0f, -12.3f), glm::vec3(2.4f, -0.4f, -3.5f), glm::vec3(-1.7f, 3.0f, -7.5f), glm::vec3(1.3f, -2.0f, -2.5f), glm::vec3(1.5f, 2.0f, -2.5f), glm::vec3(1.5f, 0.2f, -1.5f), glm::vec3(-1.3f, 1.0f, -1.5f) }; glm::vec3 pointLightPositions[] = { glm::vec3(0.7f, 0.2f, 2.0f), glm::vec3(2.3f, -3.3f, -4.0f), glm::vec3(-4.0f, 2.0f, -12.0f), glm::vec3(0.0f, 0.0f, -3.0f) }; while (!glfwWindowShouldClose(window)) { // per-frame time logic // -------------------- float currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; // input // ----- processInput(window); glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // be sure to activate shader when setting uniforms/drawing objects lightingShader.use(); lightingShader.setVec3("viewPos", camera.Position); lightingShader.setFloat("material.shininess", 32.0f); /* Here we set all the uniforms for the 5/6 types of lights we have. We have to set them manually and index the proper PointLight struct in the array to set each uniform variable. This can be done more code-friendly by defining light types as classes and set their values in there, or by using a more efficient uniform approach by using 'Uniform buffer objects', but that is something we'll discuss in the 'Advanced GLSL' tutorial. */ // directional light lightingShader.setVec3("dirLight.direction", -0.2f, -1.0f, -0.3f); lightingShader.setVec3("dirLight.ambient", 0.05f, 0.05f, 0.05f); lightingShader.setVec3("dirLight.diffuse", 0.4f, 0.4f, 0.4f); lightingShader.setVec3("dirLight.specular", 0.5f, 0.5f, 0.5f); // point light 1 lightingShader.setVec3("pointLights[0].position", pointLightPositions[0]); lightingShader.setVec3("pointLights[0].ambient", 0.05f, 0.05f, 0.05f); lightingShader.setVec3("pointLights[0].diffuse", 0.8f, 0.8f, 0.8f); lightingShader.setVec3("pointLights[0].specular", 1.0f, 1.0f, 1.0f); lightingShader.setFloat("pointLights[0].constant", 1.0f); lightingShader.setFloat("pointLights[0].linear", 0.09); lightingShader.setFloat("pointLights[0].quadratic", 0.032); // point light 2 lightingShader.setVec3("pointLights[1].position", pointLightPositions[1]); lightingShader.setVec3("pointLights[1].ambient", 0.05f, 0.05f, 0.05f); lightingShader.setVec3("pointLights[1].diffuse", 0.8f, 0.8f, 0.8f); lightingShader.setVec3("pointLights[1].specular", 1.0f, 1.0f, 1.0f); lightingShader.setFloat("pointLights[1].constant", 1.0f); lightingShader.setFloat("pointLights[1].linear", 0.09); lightingShader.setFloat("pointLights[1].quadratic", 0.032); // point light 3 lightingShader.setVec3("pointLights[2].position", pointLightPositions[2]); lightingShader.setVec3("pointLights[2].ambient", 0.05f, 0.05f, 0.05f); lightingShader.setVec3("pointLights[2].diffuse", 0.8f, 0.8f, 0.8f); lightingShader.setVec3("pointLights[2].specular", 1.0f, 1.0f, 1.0f); lightingShader.setFloat("pointLights[2].constant", 1.0f); lightingShader.setFloat("pointLights[2].linear", 0.09); lightingShader.setFloat("pointLights[2].quadratic", 0.032); // point light 4 lightingShader.setVec3("pointLights[3].position", pointLightPositions[3]); lightingShader.setVec3("pointLights[3].ambient", 0.05f, 0.05f, 0.05f); lightingShader.setVec3("pointLights[3].diffuse", 0.8f, 0.8f, 0.8f); lightingShader.setVec3("pointLights[3].specular", 1.0f, 1.0f, 1.0f); lightingShader.setFloat("pointLights[3].constant", 1.0f); lightingShader.setFloat("pointLights[3].linear", 0.09); lightingShader.setFloat("pointLights[3].quadratic", 0.032); // spotLight lightingShader.setVec3("spotLight.position", camera.Position); lightingShader.setVec3("spotLight.direction", camera.Front); lightingShader.setVec3("spotLight.ambient", 0.0f, 0.0f, 0.0f); lightingShader.setVec3("spotLight.diffuse", 1.0f, 1.0f, 1.0f); lightingShader.setVec3("spotLight.specular", 1.0f, 1.0f, 1.0f); lightingShader.setFloat("spotLight.constant", 1.0f); lightingShader.setFloat("spotLight.linear", 0.09); lightingShader.setFloat("spotLight.quadratic", 0.032); lightingShader.setFloat("spotLight.cutOff", glm::cos(glm::radians(12.5f))); lightingShader.setFloat("spotLight.outerCutOff", glm::cos(glm::radians(15.0f))); // view/projection transformations glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)wWidth / (float)wHeight, 0.1f, 100.0f); glm::mat4 view = camera.GetViewMatrix(); lightingShader.setMat4("projection", projection); lightingShader.setMat4("view", view); // world transformation glm::mat4 model = glm::mat4(1.0f); lightingShader.setMat4("model", model); // bind diffuse map glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, diffuseMap); // bind specular map glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, specularMap); // render containers glBindVertexArray(cubeVAO); for (unsigned int i = 0; i < 10; i++) { // calculate the model matrix for each object and pass it to shader before drawing glm::mat4 model = glm::mat4(1.0f); model = glm::translate(model, cubePositions[i]); float angle = 20.0f * i; model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f)); lightingShader.setMat4("model", model); glDrawArrays(GL_TRIANGLES, 0, 36); } // also draw the lamp object lightCubeShader.use(); lightCubeShader.setMat4("projection", projection); lightCubeShader.setMat4("view", view); model = glm::mat4(1.0f); model = glm::translate(model, lightPos); model = glm::scale(model, glm::vec3(0.2f)); // a smaller cube lightCubeShader.setMat4("model", model); glBindVertexArray(lightCubeVAO); glDrawArrays(GL_TRIANGLES, 0, 36); // bind Texture1 /*glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, diffuseMap);*/ textureShader.use(); glBindVertexArray(mmapVAO); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glfwSwapBuffers(window); glfwPollEvents(); } glDeleteVertexArrays(1, &cubeVAO); glDeleteVertexArrays(1, &lightCubeVAO); glDeleteBuffers(1, &VBO); glDeleteVertexArrays(1, &mmapVAO); glDeleteBuffers(1, &mmapVBO); glDeleteBuffers(1, &mmapEBO); TERMINATE: glfwTerminate(); return 0; } // process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly // --------------------------------------------------------------------------------------------------------- void processInput(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) camera.ProcessKeyboard(FORWARD, deltaTime); if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) camera.ProcessKeyboard(BACKWARD, deltaTime); if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) camera.ProcessKeyboard(LEFT, deltaTime); if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) camera.ProcessKeyboard(RIGHT, deltaTime); } // glfw: whenever the window size changed (by OS or user resize) this callback function executes // --------------------------------------------------------------------------------------------- void framebuffer_size_callback(GLFWwindow* window, int width, int height) { // make sure the viewport matches the new window dimensions; note that width and // height will be significantly larger than specified on retina displays. glViewport(0, 0, width, height); } // glfw: whenever the mouse moves, this callback is called // ------------------------------------------------------- void mouse_callback(GLFWwindow* window, double xpos, double ypos) { if (firstMouse) { lastX = xpos; lastY = ypos; firstMouse = false; } float xoffset = xpos - lastX; float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top lastX = xpos; lastY = ypos; camera.ProcessMouseMovement(xoffset, yoffset); } // glfw: whenever the mouse scroll wheel scrolls, this callback is called // ---------------------------------------------------------------------- void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { camera.ProcessMouseScroll(yoffset); } // utility function for loading a 2D texture from file // --------------------------------------------------- unsigned int loadTexture(char const * path) { unsigned int textureID; glGenTextures(1, &textureID); int width, height, nrComponents; unsigned char *data = stbi_load(path, &width, &height, &nrComponents, 0); if (data) { GLenum format; if (nrComponents == 1) format = GL_RED; else if (nrComponents == 3) format = GL_RGB; else if (nrComponents == 4) format = GL_RGBA; glBindTexture(GL_TEXTURE_2D, textureID); glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); stbi_image_free(data); } else { std::cout << "Texture failed to load at path: " << path << std::endl; stbi_image_free(data); } return textureID; }