OpenGL入门009——漫反射在片段着色器中的应用

本节将在片段着色器中应用漫反射

文章目录

  • 一些概念
    • 漫反射
  • 实战
    • 简介
    • dependencies
      • shadervs
      • shader.fs
    • utils
      • Cube.cpp
    • main.cpp
    • CMakeLists.txt
    • 最终效果

一些概念

漫反射

概述: 描述的是粗糙表面对光的反射,反射的光线相关各个方向均匀分布,与视角无光

特点:

  • 亮度取决于光源的方向和物体表面法向量之间的夹角
  • 适合模拟不光滑的表面,例如木材、纸张等
  • 视角变化不会影响光的强度

公式(朗伯余弦定律):
I d = k d ⋅ I l i g h t ⋅ m a x ( 0 , L ⋅ N ) I_d = k_d \cdot I_{light} \cdot max(0, L \cdot N) Id=kdIlightmax(0,LN)

  • I d I_d Id:物体表面的漫反射亮度
  • k d k_d kd:漫反射的反射系数(0到1之间)
  • I l i g h t I_{light} Ilight:光源强度
  • L:指向光源的单位向量
  • N:表面的法向量

实战

简介

怎么在vscode上使用cmake构建项目,具体可以看这篇Windows上如何使用CMake构建项目 - 凌云行者的博客

目的: 使用环境光

  • 编译工具链:使用msys2安装的mingw-gcc
  • 依赖项:glfw3:x64-mingw-static,glad:x64-mingw-static(通过vcpkg安装)

源码: OpenGL-Learn-Program/008-ambient-light at main · 1037827920/OpenGL-Learn-Program

dependencies

主要改动shader.vs和shader.fs,其他文件看这里

shadervs

立方体的顶点着色器源码:

#version 330 core
layout (location = 0) in vec3 vPos;
layout (location = 1) in vec2 vTexCoord;
layout (location = 2) in vec3 vNormal;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

out vec2 TexCoord;
out vec3 Normal;
out vec3 FragPos;

void main()
{
    gl_Position = projection * view * model * vec4(vPos, 1.0f);

    TexCoord = vTexCoord;
    Normal = mat3(transpose(inverse(model))) * vNormal;
    FragPos = vec3(model * vec4(vPos, 1.0f));
}

shader.fs

#version 330 core

in vec2 TexCoord;
// 表示片段的法向量,用于确定片段相对于光源的角度
in vec3 Normal;
// 表示片段在世界空间中的位置,用于确定片段相对于光源的距离
in vec3 FragPos;

// 第一个纹理
uniform sampler2D texture0;
// 第二个纹理
uniform sampler2D texture1;
// 混合比例
uniform float blendRatio;
// 立方体本身的环境光 光源颜色
uniform vec3 lightColor;
// 点光源位置
uniform vec3 lightPos;

out vec4 FragColor;

void main()
{
    // 环境光强度
    float ambientStrength = 0.2;
    // 计算环境光分量
    vec3 ambient = ambientStrength * lightColor;

    // 标准化法向量
    vec3 norm = normalize(Normal);
    // 计算片段位置和光源位置之间的方向向量
    vec3 lightDir = normalize(lightPos - FragPos);
    // 计算光源到片段的距离
    float distance = length(lightPos - FragPos);
    // 计算衰减
    float attenuation = 1.0 / (distance * distance);
    // 计算漫反射分量
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * lightColor * attenuation;
 
    // 最终颜色结果
    vec3 lighting = ambient + diffuse;

    // 将两个纹理混合并乘以环境光分量
    FragColor = mix(texture(texture0, TexCoord), texture(texture1, TexCoord), blendRatio) * vec4(lighting, 1.0);
}

顶点着色器源码的输出会作为片段着色器源码的输入

utils

修改的代码文件只有和Cube.cpp,其他可以看这里

Cube.cpp

#include "Cube.h"
#include <iostream>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

Cube::Cube(GLFWWindowFactory* window) : window(window) {
    this->shader = Shader("shader.vs", "shader.fs");
    this->lightShader = Shader("lightShader.vs", "lightShader.fs");
    // 加载纹理
    loadTexture();
    // 设置顶点数据
    setupVertices();
}

Cube::~Cube() {
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);
}

/// Public
void Cube::draw() {
    // 存储光源的位置和强度
    vector<float> lightPos = { 1.0f, 0.5f, -1.55f, 1.0f };

    // 使用立方体的着色器
    shader.use();
    // 将立方体的VAO绑定到上下文
    glBindVertexArray(this->VAO);

    // 设置立方体模型矩阵
    auto model = glm::mat4(1.0f);
    // 设置平移矩阵
    model = glm::translate(model, glm::vec3(0.0f, 0.0f, -3.0f));
    // 设置旋转矩阵
    model = glm::rotate(model, glm::radians(20.0f), glm::vec3(1.0f, 0.0f, 0.0f));

    // 将uniform变量传递给着色器
    shader.setMat4("model", model);
    shader.setMat4("view", this->window->getViewMatrix());
    shader.setMat4("projection", this->window->getProjectionMatrix());
    shader.setVec3("lightColor", 1.0f, 1.0f, 1.0f);
    shader.setVec3("lightPos", lightPos[0], lightPos[1], lightPos[2]);
    shader.setFloat("blendRatio", 0.5f);

    // 绘制立方体
    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);

    // 使用光源的着色器
    lightShader.use();
    // 光源的VAO仍然使用立方体的VAO
    // 设置模型矩阵
    model = glm::mat4(1.0f);
    // 设置平移矩阵
    model = glm::translate(model, glm::vec3(lightPos[0], lightPos[1], lightPos[2]));
    // 设置缩放矩阵
    model = glm::scale(model, glm::vec3(0.2f));

    // 将uniform变量传递给着色器
    lightShader.setMat4("model", model);
    lightShader.setMat4("view", this->window->getViewMatrix());
    lightShader.setMat4("projection", this->window->getProjectionMatrix());
    lightShader.setVec3("lightColor", glm::vec3(1.0f, 1.0f, 1.0f));

    // 绘制光源
    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
}


/// Private
// 设置顶点数据
void Cube::setupVertices() {
    float vertices[] = {
        // Front
        -0.75f, -0.75f,0.0f, 0.0f, 0.0f, 0.0f, 0.0f,1.0f,  // Bottom-left vertex
        0.75f, -0.75f,0.0f, 1.0f, 0.0f,  0.0f, 0.0f,1.0f, // Bottom-right vertex
        -0.75f, 0.75f,0.0f, 0.0f, 1.0f, 0.0f, 0.0f,1.0f,  // Top-left vertex
        0.75f, 0.75f,0.0f, 1.0f, 1.0f,  0.0f, 0.0f,1.0f,  // Top-right vertex

        // Back
        0.75f, -0.75f, -1.5f, 0.0f, 0.0f,  0.0f, 0.0f,-1.0f,// Bottom-left vertex
        -0.75f, -0.75f, -1.5f, 1.0f, 0.0f, 0.0f, 0.0f,-1.0f,  // Bottom-right vertex
        0.75f, 0.75f, -1.5f, 0.0f, 1.0f,   0.0f, 0.0f,-1.0f,// Top-left vertex
        -0.75f, 0.75f, -1.5f, 1.0f, 1.0f,  0.0f, 0.0f,-1.0f,  // Top-right vertex

        // Left
        -0.75f, -0.75f, -1.5f, 0.0f, 0.0f, -1.0f,0.0f,0.0f,  // Bottom-left vertex
        -0.75f, -0.75f, 0.0f, 1.0f, 0.0f, -1.0f,0.0f,0.0f,  // Bottom-right vertex
        -0.75f, 0.75f, -1.5f, 0.0f, 1.0f, -1.0f,0.0f,0.0f,  // Top-left vertex
        -0.75f, 0.75f, 0.0f, 1.0f, 1.0f,  -1.0f,0.0f,0.0f,  // Top-right vertex

        // Right
        0.75f, -0.75f, 0.0f, 0.0f, 0.0f, 1.0f,0.0f,0.0f, // Bottom-left vertex
        0.75f, -0.75f, -1.5f, 1.0f, 0.0f,1.0f,0.0f,0.0f,   // Bottom-right vertex
        0.75f, 0.75f, 0.0f, 0.0f, 1.0f,  1.0f,0.0f,0.0f, // Top-left vertex
        0.75f, 0.75f, -1.5f, 1.0f, 1.0f, 1.0f,0.0f,0.0f,   // Top-right vertex

        // Top
        -0.75f, 0.75f, 0.0f, 0.0f, 0.0f,  0.0f,1.0f,0.0f,// Bottom-left vertex
        0.75f, 0.75f, 0.0f, 1.0f, 0.0f,  0.0f,1.0f,0.0f, // Bottom-right vertex
        -0.75f, 0.75f, -1.5f, 0.0f, 1.0f,  0.0f,1.0f,0.0f, // Top-left vertex
        0.75f, 0.75f, -1.5f, 1.0f, 1.0f,   0.0f,1.0f,0.0f, // Top-right vertex

        // Bottom
        -0.75f, -0.75f, -1.5f, 0.0f, 0.0f, 0.0f,-1.0f,0.0f, // Bottom-left vertex
        0.75f, -0.75f, -1.5f, 1.0f, 0.0f,  0.0f,-1.0f,0.0f, // Bottom-right vertex
        -0.75f, -0.75f, 0.0f, 0.0f, 1.0f,  0.0f,-1.0f,0.0f, // Top-left vertex
        0.75f, -0.75f, 0.0f, 1.0f, 1.0f ,  0.0f,-1.0f,0.0f,// Top-right vertex
    };

    // 索引数据
    int indices[] = {
        0, 1, 2,
        2, 1, 3,

        4, 5, 6,
        6, 5, 7,

        8, 9, 10,
        10, 9, 11,

        12, 13, 14,
        14, 13, 15,

        16, 17, 18,
        18, 17, 19,

        20, 21, 22,
        22, 21, 23
    };

    // 创建VAO, VBO, EBO
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    // 绑定VAO
    glBindVertexArray(VAO);

    // 绑定VBO
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    // 将顶点数据复制到VBO
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // 绑定EBO
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    // 将索引数据复制到EBO
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    // 设置顶点位置属性(这里跟顶点着色器源码强相关,每个属性有多少个元素都是看这个顶点着色器源码是怎么写的)
    // 位置属性
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    // 纹理位置属性
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    // 法向量属性
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(5 * sizeof(float)));
    glEnableVertexAttribArray(2);

    // 恢复上下人默认的VAO
    glBindVertexArray(0);
}

// 加载纹理
void Cube::loadTexture() {
    vector<string> paths = { "teenager.png", "tex.png" };
    this->texture.resize(paths.size());
    // 绑定纹理
    for (int i = 0; i < paths.size(); i++) {
        bindTexture(this->texture[i], paths[i].c_str());
    }

    // 激活纹理
    glActiveTexture(GL_TEXTURE0);
    // 将纹理绑定到上下文
    glBindTexture(GL_TEXTURE_2D, this->texture[0]);
    // 激活纹理
    glActiveTexture(GL_TEXTURE1);
    // 将纹理绑定到上下文
    glBindTexture(GL_TEXTURE_2D, this->texture[1]);

    // 使用立方体着色器
    this->shader.use();
    // 为着色器设置uniform变量
    this->shader.setInt("texture0", 0);
    this->shader.setInt("texture1", 1);
}

// 绑定纹理
void Cube::bindTexture(GLuint& textureId, const char* path) {
    // 生成纹理
    glGenTextures(1, &textureId);
    // 绑定上下文的纹理
    glBindTexture(GL_TEXTURE_2D, textureId);

    // 设置纹理环绕方式
    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_set_flip_vertically_on_load(true);
    int width, height, nrChannels;
    unsigned char* data = stbi_load(path, &width, &height, &nrChannels, 0);

    if (data) {
        GLenum format;
        if (nrChannels == 4)
            format = GL_RGBA;
        else if (nrChannels == 3)
            format = GL_RGB;
        else
            format = GL_RED;

        glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
    }
    else {
        std::cout << "Failed to load texture" << std::endl;
    }

    stbi_image_free(data);
}

main.cpp

#include "utils/Cube.h"
#include "utils/windowFactory.h"

int main() {
    // 创建一个窗口Factory对象
    GLFWWindowFactory myWindow(800, 600, "This is Title");
    // 创建一个矩形模型对象
    Cube cube(&myWindow);
    
    // 运行窗口,传入一个lambda表达式,用于自定义渲染逻辑
    myWindow.run([&]() {
        // 绘制矩形
        cube.draw();
    });
    
    return 0;
}

CMakeLists.txt

# 设置CMake的最低版本要求
cmake_minimum_required(VERSION 3.10)
# 设置项目名称
project(Ambient)

# vcpkg集成, 这里要换成你自己的vcpkg工具链文件和共享库路径
set(VCPKG_ROOT D:/software6/vcpkg/)
set(CMAKE_TOOLCHAIN_FILE ${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake)
set(CMAKE_PREFIX_PATH ${VCPKG_ROOT}/installed/x64-mingw-static/share)

# 查找所需的包
find_package(glad CONFIG REQUIRED)
find_package(glfw3 CONFIG REQUIRED)
find_package(glm CONFIG REQUIRED)
find_package(assimp CONFIG REQUIRED)
find_package(yaml-cpp CONFIG REQUIRED)

# 搜索并收集utils文件夹下的所有源文件
file(GLOB UTILS "utils/*.cpp", "utils/*.h")

# 添加可执行文件(还要加入utils文件夹下的源文件)
add_executable(Ambient main.cpp ${UTILS})

# 链接所需的库
target_link_libraries(Ambient PRIVATE glad::glad glfw glm::glm assimp::assimp yaml-cpp::yaml-cpp)

# 检查项目是否有dependeicies目录,如果存在,则在使用add_custom_command命令在构建后将dependencies目录中的文件复制到项目的输出目录
set(SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dependencies")
if(EXISTS ${SOURCE_DIR})
    add_custom_command(TARGET Ambient POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_directory
        ${SOURCE_DIR} $<TARGET_FILE_DIR:Ambient>)
endif()

最终效果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/920836.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

删库跑路,启动!

起因&#xff1a;这是一个悲伤的故事&#xff0c;在抓logcat时 device待机自动回根目录了&#xff0c;而题主对当前路径的印象还停留在文件夹下&#xff0c;不小心在根目录执行了rm -rf * … 所以&#xff0c;这是个悲伤的故事&#xff0c;东西全没了…device也黑屏了&#xff…

Ubuntu下的Eigen库的安装及基本使用教程

一、Eigen库介绍 简介 Eigen [1]目前最新的版本是3.4&#xff0c;除了C标准库以外&#xff0c;不需要任何其他的依赖包。Eigen使用的CMake建立配置文件和单元测试&#xff0c;并自动安装。如果使用Eigen库&#xff0c;只需包特定模块的的头文件即可。 基本功能 Eigen适用范…

OpenCV与AI深度学习|16个含源码和数据集的计算机视觉实战项目(建议收藏!)

本文来源公众号“OpenCV与AI深度学习”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;分享&#xff5c;16个含源码和数据集的计算机视觉实战项目 本文将分享16个含源码和数据集的计算机视觉实战项目。具体包括&#xff1a; 1. 人…

MySQL win安装 和 pymysql使用示例

目录 一、MySQL安装 下载压缩包&#xff1a; 编写配置文件&#xff1a; 配置环境变量&#xff1a; 初始化服务和账户 关闭mysql开机自启&#xff08;可选&#xff09; 建议找一个数据库可视化软件 二、使用pymysql操作数据库 安装pymysql 示例代码 报错处理 一、My…

springboot基于微信小程序的停车场管理系统

摘 要 停车场管理系统是一种基于移动端的应用程序&#xff0c;旨在方便车主停车的事务办理。该小程序提供了便捷的停车和功能&#xff0c;使车主能够快速完成各项必要的手续和信息填写。旨在提供一种便捷、高效的预约停车方式&#xff0c;减少停车手续的时间和精力成本。通过该…

js:数组转换为字符串

1、使用join 通过join&#xff0c;将数组拼接&#xff0c;使用&#xff0c;进行分割 let array [a, b, c] let str array.join(,); console.log(str) 2、使用toString() const array [a, b, c] const string array.toString() console.log(string) 3、使用扩展运算符和…

npm上传自己封装的插件(vue+vite)

一、npm账号及发包删包等命令 若没有账号&#xff0c;可在npm官网&#xff1a;https://www.npmjs.com/login 进行注册。 在当前项目根目录下打开终端命令窗口&#xff0c;常见命令如下&#xff1a; 1、登录命令&#xff1a;npm login&#xff08;不用每次都重新登录&#xff0…

路由缓存后跳转到新路由时,上一路由中的tip信息框不销毁问题解决

上一路由tip信息框不销毁问题解决 路由缓存篇问题描述及截图解决思路关键代码 路由缓存篇 传送门 问题描述及截图 路由缓存后跳转新路由时&#xff0c;上一个路由的tip信息框没销毁。 解决思路 在全局路由守卫中获取DOM元素&#xff0c;通过css去控制 关键代码 修改文…

uni-app 界面TabBar中间大图标设置的两种方法

一、前言 最近写基于uni-app 写app项目的时候&#xff0c;底部导航栏 中间有一个固定的大图标&#xff0c;并且没有激活状态。这里记录下实现方案。效果如下&#xff08;党组织这个图标&#xff09;&#xff1a; 方法一&#xff1a;midButton的使用 官方文档&#xff1a;ta…

Apple Vision Pro开发003-PolySpatial2.0新建项目

unity6.0下载链接:Unity 实时开发平台 | 3D、2D、VR 和 AR 引擎 一、新建项目 二、导入开发包 com.unity.polyspatial.visionos 输入版本号 2.0.4 com.unity.polyspatial&#xff08;单独导入&#xff09;&#xff0c;或者直接安装 三、对应设置 其他的操作与之前的版本相同…

xiaolin coding 图解网络笔记——基础篇

基础篇 Linux 系统是如何收发网络包的&#xff1f; 网络模型 为了使多种设备能通过网络相互通信&#xff0c;和为了解决不同设备在网络互连中的兼容性问题&#xff0c;国际标准化组织制定了开放式系统互连通信参考模型&#xff08;Open System Interconnection Reference Mo…

【vba源码】导入excel批注信息

Hi&#xff0c;大家好呀&#xff01; 又到了一周一分享的时间&#xff0c;上周繁忙的我都没有给大家直播&#xff0c;视频也没更新&#xff0c;那这周大家放心&#xff0c;都会给大家更新&#xff0c;今天我们来讲点啥呢&#xff1f;每周找优质的内容给大家更新是我最最痛苦的…

跨平台WPF框架Avalonia教程 十三

AutoCompleteBox 自动补全输入框 自动补全输入框提供了一个供用户输入的文本框和一个包含可能匹配项的下拉列表。下拉列表会在用户开始输入时显示&#xff0c;并且每输入一个字符&#xff0c;匹配项都会更新。用户可以从下拉列表中选择匹配项。 文本与可能项匹配的方式是可配…

MATLAB实现GARCH(广义自回归条件异方差)模型计算VaR(Value at Risk)

MATLAB实现GARCH(广义自回归条件异方差)模型计算VaR(Value at Risk) 1.计算模型介绍 使用GARCH&#xff08;广义自回归条件异方差&#xff09;模型计算VaR&#xff08;风险价值&#xff09;时&#xff0c;方差法是一个常用的方法。GARCH模型能够捕捉到金融时间序列数据中的波…

力扣 LeetCode 513. 找树左下角的值(Day8:二叉树)

解题思路&#xff1a; 方法一&#xff1a;递归法&#xff08;方法二更好理解&#xff0c;个人更习惯方法二&#xff09; 前中后序均可&#xff0c;实际上没有中的处理 中左右&#xff0c;左中右&#xff0c;左右中&#xff0c;实际上都是左在前&#xff0c;所以遇到的第一个…

Nuget For Unity插件介绍

NuGet for Unity&#xff1a;提升 Unity 开发效率的利器 NuGet 是 .NET 开发生态中不可或缺的包管理工具,你可以将其理解为Unity的Assets Store或者UPM,里面有很多库可以帮助我们提高开发效率。当你想使用一个库,恰好这个库没什么依赖(比如newtonjson),那么下载包并找到Dll直接…

“乐鑫组件注册表”简介

当启动一个新的开发项目时&#xff0c;开发者们通常会利用库和驱动程序等现有的代码资源。这种做法不仅节省时间&#xff0c;还简化了项目的维护工作。本文将深入探讨乐鑫组件注册表的概念及其核心理念&#xff0c;旨在指导您高效地使用和贡献组件。 概念解析 ESP-IDF 的架构…

药房革新:Spring Boot中药实验管理系统

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

嵌入式 UI 开发的开源项目推荐

嵌入式开发 UI 难吗&#xff1f;你的痛点我懂&#xff01;作为嵌入式开发者&#xff0c;你是否也有以下困扰&#xff1f;设备资源太少&#xff0c;功能和美观只能二选一&#xff1f;调试效率低&#xff0c;每次调整都要反复烧录和测试&#xff1f;开发周期太长&#xff0c;让你…

CTF--php伪协议结合Base64绕过

Base64绕过 在ctf中&#xff0c;base64是比较常见的编码方式&#xff0c;在做题的时候发现自己对于base64的编码和解码规则不是很了解&#xff0c;并且恰好碰到了类似的题目&#xff0c;在翻阅了大佬的文章后记录一下&#xff0c;对于base64编码的学习和一个工具 base64编码是…