opengl + glfw + glad 实现天空盒

天空盒基础:

天空盒技术,说到底就是就是多纹理贴图技术。是一种将多个纹理贴到一个立方体表面的技术。即立方体贴图

简单来说,立方体贴图就是一个包含了6个2D纹理的纹理,每个2D纹理都组成了立方体的一个面:一个有纹理的立方体。你可能会奇怪,这样一个立方体有什么用途呢?为什么要把6张纹理合并到一张纹理中,而不是直接使用6个单独的纹理呢?立方体贴图有一个非常有用的特性,它可以通过一个方向向量来进行索引/采样。假设我们有一个1x1x1的单位立方体,方向向量的原点位于它的中心。使用一个橘黄色的方向向量来从立方体贴图上采样一个纹理值会像是这样:

一个提供天空盒的网站:http://www.custommapmakers.org/skyboxes.php

如果你将这六个面折成一个立方体,你就会得到一个完全贴图的立方体,模拟一个巨大的场景。一些资源可能会提供了这样格式的天空盒,你必须手动提取六个面的图像,但在大部分情况下它们都是6张单独的纹理图像。

下面的网址是,LearnOpengl上针对立方体贴图的文档

https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/06%20Cubemaps/ 

我在这个文档的额基础上进行了简单的封装:

skyBox.h

#ifndef _SKYBOX_H_
#define _SKYBOX_H_

#include <vector>
#include <string>
#include <memory>

class Camera;
class Shader;
class SkyBox
{
public:
    /**
     * *structure
     */ 
	SkyBox(std::weak_ptr<Camera> pCamera,
            const float &width = 0,const float &height = 0);
    /**
     * *destruct
     */ 
	~SkyBox();
    /**
     * *init
     * @brief init skybox cube
     * @param null
     * @return null
     */ 
    void init();
    /**
     * *loadCubeMap
     * @brief load textures for skybox
     * @param images,skybox images list,includes top\bottom\left\right\front\back,total six images.
     * @return bool,true or false.ture is load sucess,false is load failed.      
     */ 
    bool loadCubeMap(const std::vector<std::string>& images);
    /**
     * *draw
     * @brief draw skybox
     * @param null
     * @return null
     */ 
    void draw();
private:
    // ?CubeMap textureid  
    unsigned int      m_cubeTextureId; 
    // ?camera object     
    std::shared_ptr<Camera> m_pCamera;
    // ?shader
    std::shared_ptr<Shader> m_pShader;
    // ?顶点数组对象
    unsigned int      m_skyboxVAO;
    // ?顶点缓冲对象
    unsigned int      m_skyboxVBO;

    float m_width;
    float m_height;
};

#endif //_SKYBOX_H_

 

skyBox.cpp

#include "skyBox.h"
#include <iostream>

#include <glad/glad.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "core/stb_image.h"

#include "core/shader.h"
#include "core/camera.h"


SkyBox::SkyBox(std::weak_ptr<Camera> pCamera,
        const float &width,const float &height)
    :m_cubeTextureId(0),m_pCamera(nullptr),m_pShader(nullptr),
    m_skyboxVAO(0),m_skyboxVBO(0),
    m_width(width),m_height(height)
{
    if(!m_pCamera.use_count())
        m_pCamera = pCamera.lock();
    if(!m_pShader.use_count())
        m_pShader = std::make_shared<Shader>("../shader/skybox.vs",
                                  "../shader/skybox.fs");    
    init();
}


SkyBox::~SkyBox()
{
    // glDeleteVertexArrays(1,&m_skyboxVAO);
    // glDeleteBuffers(1,&m_skyboxVBO);
}

void SkyBox::init()
{
    //准备数据
    float skyboxVertices[] = {
        // positions          
        -1.0f,  1.0f, -1.0f,
        -1.0f, -1.0f, -1.0f,
         1.0f, -1.0f, -1.0f,
         1.0f, -1.0f, -1.0f,
         1.0f,  1.0f, -1.0f,
        -1.0f,  1.0f, -1.0f,

        -1.0f, -1.0f,  1.0f,
        -1.0f, -1.0f, -1.0f,
        -1.0f,  1.0f, -1.0f,
        -1.0f,  1.0f, -1.0f,
        -1.0f,  1.0f,  1.0f,
        -1.0f, -1.0f,  1.0f,

         1.0f, -1.0f, -1.0f,
         1.0f, -1.0f,  1.0f,
         1.0f,  1.0f,  1.0f,
         1.0f,  1.0f,  1.0f,
         1.0f,  1.0f, -1.0f,
         1.0f, -1.0f, -1.0f,

        -1.0f, -1.0f,  1.0f,
        -1.0f,  1.0f,  1.0f,
         1.0f,  1.0f,  1.0f,
         1.0f,  1.0f,  1.0f,
         1.0f, -1.0f,  1.0f,
        -1.0f, -1.0f,  1.0f,

        -1.0f,  1.0f, -1.0f,
         1.0f,  1.0f, -1.0f,
         1.0f,  1.0f,  1.0f,
         1.0f,  1.0f,  1.0f,
        -1.0f,  1.0f,  1.0f,
        -1.0f,  1.0f, -1.0f,

        -1.0f, -1.0f, -1.0f,
        -1.0f, -1.0f,  1.0f,
         1.0f, -1.0f, -1.0f,
         1.0f, -1.0f, -1.0f,
        -1.0f, -1.0f,  1.0f,
         1.0f, -1.0f,  1.0f
    };

    glGenVertexArrays(1, &m_skyboxVAO);
    glGenBuffers(1, &m_skyboxVBO);
    glBindVertexArray(m_skyboxVAO);
    glBindBuffer(GL_ARRAY_BUFFER, m_skyboxVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
}

bool SkyBox::loadCubeMap(const std::vector<std::string>& images)
{
    glGenTextures(1, &m_cubeTextureId);
    glBindTexture(GL_TEXTURE_CUBE_MAP, m_cubeTextureId);

    int width, height, nrChannels;
    for (unsigned int i = 0; i < images.size(); i++)
    {
        auto data = stbi_load(images[i].c_str(), &width, &height, &nrChannels, 0);
        if (data)
        {
            glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
            stbi_image_free(data);
        }
        else
        {
            std::cout << "Cubemap texture failed to load at path: " << images[i] << std::endl;
            stbi_image_free(data);
            return false;
        }
    }
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

    m_pShader->use();
    m_pShader->setInt("skybox", 0);

    return true;
}

void SkyBox::draw()
{
    // todo
    m_pShader->use();
    // remove translation from the view matrix
    glm::mat4 view = glm::mat4(glm::mat3(m_pCamera->GetViewMatrix()));
    glm::mat4 projection = glm::perspective(glm::radians(m_pCamera->Zoom), 
                                m_width / m_height, 0.1f, 100.0f);
    
    m_pShader->setMat4("view", view);
    m_pShader->setMat4("projection", projection);

    glBindVertexArray(m_skyboxVAO);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_CUBE_MAP, m_cubeTextureId);
    glDrawArrays(GL_TRIANGLES, 0, 36);
    glBindVertexArray(0);
    glDepthFunc(GL_LESS); // set depth function back to default
}

 

skybox.vs

#version 330 core
layout (location = 0) in vec3 aPos;

out vec3 TexCoords;

uniform mat4 projection;
uniform mat4 view;

void main()
{
    TexCoords = aPos;
    vec4 pos = projection * view * vec4(aPos, 1.0);
    gl_Position = pos.xyww;
}  

skybox.fs

#version 330 core
out vec4 FragColor;

in vec3 TexCoords;

uniform samplerCube skybox;

void main()
{    
    FragColor = texture(skybox, TexCoords);
}

调用

std::shared_ptr<Camera> pCamera = std::make_shared<Camera>(glm::vec3(0.0f, 0.0f, 0.0f));
    SkyBox skyBox(pCamera,(float)SCR_WIDTH,(float)SCR_HEIGHT);

    // load textures

    std::vector<std::string> images
    {
        "../resources/Texture/mp_ac/ac_rt.tga",
        "../resources/Texture/mp_ac/ac_lf.tga",
        "../resources/Texture/mp_ac/ac_up.tga",
        "../resources/Texture/mp_ac/ac_dn.tga",
        "../resources/Texture/mp_ac/ac_ft.tga",
        "../resources/Texture/mp_ac/ac_bk.tga"
    };

    skyBox.loadCubeMap(images);
glDepthFunc(GL_LEQUAL);

        skyBox.draw();

运行结果:

源代码:https://download.csdn.net/download/qq_15024587/11042366 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是使用 GLFWGLAD 库绘制四边形的示例代码: ```c++ #include <glad/glad.h> #include <GLFW/glfw3.h> #include <iostream> void framebuffer_size_callback(GLFWwindow* window, int width, int height) { glViewport(0, 0, width, height); } void processInput(GLFWwindow* window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { glfwSetWindowShouldClose(window, true); } } int main() { glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); GLFWwindow* window = glfwCreateWindow(800, 600, "Quad", nullptr, nullptr); if (window == nullptr) { std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "Failed to initialize GLAD" << std::endl; return -1; } glViewport(0, 0, 800, 600); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); while (!glfwWindowShouldClose(window)) { processInput(window); glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); float vertices[] = { -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f, 0.5f, 0.5f, 0.0f, -0.5f, 0.5f, 0.0f }; unsigned int indices[] = { 0, 1, 3, 1, 2, 3 }; unsigned int VBO, VAO, EBO; glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glGenBuffers(1, &EBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glfwSwapBuffers(window); glfwPollEvents(); } glfwTerminate(); return 0; } ``` 在 `main()` 函数中,我们首先初始化 GLFW 库和 OpenGL 上下文。然后使用 GLAD 库初始化 OpenGL 函数指针。 在主循环中,我们首先处理输入事件,然后清空颜色缓冲区。接着定义四边形的顶点坐标和顶点索引,生成 VBO、VAO 和 EBO,绑定并填充数据。最后绘制四边形并交换缓冲区。 在 `framebuffer_size_callback()` 回调函数中,我们重新设置视口大小。 在 `processInput()` 函数中,我们检查 ESC 键是否被按下,如果是则设置窗口关闭标志,退出主循环。 这段代码使用了现代 OpenGL 的方式,使用了顶点缓冲对象、顶点数组对象和索引缓冲对象。同时也使用了 GLAD 库来加载 OpenGL 函数指针。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值