OpenGL_Learn11(光照)

news2024/11/25 4:06:20

目录

1. 光照

2. 环境光照

3. 漫反射光照

4. 代码实战


1. 光照

在OpenGL中主要分以下几个光照类型

  • 环境光照(Ambient Lighting):即使在黑暗的情况下,世界上通常也仍然有一些光亮(月亮、远处的光),所以物体几乎永远不会是完全黑暗的。为了模拟这个,我们会使用一个环境光照常量,它永远会给物体一些颜色。
  • 漫反射光照(Diffuse Lighting):模拟光源对物体的方向性影响(Directional Impact)。它是冯氏光照模型中视觉上最显著的分量。物体的某一部分越是正对着光源,它就会越亮。
  • 镜面光照(Specular Lighting):模拟有光泽物体上面出现的亮点。镜面光照的颜色相比于物体的颜色会更倾向于光的颜色。

2. 环境光照

光通常都不是来自于同一个光源,而是来自于我们周围分散的很多光源,即使它们可能并不是那么显而易见。光的一个属性是,它可以向很多方向发散并反弹,从而能够到达不是非常直接临近的点。

我们将会先使用一个简化的全局照明模型,即环境光照,

把环境光照添加到场景里非常简单。我们用光的颜色乘以一个很小的常量环境因子,再乘以物体的颜色,然后将最终结果作为片段的颜色:

void main()
{
    float ambientStrength = 0.1;
    vec3 ambient = ambientStrength * lightColor;

    vec3 result = ambient * objectColor;
    FragColor = vec4(result, 1.0);
}

3. 漫反射光照

为了测量光线和片段的角度,我们使用一个叫做法向量(Normal Vector)的东西,它是垂直于片段表面的一个向量(这里以黄色箭头表示

漫反射光照使物体上与光线方向越接近的片段能从光源处获得更多的亮度。

光线的方向接触该物体表面的角度决定是否可以获取更多的亮度

记得把,两个向量的点乘的几何意义就是判断两个向量之间相似程度。

所以,计算漫反射光照需要什么?

  • 法向量:一个垂直于顶点表面的向量。
  • 定向的光线:作为光源的位置片段的位置之间向量差的方向向量。为了计算这个光线,我们需要光的位置向量和片段的位置向量。

4. 代码实战

所有光照的计算都是在片段着色器里进行,这里光照是作用于被照射的物体,也就是cube.vs

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

out vec3 FragPos;
out vec3 Normal;

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

void main()
{
    FragPos=vec3(model*vec4(aPos,1.0));
    Normal=aNormal;
    gl_Position = projection * view  * vec4(FragPos, 1.0);
}

cube.fs

计算实际的颜色需要(环境光+漫反射的光,应该属于增强光)*物体的颜色

环境光容易得到

慢反射的变量取决于光线向量和物体表面法向量之间的夹角,夹角越小,这个漫反射变量越大,作用到物体上亮度越大。

#version 330 core
out vec4 FragColor;

in vec3 Normal;
in vec3 FragPos;

uniform vec3 objectColor;
uniform vec3 lightColor;
uniform vec3 lightPos;

void main()
{
    //ambient
    float ambientStrength=0.1;
    vec3 ambient=ambientStrength*lightColor;

    //diffuse
    vec3 norm=normalize(Normal);
    vec3 lightDir=normalize(lightPos-FragPos);//光的方向向量是光源位置向量与片段位置向量之间的向量差。
    //对norm和lightDir向量进行点乘,计算光源对当前片段实际的漫反射影响
    //两个向量之间的角度越大,漫反射分量就会越小,点乘的几何意义也如此
    float diff=max(dot(norm,lightDir),0.0);
    vec3 diffuse=diff*lightColor;

    vec3 result=(ambient+diffuse)*objectColor;
    FragColor = vec4(result, 1.0);
}

下面两个着色器就是光源点,无需进行其他操作。 

light_cube.vs

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

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

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

light_cube.fs

#version 330 core
out vec4 FragColor;

void main()
{
    FragColor = vec4(1.0); // set all 4 vector values to 1.0
}

main.cpp

#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include <iostream>
#include "stb_image.h"
#include <cmath>
#include "shader.h"
#include "camera.h"

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);

// settings
const unsigned int SCR_WIDTH = 1800;
const unsigned int SCR_HEIGHT = 1200;


//camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
float lastX = SCR_WIDTH / 2.0f;
float lastY = SCR_HEIGHT / 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() {
	//glfw:initialize and configure
	//=============================
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

#ifdef __APPLE__
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif

	//glfw window creation
	//=============================
	GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Learn", NULL, NULL);
	if (window == NULL) {
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return -1;
	}

	glfwMakeContextCurrent(window);
	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
	glfwSetCursorPosCallback(window, mouse_callback);
	glfwSetScrollCallback(window, scroll_callback);

	//tell GLFW to capture our mouse
	glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

	//glad::load all OPenGL function pointers
	//=============================
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
		std::cout << "Failed to initialize GLAD" << std::endl;
		return -1;
	}

	//configure gloabl opengl state
	//=============================
	glEnable(GL_DEPTH_TEST);

	//build and compile our shader zprogram
	//=============================
	Shader lightingShader("./cube.vs", "./cube.fs");
    Shader lightingCubeShader("./light_cube.vs", "./light_cube.fs");
	//set up vertex data 

    float vertices[] = {
    -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
     0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
     0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
     0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
    -0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
    -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,

    -0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,
     0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,
     0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,
     0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,
    -0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,
    -0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,

    -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,
    -0.5f,  0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
    -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
    -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
    -0.5f, -0.5f,  0.5f, -1.0f,  0.0f,  0.0f,
    -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,

     0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,
     0.5f,  0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
     0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
     0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
     0.5f, -0.5f,  0.5f,  1.0f,  0.0f,  0.0f,
     0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,

    -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,
     0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,
     0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
     0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
    -0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,

    -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,
     0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,
     0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
     0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
    -0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
    -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.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);

    //position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    //normal attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    
    //第二个
    unsigned int lightCubeVAO;
    glGenVertexArrays(1, &lightCubeVAO);
    glBindVertexArray(lightCubeVAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);



    // render loop
    // -----------
    while (!glfwWindowShouldClose(window))
    {
        // per-frame time logic
        // --------------------
        float currentFrame = static_cast<float>(glfwGetTime());
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;

        // input
        // -----
        processInput(window);

        // render
        // ------
        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("objectColor", 1.0f, 0.5f, 0.31f);
        lightingShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f);
        lightingShader.setVec3("lightPos", lightPos);

        // view/projection transformations
        glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 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);

        // render the cube
        glBindVertexArray(cubeVAO);
        glDrawArrays(GL_TRIANGLES, 0, 36);


        // also draw the lamp object
        lightingCubeShader.use();
        lightingCubeShader.setMat4("projection", projection);
        lightingCubeShader.setMat4("view", view);
        model = glm::mat4(1.0f);
        model = glm::translate(model, lightPos);
        model = glm::scale(model, glm::vec3(0.2f)); // a smaller cube
        lightingCubeShader.setMat4("model", model);

        glBindVertexArray(lightCubeVAO);
        glDrawArrays(GL_TRIANGLES, 0, 36);


        // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
        // -------------------------------------------------------------------------------
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glDeleteVertexArrays(1, &cubeVAO);
    glDeleteVertexArrays(1, &lightCubeVAO);
    glDeleteBuffers(1, &VBO);

    glfwTerminate();
    return 0;

}
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);
}

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 xposIn, double yposIn)
{
    float xpos = static_cast<float>(xposIn);
    float ypos = static_cast<float>(yposIn);

    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(static_cast<float>(yoffset));
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高德地图系列(一):vue项目如何使用高德地图、入门以及基本控件使用

目录 第一章 前言 第二章 准备工作 2.1 账号注册 2.2 高德地图开发平台文档 2.3 创建应用 第三章 使用地图 3.1 地图使用步骤 3.2 理解几个地图基础控件 3.3 基础类理解 第一章 前言 小编都是在vue项目中使用高德地图的&#xff0c;每一个功能都会亲测可用之后才会…

【2014年数据结构真题】

41. (13分&#xff09;二叉树的带权路径长度(WPL)是二叉树中所有叶结点的带权路径长度之和。 给定一棵二叉树T,采用二叉链表存储&#xff0c;结点结构如下&#xff1a; 其中叶结点的weight域保存该结点的非负权值。 设root为指向T的根结点的指针&#xff0c; 请设计求T 的WPL…

linux下安装向日葵

https://sunlogin.oray.com/download/linux?typepersonal下载 在文件所在位置的空白处右键&#xff08;在此处打开终端&#xff09; 输入命令&#xff1a; sudo dpkg -i 文件名.deb &#xff08;文件名为下载的deb文件名字&#xff09;/usr/local/sunlogin/bin/sunlogincl…

JVM实战-JVM之类加载时机

目录 JVM实战-JVM之类加载时机1 主动引用2 被动引用 JVM实战-JVM之类加载时机 Java虚拟机把描述类的数据从Class文件加载到内存&#xff0c;并对数据进行校验、转换解析和初始化&#xff0c;最终形成可以被虚拟机直接使用的Java类型&#xff0c;这个过程被称作虚拟机的类加载机…

No208.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

arcgis--二维建筑面的三维显示设置

1、打开ArcScene软件&#xff0c;导入数据&#xff0c;如下&#xff1a; 2、 对建筑面进行拉伸。双击建筑物面图层&#xff0c;打开属性表&#xff0c;选择【拉伸】选项卡&#xff0c;参数设置如下&#xff1a; 显示结果如下&#xff1a;

第一篇 《随机点名答题系统》简介及设计流程图(类抽奖系统、在线答题系统、线上答题系统、在线点名系统、线上点名系统、在线考试系统、线上考试系统)

专栏目录 第一篇 《随机点名答题系统》简介及设计流程图&#xff08;类抽奖系统、在线答题系统、线上答题系统、在线点名系统、线上点名系统、在线考试系统、线上考试系统&#xff09;-CSDN博客 第二篇 《随机点名答题系统》——题库管理详解&#xff08;类抽奖系统、在线答题…

万宾科技内涝积水监测仪效果,预警城市积水

当城市之中出现强降雨或者大暴雨&#xff0c;可能会导致雨水不断堆积到城市排水管网之中&#xff0c;可能还会淹没城市的排水系统时&#xff0c;这种现象被称为城市之中的内涝&#xff0c;并且在许多城市之中内涝问题日益引起人们的关注。 内涝积水监测仪的出现成为了希望的灯塔…

java轮播图接口实现

一. 内容简介 实现java后端用户管理接口&#xff0c;数据库使用msyql。 二. 软件环境 2.1 java 1.8 2.2 mysql Ver 8.0.13 for Win64 on x86_64 (MySQL Community Server - GPL) 2.3 IDEA ULTIMATE 2019.3 2.4d代码地址 https://gitee.com/JJW_1601897441/competitionAs…

Unity中Shader的矩阵加减法

文章目录 前言一、什么是矩阵矩阵就是一组数的阵列 二、矩阵的加法三、矩阵的负值四、矩阵的减法五、矩阵的表示 前言 Unity中Shader用到的矩阵加减法&#xff0c;以及矩阵的一些基础常识 一、什么是矩阵 矩阵就是一组数的阵列 1 2 3 4 5 6 二、矩阵的加法 两个矩阵相加就是…

UE4 / UE5 内存与性能优化

性能优化 资源压缩粒子优化NavMeshGenerate Overlap EventGCMarkTime光照优化Shader优化卡的时间长LOD官方CPU、GPU Insights、stat cpu、 ue4 memory report、inter GPA 、RenderDOC、减少模型面数等 资源压缩 在图片资源上右键选择Size Map可以看到资源所占大小&#xff0c;…

预览PDF并显示当前页数

这里写目录标题 步骤实例实例效果图 步骤 1.安装依赖 npm install --save vue-pdf2.在需要的页面&#xff0c;引入插件 import pdf from vue-pdf3.使用 单页pdf可以直接使用 <pdf :src"获取到的pdf地址"></pdf>多页pdf通过循环实现 html标签部分 &l…

Docker - 企业项目

Docker - 企业项目 因为环境原因&#xff0c;本章本人没有实际操作&#xff0c;以理论为主 容器单独没有什么意义&#xff0c;有意义的是容器的编排 Docker 4台&#xff1a;1核2G的ECS K8s 9台&#xff1a;2核4G的ECS Docker Compose Docker Swarm # manager节点初始化sw…

最小二乘法及参数辨识

文章目录 一、最小二乘法1.1 定义1.2 SISO系统运用最小二乘估计进行辨识1.3 几何解释1.4 最小二乘法性质 二、加权最小二乘法三、递推最小二乘法四、增广最小二乘法 一、最小二乘法 1.1 定义 1974年高斯提出的最小二乘法的基本原理是未知量的最可能值是使各项实际观测值和计算…

前端AJAX入门到实战,学习前端框架前必会的(ajax+node.js+webpack+git)(四)

你可以的&#xff0c;去飞吧&#xff01; 同步代码和异步代码 回调函数地狱和 Promise 链式调用 回调函数地狱 缔造“回调地狱”↓ 制造里层回调错误&#xff0c;却在最外层接收错误→无法捕获 axios源码抛出异常&#xff08;未捕获&#xff09; <!DOCTYPE html> <ht…

Elastic stack8.10.4搭建、启用安全认证,启用https,TLS,SSL 安全配置详解

ELK大家应该很了解了&#xff0c;废话不多说开始部署 kafka在其中作为消息队列解耦和让logstash高可用 kafka和zk 的安装可以参考这篇文章 深入理解Kafka3.6.0的核心概念&#xff0c;搭建与使用-CSDN博客 第一步、官网下载安装包 需要 elasticsearch-8.10.4 logstash-8.…

(论文阅读30/100)Convolutional Pose Machines

30.文献阅读笔记CPMs 简介 题目 Convolutional Pose Machines 作者 Shih-En Wei, Varun Ramakrishna, Takeo Kanade, and Yaser Sheikh, CVPR, 2016. 原文链接 https://arxiv.org/pdf/1602.00134.pdf 关键词 Convolutional Pose Machines&#xff08;CPMs&#xff09;…

STM32中使用看门狗实现系统自动复位

STM32中的看门狗(Watchdog)是一种用于监控系统运行状态并在系统故障或死锁时执行自动复位的硬件功能。在本文中&#xff0c;我将介绍如何在STM32微控制器中使用看门狗来实现系统的自动复位。下面是详细的解释&#xff1a; 一、看门狗原理简介 看门狗是一种独立的硬件计时器&am…

C/C++计算乘积 2021年9月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录 C/C计算乘积 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 C/C计算乘积 2021年9月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 给定两个数a,b&#xff0c;计算它们的乘积 2、输入输出…

Spring 6 资源Resources 相关操作

Java全能学习面试指南&#xff1a;https://javaxiaobear.cn 1、Spring Resources概述 Java的标准java.net.URL类和各种URL前缀的标准处理程序无法满足所有对low-level资源的访问&#xff0c;比如&#xff1a;没有标准化的 URL 实现可用于访问需要从类路径或相对于 ServletCont…