OpenGL入门008——环境光在片段着色器中的应用

本节将在片段着色器中应用环境光照(Ambient)

文章目录

  • 一些概念
    • 光照模型
      • 环境光
      • 漫反射
      • 镜面反射
      • 总结
  • 实战
    • 简介
    • dependencies
      • lightShader.vs
      • lightShader.fs
      • shader.vs
      • shader.fs
    • utils
      • Cube.h
      • Cube.cpp
    • main.cpp
    • CMakeLists.txt
    • 最终效果

一些概念

光照模型

环境光

概述: 在场景中无处不在、均匀分布的光线,用来模拟从周伟环境反射到物体上的光。即使没有明确的光源,物体表面仍然有一定亮度

特点:

  • 不依赖光源方向
  • 为整个物体提供均匀的基本亮度
  • 不计算光源与物体表面的方向关系

公式:
I a = K a ⋅ I a m b i e n t I_a = K_a \cdot I_{ambient} Ia=KaIambient

  • I a I_a Ia:物体表面的环境光亮度
  • k a k_a ka:环境光的反射系数(0到1之间)
  • I a m b i e n t I_{ambient} Iambient:环境光强度

漫反射

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

特点:

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

公式(朗伯余弦定律):
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:表面的法向量

镜面反射

概述: 镜面反射描述的是光滑表面(如金属或镜子)对光的反射,反射光集中在一个特定方向上,与视角密切相关

特点:

  • 表现为高光,即表面某些点的强亮反射
  • 亮度取决于观察者方向、光源方向于物体表面的关系
  • 表面越光滑,高光越集中;越粗糙,高光越分散

公式(Phong反射模型):
I s = k s ⋅ I l i g h t ⋅ m a x ( 0 , R ⋅ V ) n I_s = k_s \cdot I_{light} \cdot max(0, R \cdot V)^n Is=ksIlightmax(0,RV)n

  • I s I_s Is:镜面反射亮度
  • k s k_s ks:镜面反射系数(0到1之间)
  • R:反射方向的单位向量
  • V:观察方向的单位向量
  • n:高光的锐利程度,称为”高光指数“

总结

  • 环境光:提供基础的整体亮度,与光源和视角无光
  • 漫反射:模拟粗糙表面的光照,依赖于光源方向,但与视角无关
  • 镜面反射:模拟光滑表面的高光,依赖于光源方向和视角

这三种光照成分通常组合在一起形成Phong光照模型,用于计算场景中物体的颜色和亮度:
I = I a + I d + I s I = I_a + I_d + I_s I=Ia+Id+Is

实战

简介

怎么在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

lightShader.vs

点光源的顶点着色器源码:

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

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

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

lightShader.fs

点光源的片段着色器源码:

#version 330 core

// 光源颜色
uniform vec3 lightColor;

// 输出的片段颜色
out vec4 FragColor;

void main()
{
    FragColor = vec4(lightColor, 1.0);
}

shader.vs

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

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

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

out vec2 TexCoord;

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

    TexCoord = vTexCoord;
}

shader.fs

#version 330 core

in vec2 TexCoord;

// 第一个纹理
uniform sampler2D texture0;
// 第二个纹理
uniform sampler2D texture1;
// 混合比例
uniform float blendRatio;
// 光源颜色
uniform vec3 lightColor;

out vec4 FragColor;

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

    // 最终颜色结果
    vec3 lighting = ambient;

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

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

utils

新增的代码文件只有Cube.h和Cube.cpp,其他可以看源码的utils目录

Cube.h

#pragma once
#include "windowFactory.h"

#include <glad/glad.h>
#include "shader.h"
#include <vector>
#include <cmath>
#include <glm/glm.hpp> 
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

using std::vector;
using std::string;


class Cube {
public:
    // 构造函数
    Cube(GLFWWindowFactory* window);

    // 析构函数
    ~Cube();

    // 绘制函数
    void draw();

private:
    // 顶点数组对象
    GLuint VAO;
    // 顶点缓冲对象
    GLuint VBO;
    // 索引缓冲对象
    GLuint EBO;
    // 着色器对象
    Shader shader;
    // 点光源着色器对象
    Shader lightShader;
    // 窗口对象
    GLFWWindowFactory* window;
    // 纹理对象
    vector<GLuint> texture;

    // 设置顶点数据
    void setupVertices();
    // 加载纹理
    void loadTexture();
    // 绑定纹理
    void bindTexture(GLuint& textureId, const char* path);
};

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 = { 2.0f, 1.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 vectices[] = {
        // Front
        -0.75f, -0.75f,0.0f, 0.0f, 0.0f,  // Bottom-left vertex
        0.75f, -0.75f,0.0f, 1.0f, 0.0f,   // Bottom-right vertex
        -0.75f, 0.75f,0.0f, 0.0f, 1.0f,   // Top-left vertex
        0.75f, 0.75f,0.0f, 1.0f, 1.0f,    // Top-right vertex

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

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

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

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

        // Bottom
        -0.75f, -0.75f, -1.5f, 0.0f, 0.0f,  // Bottom-left vertex
        0.75f, -0.75f, -1.5f, 1.0f, 0.0f,   // Bottom-right vertex
        -0.75f, -0.75f, 0.0f, 0.0f, 1.0f,   // Top-left vertex
        0.75f, -0.75f, 0.0f, 1.0f, 1.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(vectices), vectices, 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, 5 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    // 纹理位置属性
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    // 恢复上下人默认的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/919786.html

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

相关文章

cesium for unity的使用

先聊聊导入 看到这里的因该能够知道&#xff0c;官网以及网上绝大多数的方法都导入不进来&#xff0c;那么解决方法如下: 两个链接&#xff1a;按照顺序依次下载这两个tgz和zip&#xff0c;其中tgz为主要部分&#xff0c;zip为示例工程项目 如果您要查看示例工程项目的话&am…

stm32cubemx+VSCODE+GCC+makefile 开发环境搭建

title: stm32cubemxVSCODEGCCmakefile 开发环境搭建 tags: FreertosHalstm32cubeMx 文章目录 内容往期内容导航第一步准备环境vscode 插件插件配置点灯 内容 往期内容导航 第一步准备环境 STM32CubeMXVSCODEMinGWOpenOcdarm-none-eabi-gcc 然后把上面下载的软件 3 4 5 bin 文…

20241120-Milvus向量数据库快速体验

目录 20241120-Milvus向量数据库快速体验Milvus 向量数据库pymilvus内嵌向量数据库模式设置向量数据库创建 Collections准备数据用向量表示文本插入数据 语义搜索向量搜索带元数据过滤的向量搜索查询通过主键搜索 删除实体加载现有数据删除 Collections了解更多 个人主页: 【⭐…

【Axure高保真原型】3D农业管理大屏可视化案例

今天和大家分享3D农业管理大屏可视化案例的原型模板&#xff0c;里面包括重点指标分析、产量分析、种类分析、分布分析、收入分析和销售分析&#xff0c;具体效果可以点击下方视频观看或打开下方预览地址查看哦 【原型效果】 【Axure高保真原型】3D农业管理大屏可视化案例 【原…

使用 LSTM(长短期记忆网络) 模型对时间序列数据(航空旅客人数数据集)进行预测

代码功能 数据准备 加载数据&#xff1a;从公开的航空旅客人数数据集&#xff08;Airline Passengers Dataset&#xff09;中读取时间序列数据。 对数变换和平稳化&#xff1a;对数据应用 log1p 函数减少趋势和波动&#xff0c;使模型更容易学习规律。 归一化处理&#xff1a;…

Redis Search系列 - 第七讲 Windows(CygWin)编译Friso

目录 一、背景二、安装CygWin三、编译Friso四、运行Friso五、Friso分词效果测试 一、背景 最近在做RedisSearch的中文分词效果调研&#xff0c;底层的中文分词插件使用的就是Friso&#xff0c;目前手里的Linux环境上yum镜像仓库有问题导致没法安装gcc&#xff0c;又急于验证Fr…

【AI大模型引领变革】探索AI如何重塑软件开发流程与未来趋势

文章目录 每日一句正能量前言流程与模式介绍【传统软件开发 VS AI参与的软件开发】一、传统软件开发流程与模式二、AI参与的软件开发流程与模式三、AI带来的不同之处 结论 AI在软件开发流程中的优势、挑战及应对策略AI在软件开发流程中的优势面临的挑战及应对策略 结论 后记 每…

智领未来: 宏集物联网HMI驱动食品与包装行业迈向智能化新高度

行业现状与挑战 食品与包装行业对设备的自动化、智能化水平要求日益提高&#xff0c;特别是瓶装和灌装生产线需要实现高速、高效的生产。此外&#xff0c;该行业还需遵循严格的卫生标准和安全规范&#xff0c;以保证产品质量符合消费者需求。在提高生产效率的同时&#xff0c;…

LeetCode 热题100(九)【图论】(待更新)

目录 9.图论 9.1岛屿数量&#xff08;中等&#xff09; 9.2腐烂的橘子&#xff08;中等&#xff09; 9.3课程表&#xff08;中等&#xff09; 9.4实现 Trie (前缀树)&#xff08;中等&#xff09; 9.图论 9.1岛屿数量&#xff08;中等&#xff09; 题目描述&#xff1a;…

数据结构--跳表

跳表 原理实现 原理 跳表&#xff08;skiplist&#xff09;是一种链表&#xff0c;而链表查询的时间复杂度为O(n)&#xff0c;为了优化查询效率&#xff0c;我们可以让每相邻两个节点升高一层&#xff0c;增加一个指针&#xff0c;让指针指向下下个节点&#xff1a; 这样所有…

ChatGPT高级语音模式正在向Web网页端推出!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;专注于分享AI全维度知识&#xff0c;包括但不限于AI科普&#xff0c;AI工…

多传感器融合slam过程解析【大白话版】

SLAM&#xff08;同步定位与地图构建&#xff09;是自动驾驶、机器人导航和三维建模的关键技术之一。多传感器融合&#xff08;激光雷达、IMU、相机&#xff09;进一步提升了SLAM的鲁棒性和适应性&#xff0c;使其能够在复杂环境中实时构建高精度地图。本文将围绕激光雷达IMU相…

MySQL 中 InnoDB 支持的四种事务隔离级别名称,以及逐级之间的区别?

MySQL中的InnoDB存储引擎支持四种事务隔离级别&#xff0c;这些级别定义了事务在并发环境中的行为和相互之间的可见性。以下是这四种隔离级别的名称以及它们之间的区别&#xff1a; 读未提交&#xff08;Read Uncommitted&#xff09; 特点&#xff1a;这是最低的隔离级别&…

【Vue】Vue3.0(二十六)Vue3.0中的作用域插槽

上篇文章 【Vue】Vue3.0&#xff08;二十五&#xff09;Vue3.0中的具名插槽 的概念和使用场景 &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Vue专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年11月20日17点30分 文章目录 概念使用场景示…

湘潭大学软件工程算法设计与分析考试复习笔记(四)

回顾 湘潭大学软件工程算法设计与分析考试复习笔记&#xff08;一&#xff09;湘潭大学软件工程算法设计与分析考试复习笔记&#xff08;二&#xff09;湘潭大学软件工程算法设计与分析考试复习笔记&#xff08;三&#xff09; 前言 现在是晚上十一点&#xff0c;我平时是十…

电路模型和电路定理(二)

电路元件 是电路中最基本的组成单元。 电阻元件&#xff1a;表示消耗电能的元件 电感元件&#xff1a;表示产生磁场&#xff0c;储存磁场能的元件 电容元件&#xff1a;表示产生电场&#xff0c;储存电场能量的元件 电压源和电流源&#xff1a;表示将其他形式的能量转变成…

【Golang】——Gin 框架中的 API 请求处理与 JSON 数据绑定

在现代 Web 开发中&#xff0c;API&#xff08;特别是 RESTful API&#xff09;是前后端分离架构的核心。Gin 框架提供了丰富的功能来处理 API 请求和 JSON 数据&#xff0c;使得开发者可以快速构建高效的接口服务。本篇博客将从基础到深入&#xff0c;全面讲解如何使用 Gin 框…

【STM32】时钟系统

在我们学习STM32之前&#xff0c;我们需要先了解STM32系列芯片的时钟系统&#xff0c;这个是我们学习这个芯片的基础。为什么时钟系统这么重要呢&#xff1f;举个例子&#xff0c;如果把STM32比作我们的整个人体&#xff0c;那么时钟就是维持我们人体正常工作的心脏。STM32芯片…

macOS 的目录结构

文章目录 根目录 (/)常见目录及其用途示例目录结构注意事项根目录 (/)主要目录及其含义其他目录总结 macOS 的目录结构无论是在 Intel 架构还是 ARM 架构的 Mac 电脑上都是相同的。macOS 的目录结构遵循 Unix 和 BSD 的传统&#xff0c;具有许多标准目录。以下是一些主要目录及…

鸿蒙NEXT开发案例:随机密码生成

【引言】 本案例将实现一个随机密码生成器。用户可以自定义密码的长度以及包含的字符类型&#xff08;大写字母、小写字母、数字、特殊字符&#xff09;&#xff0c;最后通过点击按钮生成密码&#xff0c;并提供一键复制功能。 【环境准备】 •操作系统&#xff1a;Windows …