LearnOpenGL-光照-1.颜色

news/2024/11/8 20:25:20/

本人刚学OpenGL不久且自学,文中定有代码、术语等错误,欢迎指正

我写的项目地址:https://github.com/liujianjie/LearnOpenGLProject

文章目录

  • 颜色
  • OpenGL代码例子

颜色

  • 物体颜色简介

    我们在现实生活中看到某一物体的颜色并不是这个物体真正拥有的颜色,而是它所反射的(Reflected)颜色

    那些不能被物体所吸收(Absorb)的颜色(被拒绝的颜色)就是我们能够感知到的物体的颜色

  • 举个栗子

    (太阳光能被看见的白光其实是由许多不同的颜色组合而成的(如下图所示))

    如果我们将白光照在一个蓝色的玩具上,这个蓝色的玩具会吸收白光中除了蓝色以外的所有子颜色,不被吸收的蓝色光被反射到我们的眼中,让这个玩具看起来是蓝色的

  • 图示

  • 在opengl中

    在图中我们有一个白色的太阳,所以我们也将光源设置为白色

    当我们把光源的颜色与物体的颜色值相乘,所得到的就是这个物体所反射的颜色(也就是我们所感知到的颜色)

  • opengl例子

    glm::vec3 lightColor(1.0f, 1.0f, 1.0f);
    glm::vec3 toyColor(1.0f, 0.5f, 0.31f);
    glm::vec3 result = lightColor * toyColor; // = (1.0f, 0.5f, 0.31f);
    

    我们可以看到玩具的颜色吸收了白色光源中很大一部分的颜色,但它根据自身的颜色值对红、绿、蓝三个分量都做出了一定的反射。这也表现了现实中颜色的工作原理。

    由此,我们可以定义物体的颜色为物体从一个光源反射各个颜色分量的大小

    glm::vec3 lightColor(0.0f, 1.0f, 0.0f);
    glm::vec3 toyColor(1.0f, 0.5f, 0.31f);
    glm::vec3 result = lightColor * toyColor; // = (0.0f, 0.5f, 0.0f);
    

    可以看到,并没有红色和蓝色的光让我们的玩具来吸收或反射。这个玩具吸收了光线中一半的绿色值,但仍然也反射了一半的绿色值。玩具现在看上去是深绿色(Dark-greenish)的。我们可以看到,如果我们用绿色光源来照射玩具,那么只有绿色分量能被反射和感知到,红色和蓝色都不能被我们所感知到。这样做的结果是,一个珊瑚红的玩具突然变成了深绿色物体。

OpenGL代码例子

  • 代码

    glsl

    #version 330 core
    layout (location = 0) in vec3 aPos;uniform mat4 view;
    uniform mat4 projection;
    uniform mat4 model;
    void main()
    {gl_Position = projection * view * model * vec4(aPos, 1.0);
    }
    
    #version 330 core
    out vec4 FragColor;uniform vec3 objectColor;
    uniform vec3 lightColor;void main()
    {FragColor = vec4(lightColor * objectColor, 1.0f);
    }
    

    cpp

    // 物体的光照shader
    Shader lightingShader("assest/shader/2光照/2.1.1.color.vs", "assest/shader/2光照/2.1.1.color.fs");
    // 光源shader
    Shader lightCubeShader("assest/shader/2光照/2.1.2.light_cube.vs", "assest/shader/2光照/2.1.2.light_cube.fs");// 0.1顶点数据
    float vertices[] = {-0.5f, -0.5f, -0.5f,..........
    };
    unsigned int VBO, cubeVAO;
    glGenVertexArrays(1, &cubeVAO);
    glGenBuffers(1, &VBO);
    // 1. 绑定顶点数组对象
    glBindVertexArray(cubeVAO);
    // 2. 把我们的CPU的顶点数据复制到GPU顶点缓冲中,供OpenGL使用
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    // 3. 设定顶点属性指针,来解释顶点缓冲中的顶点属性布局
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);// 重新创建一个顶点数组,同样指向这个顶点缓冲对象VBO
    unsigned int lightCubeVAO;
    glGenVertexArrays(1, &lightCubeVAO);
    glBindVertexArray(lightCubeVAO);
    // 重复利用顶点缓冲对象
    glBindBuffer(GL_ARRAY_BUFFER, VBO);// 绑定的是vbo
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);// render loop
    // -----------
    while (!glfwWindowShouldClose(window))
    {......// render// ------glClearColor(0.1f, 0.1f, 0.1f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 绑定着色器lightingShader.use();lightingShader.setVec3("objectColor", 1.0f, 0.5f, 0.31f);lightingShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f);// 观察/投影变换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);// 世界变换glm::mat4 model = glm::mat4(1.0f);lightingShader.setMat4("model", model);// 渲染这个cubeglBindVertexArray(cubeVAO);glDrawArrays(GL_TRIANGLES, 0, 36);// 同样渲染白色的cube当做太阳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 cubelightCubeShader.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();
    }
    
  • 效果


http://www.ppmy.cn/news/31154.html

相关文章

第十四届蓝桥杯第三期模拟赛 C/C++ B组 原题与详解

文章目录 一、填空题 1、1 找最小全字母十六进制数 1、1、1 题目描述 1、1、2 题解关键思路与解答 1、2 给列命名 1、2、1 题目描述 1、2、2 题解关键思路与解答 1、3 日期相等 1、3、1 题目描述 1、3、2 题解关键思路与解答 1、4 乘积方案数 1、4、1 题目描述 1、4、2 题解关…

Spring的@Conditional注解

前言Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册bean。Conditional的源码定义://此注解可以标注在类和方法上 Target({ElementType.TYPE, ElementType.METHOD}) Retention(RetentionPolicy.RUNTI…

【模板进阶】

目录 1. 非类型模板参数 2. 模板的特化 2.1 概念 2.2 函数模板特化 2.3 类模板特化 2.3.1 全特化 3 模板分离编译 3.1 什么是分离编译 3.2 模板的分离编译 4. 模板总结 有需要的老哥可以先看看模板的介绍:http://t.csdn.cn/2TkUYhttp://t.csdn.cn/2TkUY 1. …

嵌入式学习笔记——寄存器实现控制LED小灯

文章目录前言GPIO通用输出模式初始化LED小灯的GPIO原理图初始化代码初始化的效果功能函数封装直接分开宏定义两个使用条件运算符封装函数实现简单的功能前言 上一篇中,介绍了GPIO相关的所有寄存器,并在最后简单实现了一个LED灯的控制,由于那…

JDBC连接执行SQL

JDBC [Java DataBase Connectivity] JAVA数据库连接JDBC是SUN提供的一套API接口,使用JAVA连接数据库的一套标准接口。各个数据库提供上都提供了一套JDBC的实现类用于连接自家的DBMS。而提供的这一套实现类也称为连接该DBMS的驱动(Driver)1:要加载需要操作的DBMS厂商…

kube-ipam配置和使用说明

Kube-ipam基于etcd分布式存储实现kubernetes动态IP网络分配管理,确保集群中IP地址的唯一性。Kube-ipam支持给kubernetes集群中的Pod固定IP地址,同时支持resolv.conf的DNS配置。 1. 概述 一些场景往往对IP地址有依赖,需要使用固定IP地址的Po…

JVM调优面试题——垃圾回收专题

文章目录1、如何确定一个对象是垃圾?1.1、引用计数法1.2、可达性分析2、对象被判定为不可达对象之后就“死”了吗?3、都有哪些垃圾收集算法?3.1、 标记-清除(Mark-Sweep)3.2、标记-复制(Mark-Copying)3.3、标记-整理(Mark-Compact)3.4、分代收…

Tomcat源码分析-Session源码解析

Session清理 Background 线程 前面我们分析了 Session 的创建过程,而 Session 会话是有时效性的,下面我们来看下 tomcat 是如何进行失效检查的。在分析之前,我们先回顾下 Container 容器的 Background 线程。 tomcat 所有容器组件&#xf…