LearnOpenGL学习笔记9:材质

Posted 键盘春秋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LearnOpenGL学习笔记9:材质相关的知识,希望对你有一定的参考价值。

一、 材质

通过为每个元素指定一个颜色,我们已经对物体的颜色输出有了精密的控制。现在把一个镜面高光元素添加到这三个颜色里,这是我们需要的所有材质属性:

#version 330 core
struct Material

    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
    float shininess;
;
uniform Material material;

1. 设置材质

由于所有材质元素都储存在结构体中,我们可以从uniform变量material取得它们:

void main()

    // 环境光
    vec3 ambient = lightColor * material.ambient;

    // 漫反射光
    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(lightPos - FragPos);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = lightColor * (diff * material.diffuse);

    // 镜面高光
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
    vec3 specular = lightColor * (spec * material.specular);

    vec3 result = ambient + diffuse + specular;
    color = vec4(result, 1.0f);

一个结构体值扮演uniform变量的封装体,所以如果我们希望填充这个结构体,我们就仍然必须设置结构体中的各个元素的uniform值,但是这次带有结构体名字作为前缀:

GLint matAmbientLoc = glGetUniformLocation(lightingShader.Program, "material.ambient");
GLint matDiffuseLoc = glGetUniformLocation(lightingShader.Program, "material.diffuse");
GLint matSpecularLoc = glGetUniformLocation(lightingShader.Program, "material.specular");
GLint matShineLoc = glGetUniformLocation(lightingShader.Program, "material.shininess");

glUniform3f(matAmbientLoc, 1.0f, 0.5f, 0.31f);
glUniform3f(matDiffuseLoc, 1.0f, 0.5f, 0.31f);
glUniform3f(matSpecularLoc, 0.5f, 0.5f, 0.5f);
glUniform1f(matShineLoc, 32.0f);

2. 光的属性

前面的教程,我们通过使用一个强度值改变环境和镜面强度的方式解决了这个问题。我们想做一个相同的系统,但是这次为每个光照元素指定了强度向量。如果我们想象lightColor是vec3(1.0),代码看起来像是这样:

vec3 ambient = vec3(1.0f) * material.ambient;
vec3 diffuse = vec3(1.0f) * (diff * material.diffuse);
vec3 specular = vec3(1.0f) * (spec * material.specular);

所以物体的每个材质属性返回了每个光照元素的全强度。这些vec3(1.0)值可以各自独立的影响各个光源,这通常就是我们想要的。现在物体的ambient元素完全地展示了立方体的颜色,可是环境元素不应该对最终颜色有这么大的影响,所以我们要设置光的ambient亮度为一个小一点的值,从而限制环境色:

vec3 result = vec3(0.1f) * material.ambient;

我们可以用同样的方式影响光源diffuse和specular的强度。这和我们前面教程所做的极为相似;你可以说我们已经创建了一些光的属性来各自独立地影响每个光照元素。我们希望为光的属性创建一些与材质结构体相似的东西:

struct Light

    vec3 position;
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
;
uniform Light light;

一个光源的ambient、diffuse和specular光都有不同的亮度。环境光通常设置为一个比较低的亮度,因为我们不希望环境色太过显眼。光源的diffuse元素通常设置为我们希望光所具有的颜色;经常是一个明亮的白色。specular元素通常被设置为vec3(1.0f)类型的全强度发光。要记住的是我们同样把光的位置添加到结构体中。

就像材质uniform一样,需要更新片段着色器:

vec3 ambient = light.ambient * material.ambient;
vec3 diffuse = light.diffuse * (diff * material.diffuse);
vec3 specular = light.specular * (spec * material.specular);

然后我们要在应用里设置光的亮度:

GLint lightAmbientLoc = glGetUniformLocation(lightingShader.Program, "light.ambient");
GLint lightDiffuseLoc = glGetUniformLocation(lightingShader.Program, "light.diffuse");
GLint lightSpecularLoc = glGetUniformLocation(lightingShader.Program, "light.specular");

glUniform3f(lightAmbientLoc, 0.2f, 0.2f, 0.2f);
glUniform3f(lightDiffuseLoc, 0.5f, 0.5f, 0.5f);// 让我们把这个光调暗一点,这样会看起来更自然
glUniform3f(lightSpecularLoc, 1.0f, 1.0f, 1.0f);

3. 不同光源颜色

利用sin和glfwGetTime改变光的环境和漫反射颜色,我们可以随着时间流逝简单的改变光源颜色:

glm::vec3 lightColor; lightColor.x = sin(glfwGetTime() * 2.0f);
lightColor.y = sin(glfwGetTime() * 0.7f);
lightColor.z = sin(glfwGetTime() * 1.3f);

glm::vec3 diffuseColor = lightColor * glm::vec3(0.5f);
glm::vec3 ambientColor = diffuseColor * glm::vec3(0.2f);

glUniform3f(lightAmbientLoc, ambientColor.x, ambientColor.y, ambientColor.z);
glUniform3f(lightDiffuseLoc, diffuseColor.x, diffuseColor.y, diffuseColor.z);

二、 光照贴图

前面的材质系统对于除了最简单的模型以外都是不够的,所以我们需要扩展前面的系统,我们要介绍diffuse和specular贴图。它们允许你对一个物体的diffuse(而对于简洁的ambient成分来说,它们几乎总是是一样的)和specular成分能够有更精确的影响。

1. 漫反射贴图

在光照场景中,通过纹理来呈现一个物体的diffuse颜色,这个做法被称做漫反射贴图(Diffuse texture)。为了演示漫反射贴图,我们将会使用下面的图片,它是一个有一圈钢边的木箱:

在着色器中使用漫反射贴图和纹理教程介绍的一样。这次我们把纹理以sampler2D类型储存在Material结构体中。我们使用diffuse贴图替代早期定义的vec3类型的diffuse颜色。

struct Material

    sampler2D diffuse;
    vec3 specular;
    float shininess;
;
...
in vec2 TexCoords;

注意,在片段着色器中我们将会再次需要纹理坐标,所以我们声明一个额外输入变量。然后我们简单地从纹理采样,来获得原始像素的diffuse颜色值:

vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));

同样,不要忘记把ambient材质的颜色设置为diffuse材质的颜色:

vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));

为了让它工作,我们需要用到纹理坐标更新顶点数据,把它们作为顶点属性传递到片段着色器,把纹理加载并绑定到合适的纹理单元。

要保证更新的顶点属性指针,不仅是VAO匹配新的顶点数据,也要把箱子图片加载为纹理。在绘制箱子之前,我们希望首选纹理单元被赋为material.diffuse这个uniform采样器,并绑定箱子的纹理到这个纹理单元:

glUniform1i(glGetUniformLocation(lightingShader.Program, "material.diffuse"), 0);
...
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, diffuseMap);

2. 镜面贴图

我们同样用一个纹理贴图,来获得镜面高光。这意味着我们需要生成一个黑白(或者你喜欢的颜色)纹理来定义specular亮度,把它应用到物体的每个部分。下面是一个镜面贴图(Specular Map)的例子:

一个specular高光的亮度可以通过图片中每个纹理的亮度来获得。specular贴图的每个像素可以显示为一个颜色向量,比如:在那里黑色代表颜色向量vec3(0.0f),灰色是vec3(0.5f)。在片段着色器中,我们采样相应的颜色值,把它乘以光的specular亮度。像素越“白”,乘积的结果越大,物体的specualr部分越亮。
镜面贴图采样
由于我们在同样的片段着色器中使用另一个纹理采样器,我们必须为specular贴图使用一个不同的纹理单元(参见纹理),所以在渲染前让我们把它绑定到合适的纹理单元

glUniform1i(glGetUniformLocation(lightingShader.Program, "material.specular"), 1);
...
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, specularMap);

然后更新片段着色器材质属性,接受一个sampler2D作为这个specular部分的类型,而不是vec3:

struct Material

    sampler2D diffuse;
    sampler2D specular;
    float shininess;
;

最后我们希望采样这个specular贴图,来获取原始像素相应的specular亮度:

vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));
vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));
color = vec4(ambient + diffuse + specular, 1.0f);

转载请注明出处:http://blog.csdn.net/ylbs110/article/details/52566131

三、 示例

代码:

#include <iostream>
using namespace std;
// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
// SOIL
#include <SOIL\\SOIL.h>

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

#include "Shader.h"
#include "Camera.h"

const GLuint WIDTH = 800, HEIGHT = 600;

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
GLuint loadTexture(string fileName, GLint REPEAT, GLint FILTER);
void do_movement();
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
// Shaders
const GLchar* vertexShaderSource = "#version 330 core\\n"
"layout (location = 0) in vec3 position;\\n"//顶点数据传入的坐标
"layout (location = 1) in vec3 normal;\\n"//顶点数据传入的颜色
"layout (location = 2) in vec2 texCoord;\\n"//顶点数据传入的纹理坐标
"uniform vec4 offset;\\n"
"uniform float mixPar;\\n"
"uniform mat4 model;\\n"
"uniform mat4 view;\\n"
"uniform mat4 projection;\\n"
"out vec3 FragPos;\\n"
"out vec3 Normal;\\n"
"out vec2 TexCoord;\\n"
"out float MixPar;\\n"
"void main()\\n"
"\\n"
"gl_Position =projection * view * model* vec4(position.x, position.y, position.z, 1.0)+offset;\\n"
"FragPos = vec3(model * vec4(position, 1.0f));\\n"
"Normal=normal;\\n"
"TexCoord=texCoord;\\n"
"MixPar=mixPar;\\n"
"\\0";

const GLchar* fragmentShaderSource = "#version 330 core\\n"
"out vec4 color;\\n"
"in vec3 FragPos;\\n"
"in vec3 Normal;\\n"
"in vec2 TexCoord;\\n"
"in float MixPar;\\n"
"uniform sampler2D ourTexture1;\\n"
"uniform sampler2D ourTexture2;\\n"
"uniform vec3 objectColor;\\n"
"uniform vec3 lightPos;\\n"
"uniform vec3 viewPos;\\n"

"struct Material\\n"
"sampler2D diffuse;\\n"
"sampler2D specular;\\n"
"float shininess;\\n"
";\\n"
"uniform Material material;\\n"

"struct Light\\n"
"vec3 position;\\n"
"vec3 ambient;\\n"
"vec3 diffuse;\\n"
"vec3 specular;\\n"
";\\n"
"uniform Light light;\\n"

"void main()\\n"
"\\n"
"vec3 diffTex = vec3(texture(material.diffuse, TexCoord));\\n"
"vec3 specTex = vec3(texture(material.specular, TexCoord));\\n"

"vec3 ambient =light.ambient * diffTex;\\n"

"vec3 norm = normalize(Normal);\\n"
"vec3 lightDir = normalize(lightPos - FragPos);\\n"
"float diff = max(dot(norm, lightDir), 0.0);\\n"
"vec3 diffuse =light.diffuse * diff * diffTex;\\n"

"vec3 viewDir = normalize(viewPos - FragPos);\\n"
"vec3 reflectDir = reflect(-lightDir, norm);\\n"
"float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);\\n"
"vec3 specular =light.specular * spec * specTex;\\n"

"vec3 result = (ambient + diffuse+specular) * objectColor;\\n"
"color = vec4(result, 1.0f);\\n"
//"color =result*mix(texture(ourTexture1, TexCoord),texture(ourTexture2, vec2(TexCoord.x,1-TexCoord.y)),MixPar)+vec4(lightColor * objectColor, 1.0f);\\n"
"\\n\\0";
const GLchar* fragmentShaderSourceLight = "#version 330 core\\n"
"out vec4 color;\\n"
"uniform vec3 lightColor;\\n"
"void main()\\n"
"\\n"
"color = vec4(lightColor,1.0f);\\n"
"\\n\\0";
Camera mainCamera;
Shader shader, lightintShader;//shader
GLuint texContainer, texAwesomeface, diffuseContainer,specularContainer;//纹理id

float key_UD = 0.5f;//混合比例
GLuint VBO, lightVAO, VAO;

GLfloat deltaTime = 0.0f;   // 当前帧遇上一帧的时间差
GLfloat lastFrame = 0.0f;   // 上一帧的时间

bool keys[1024];

GLfloat lastX = 400, lastY = 300;
GLfloat scrollSpeed = 0.05f;
bool firstMouse = true;

glm::vec3 lightPos(1.2f, 1.0f, 2.0f);
glm::mat4 model;
glm::mat4 view;
glm::mat4 projection;
GLint modelLoc;
GLint viewLoc;
GLint projectionLoc;

void shaderInit() 
    shader = Shader(vertexShaderSource, fragmentShaderSource);
    lightintShader = Shader(vertexShaderSource, fragmentShaderSourceLight);

void textureInit() 
    texContainer = loadTexture("container.jpg", GL_CLAMP_TO_EDGE, GL_LINEAR);
    texAwesomeface = loadTexture("awesomeface.png", GL_MIRRORED_REPEAT, GL_NEAREST);
    diffuseContainer = loadTexture("container_diffuse.png", GL_MIRRORED_REPEAT, GL_NEAREST);
    specularContainer = loadTexture("container_specular.png", GL_MIRRORED_REPEAT, GL_NEAREST);

GLuint loadTexture(string fileName, GLint REPEAT, GLint FILTER) 
    //创建纹理
    GLuint texture;
    glGenTextures(1, &texture);
    //绑定纹理
    glBindTexture(GL_TEXTURE_2D, texture);
    // 为当前绑定的纹理对象设置环绕、过滤方式

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, REPEAT);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, FILTER);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, FILTER);

    //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    // 加载纹理
    int width, height;
    unsigned char* image = SOIL_load_image(fileName.c_str(), &width, &height, 0, SOIL_LOAD_RGB);
    // 生成纹理
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
    glGenerateMipmap(GL_TEXTURE_2D);
    //释放图像的内存并解绑纹理对象
    SOIL_free_image_data(image);
    glBindTexture(GL_TEXTURE_2D, 0);

    return texture;


void vertexObjectInit() 
    //不使用索引缓冲对象用两个三角形绘制一个梯形
    // 设置顶点缓存和属性指针
    GLfloat vertices[] = 
        -0.5f, -0.5f, -0.5f, 0.0f,  0.0f, -1.0f,    0.0f, 0.0f,
        0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,    1.0f, 0.0f,
        0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,    1.0f, 1.0f,
        0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,    1.0f, 1.0f,
        -0.5f,  0.5f, -0.5f, 0.0f,  0.0f, -1.0f,    0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f, 0.0f,  0.0f, -1.0f,    0.0f, 0.0f,

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

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

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

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

        -0.5f,  0.5f, -0.5f, 0.0f,  1.0f,  0.0f, 0.0f, 1.0f,
        0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,1.0f, 1.0f,
        0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,1.0f, 0.0f,
        0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,1.0f, 0.0f,
        -0.5f,  0.5f,  0.5f, 0.0f,  1.0f,  0.0f, 0.0f, 0.0f,
        -0.5f,  0.5f, -0.5f, 0.0f,  1.0f,  0.0f, 0.0f, 1.0f
    ;
    //创建索引缓冲对象
    glGenBuffers(1, &VBO);

    // 把顶点数组复制到缓冲中供OpenGL使用
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glGenVertexArrays(1, &VAO);

    glBindVertexArray(VAO);
    // 位置属性
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    // 颜色属性
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
    glEnableVertexAttribArray(2);

    //glBindBuffer(GL_ARRAY_BUFFER, 0);// 这个方法将顶点属性指针注册到VBO作为当前绑定顶点对象,然后我们就可以安全的解绑
    glBindVertexArray(0);// 解绑 VAO (这通常是一个很好的用来解绑任何缓存/数组并防止奇怪错误的方法)



    glGenVertexArrays(1, &lightVAO);
    glBindVertexArray(lightVAO);
    // 只需要绑定VBO不用再次设置VBO的数据,因为容器(物体)的VBO数据中已经包含了正确的立方体顶点数据
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    // 设置灯立方体的顶点属性指针(仅设置灯的顶点数据)
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    // 颜色属性
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
    glEnableVertexAttribArray(2);
    glBindVertexArray(0);


int main()

    //初始化GLFW
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    //创建窗口对象
    GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
    if (window == nullptr)
    
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    
    glfwMakeContextCurrent(window);
    //注册键盘回调
    glfwSetKeyCallback(window, key_callback);
    //注册鼠标回调
    glfwSetCursorPosCallback(window, mouse_callback);
    //注册鼠标滚轮回到
    glfwSetScrollCallback(window, scroll_callback);
    //设置光标隐藏并捕获
    //glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
    //初始化GLEW
    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK)
    
        std::cout << "Failed to initialize GLEW" << std::endl;
        return -1;
    
    //告诉OpenGL渲染窗口尺寸大小
    int width, height;
    glfwGetFramebufferSize(window, &width, &height);

    glViewport(0, 0, width, height);

    glEnable(GL_DEPTH_TEST);
    //初始化并绑定shaders
    shaderInit();
    //初始化textures
    textureInit();
    //初始化顶点对象数据
    vertexObjectInit();

    mainCamera = Camera();
    //让窗口接受输入并保持运行
    while (!glfwWindowShouldClose(window))
    
        GLfloat currentFrame = glfwGetTime();
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;
        //检查事件
        glfwPollEvents();
        do_movement();

        //渲染指令
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        //GLfloat timeValue = glfwGetTime();
        //lightPos.x = lightPos.x+ sin(timeValue);
        //lightPos.y = lightPos.y + cos(timeValue);
        glm::vec3 lightColor; lightColor.x = sin(glfwGetTime() * 2.0f);
        lightColor.y = sin(glfwGetTime() * 0.7f);
        lightColor.z = sin(glfwGetTime() * 1.3f);

        //绘制光源
        model = glm::mat4();
        model = glm::translate(model, lightPos);
        model = glm::scale(model, glm::vec3(0.2f));
        lightintShader.Use();
        //GLint vertexColorLocation = glGetUniformLocation(lightintShader.Program, "offset");
        //glUniform4f(vertexColorLocation, offsetx, offsety, 0.0f, 1.0f);
        // 设置模型、视图和投影矩阵uniform
        modelLoc = glGetUniformLocation(lightintShader.Program, "model");
        glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
        viewLoc = glGetUniformLocation(lightintShader.Program, "view");
        glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
        projectionLoc = glGetUniformLocation(lightintShader.Program, "projection");
        glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
        GLint lightColorLoc = glGetUniformLocation(lightintShader.Program, "lightColor");
        glUniform3f(lightColorLoc, lightColor.x, lightColor.y, lightColor.z); // 依旧把光源设置为白色
                                                                              // 绘制灯立方体对象
        glBindVertexArray(lightVAO);
        glDrawArrays(GL_TRIANGLES, 0, 36);
        glBindVertexArray(0);



        //绘制箱子      
        shader.Use();
        //绑定两张贴图
        //glActiveTexture(GL_TEXTURE0);
        //glBindTexture(GL_TEXTURE_2D, texContainer);
        //glUniform1i(glGetUniformLocation(shader.Program, "ourTexture1"), 0);
        //glActiveTexture(GL_TEXTURE1);
        //glBindTexture(GL_TEXTURE_2D, texAwesomeface);
        //glUniform1i(glGetUniformLocation(shader.Program, "ourTexture2"), 1);      
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, diffuseContainer);
        glUniform1i(glGetUniformLocation(shader.Program, "material.diffuse"), 0);
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, specularContainer);
        glUniform1i(glGetUniformLocation(shader.Program, "material.specular"), 1);

        // 更新uniform值
        //设置混合比例
        GLint mixPar = glGetUniformLocation(shader.Program, "mixPar");
        glUniform1f(mixPar, key_UD);
        model = glm::rotate(model, (GLfloat)glfwGetTime() * 5.0f, glm::vec3(0.5f, 1.0f, 0.0f));
        view = mainCamera.GetViewMatrix();
        projection = glm::perspective(mainCamera.Zoom*scrollSpeed, (float)(WIDTH / HEIGHT), 0.1f, 100.0f);

        modelLoc = glGetUniformLocation(shader.Program, "model");
        glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
        viewLoc = glGetUniformLocation(shader.Program, "view");
        glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
        projectionLoc = glGetUniformLocation(shader.Program, "projection");
        glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));


        // 在此之前不要忘记首先'使用'对应的着色器程序(来设定uniform)
        GLint objectColorLoc = glGetUniformLocation(shader.Program, "objectColor");
        glUniform3f(objectColorLoc, 1.0f, 1.0f, 1.0f);// 我们所熟悉的珊瑚红
        GLint lightPosLoc = glGetUniformLocation(shader.Program, "lightPos");
        glUniform3f(lightPosLoc, lightPos.x, lightPos.y, lightPos.z);
        GLint viewPosLoc = glGetUniformLocation(shader.Program, "viewPos");
        glUniform3f(viewPosLoc, mainCamera.Position.x, mainCamera.Position.y, mainCamera.Position.z);

        //设置材质参数

        GLint matShineLoc = glGetUniformLocation(shader.Program, "material.shininess");
        glUniform1f(matShineLoc, 32.0f);

        //设置光照参数
        GLint lightAmbientLoc = glGetUniformLocation(shader.Program, "light.ambient");
        GLint lightDiffuseLoc = glGetUniformLocation(shader.Program, "light.diffuse");
        GLint lightSpecularLoc = glGetUniformLocation(shader.Program, "light.specular");

        glm::vec3 diffuseColor = lightColor * glm::vec3(0.5f);
        glm::vec3 ambientColor = diffuseColor * glm::vec3(0.2f);
        glUniform3f(lightAmbientLoc, ambientColor.x, ambientColor.y, ambientColor.z);
        glUniform3f(lightDiffuseLoc, diffuseColor.x, diffuseColor.y, diffuseColor.z);

        //glUniform3f(lightAmbientLoc, 0.2f, 0.2f, 0.2f);
        //glUniform3f(lightDiffuseLoc, 0.5f, 0.5f, 0.5f);
        glUniform3f(lightSpecularLoc, 1.0f, 1.0f, 1.0f);


        glm::vec3 cubePositions[] = 
            glm::vec3(0.0f,  0.0f,  0.0f),
            glm::vec3(2.0f,  5.0f, -15.0f),
            glm::vec3(-1.5f, -2.2f, -2.5f),
            glm::vec3(-3.8f, -2.0f, -12.3f),
            glm::vec3(2.4f, -0.4f, -3.5f),
            glm::vec3(-1.7f,  3.0f, -7.5f),
            glm::vec3(1.3f, -2.0f, -2.5f),
            glm::vec3(1.5f,  2.0f, -2.5f),
            glm::vec3(1.5f,  0.2f, -1.5f),
            glm::vec3(-1.3f,  1.0f, -1.5f)
        ;

        glBindVertexArray(VAO);
        for (GLuint i = 0; i < 10; i++)
        
            glm::mat4 model;
            model = glm::translate(model, cubePositions[i]);
            if (i < 4) 
                GLfloat angle = (GLfloat)glfwGetTime()*5.0f * i;
                model = glm::rotate(model, angle, glm::vec3(1.0f, 0.3f, 0.5f));
                glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
            
            else
            
                glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
            
            glDrawArrays(GL_TRIANGLES, 0, 36);
        
        glBindVertexArray(0);

        //交换缓冲
        glfwSwapBuffers(window);
    
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);

    //释放资源
    glfwTerminate();
    return 0;

void do_movement()

    // 摄像机控制
    GLfloat cameraSpeed = 5.0f* deltaTime;
    if (keys[GLFW_KEY_W])
        mainCamera.ProcessKeyboard(FORWARD, deltaTime);
    if (keys[GLFW_KEY_S])
        mainCamera.ProcessKeyboard(BACKWARD, deltaTime);
    if (keys[GLFW_KEY_A])
        mainCamera.ProcessKeyboard(LEFT, deltaTime);
    if (keys[GLFW_KEY_D])
        mainCamera.ProcessKeyboard(RIGHT, deltaTime);

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)

    // 当用户按下ESC键,我们设置window窗口的WindowShouldClose属性为true
    // 关闭应用程序
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
    if (key == GLFW_KEY_UP&& action == GLFW_PRESS)//按下UP键增加混合比例
        key_UD = key_UD + 0.1f;
    if (key == GLFW_KEY_DOWN&& action == GLFW_PRESS)//按下DOWN减小混合比例
        key_UD = key_UD - 0.1f;

    if (action == GLFW_PRESS)
        keys[key] = true;
    else if (action == GLFW_RELEASE)
        keys[key] = false;

void mouse_callback(GLFWwindow* window, double xpos, double ypos)

    if (firstMouse)
    
        lastX = xpos;
        lastY = ypos;
        firstMouse = false;
    

    GLfloat xoffset = xpos - lastX;
    GLfloat yoffset = lastY - ypos;  // Reversed since y-coordinates go from bottom to left 

    lastX = xpos;
    lastY = ypos;

    mainCamera.ProcessMouseMovement(xoffset, yoffset);



void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)

    cout << yoffset << endl;
    mainCamera.ProcessMouseScroll(yoffset);

结果:

可以看到金属边框产生了高光但是木质材质没有高光。

以上是关于LearnOpenGL学习笔记9:材质的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL光照2:材质

Unity学习笔记2:材质与着色器

Unity学习笔记2:材质与着色器

Unity学习笔记2:材质与着色器

unity3d 材质概述 ---- shader

vray学习笔记