LearnOpenGL 材质
2020-10-05 本文已影响0人
li_礼光
材质
材质在渲染程式中,它是表面各可视属性的结合,这些可视属性是指表面的色彩、纹理、光滑度、透明度、反射率、折射率、发光度等。正是有了这些属性,才能让我们识别三维中的模型是什么做成的,也正是有了模型材质。
我们在OpenGL中模拟多种类型的物体, 我们必须为每个物体分别定义材质(Material)属性.
类似面向对象编程, 比如当前类应该具有什么内容.
在片元着色器中
用结构体定义一个材质的组成
//材质
struct Material {
vec3 ambient;//材质向量定义了在环境光照下这个物体反射的是什么颜色,通常和物体颜色相同.
vec3 diffuse;//材质向量定义了在漫反射光照t下物体的颜色,漫反射颜色被设置为我们需要的物体颜色.
vec3 specular;//材质向量设置的是物体受到的镜面光照的影响的颜色.
float shininess;//镜面反射散射因子(半径).
};
uniform Material material;//材质
用结构体定义一个材质的光照强度组成
//光照强度
struct Light {
vec3 position;
vec3 ambientStrength;//环境光照强度
vec3 diffuseStrength;//漫反射光照强度
vec3 specularStrength;//镜面反射光照强度
};
uniform Light light;
赋值操作
//材质
GLint matAmbientLoc = glGetUniformLocation(myProgram.program, "material.ambient");
GLint matDiffuseLoc = glGetUniformLocation(myProgram.program, "material.diffuse");
GLint matSpecularLoc = glGetUniformLocation(myProgram.program, "material.specular");
GLint matShineLoc = glGetUniformLocation(myProgram.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, 64.0f);
//光照强度
GLint lightAmbientStrengthLoc = glGetUniformLocation(myProgram.program, "light.ambientStrength");
GLint lightDiffuseStrengthLoc = glGetUniformLocation(myProgram.program, "light.diffuseStrength");
GLint lightSpecularStrengthLoc = glGetUniformLocation(myProgram.program, "light.specularStrength");
glUniform3f(lightAmbientStrengthLoc, 0.2f, 0.2f, 0.2f);
glUniform3f(lightDiffuseStrengthLoc, 0.5f, 0.5f, 0.5f);
glUniform3f(lightSpecularStrengthLoc, 1.0f, 1.0f, 1.0f);
Shader
#define STRINGIZE(x) #x
#define SHADER(shader) STRINGIZE(shader)
/// 着色器程序之间的数据传递
static char *myMaterialVertexShaderStr = SHADER(
\#version 330 core\n
layout (location = 0) in vec3 position; //顶点数据源输入
layout (location = 1) in vec3 normal; //法向量
uniform mat4 myProjection;//投影矩阵
uniform mat4 myView;//观察矩阵
uniform mat4 myModel;//模型矩阵
out vec3 Normal;//法线向量
out vec3 FragPos;//片段位置
void main()
{
gl_Position = myProjection * myView * myModel * vec4(position, 1.0f);
Normal = normal;
FragPos = vec3(myModel * vec4(position, 1.0f) );
}
);
//片元着色器程序
static char *myMaterialFragmentShaderSrc = SHADER(
\#version 330 core\n
//材质
struct Material {
vec3 ambient;//材质向量定义了在环境光照下这个物体反射的是什么颜色,通常和物体颜色相同.
vec3 diffuse;//材质向量定义了在漫反射光照t下物体的颜色,漫反射颜色被设置为我们需要的物体颜色.
vec3 specular;//材质向量设置的是物体受到的镜面光照的影响的颜色.
float shininess;//镜面反射散射因子(半径).
};
uniform Material material;//材质
//光照强度
struct Light {
vec3 position;
vec3 ambientStrength;//环境光照强度
vec3 diffuseStrength;//漫反射光照强度
vec3 specularStrength;//镜面反射光照强度
};
uniform Light light;
in vec3 Normal;
in vec3 FragPos;
uniform vec3 lightColor;//光照颜色
uniform vec3 lightPos;//光源位置
uniform vec3 viewPos;//镜面反射
out vec4 color;
void main()
{
//环境光ambient
//环境颜色 = 光源颜色 × 物体的环境材质颜色 × 环境光照强度
vec3 ambient = lightColor * material.ambient * light.ambientStrength;
//漫反射diffuse
//DiffuseFactor = max(0, dot(N, L))
//漫反射颜色 = 光源颜色 × 物体的漫反射材质颜色 × 漫反射因子(diffuseFactor) × 漫反射光照强度
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(lightPos - FragPos);
float diffuseFactor = max(dot(norm, lightDir),0.0);
vec3 diffuse = lightColor * material.ambient * diffuseFactor * light.diffuseStrength;
//镜面反射specular
//R=reflect(L, N)
//SpecularFactor = pow(max(dot(R,V),0.0), shininess)
//镜面反射颜色 = 光源颜色 × 物体的镜面材质颜色 × 镜面反射因子(SpecularFactor) × 镜面反射光照强度
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir , norm);
float specularFactor = pow(max(dot(viewDir, reflectDir),0.0),material.shininess);
vec3 specular = lightColor * material.ambient * specularFactor * light.specularStrength;
//最终片段颜色:环境颜色+漫反射颜色+镜面反射颜色
vec3 result = ambient + diffuse + specular;
color = vec4(result , 1.0f);
}
);
顶点数据
#include "glad.h"
#include <GLFW/glfw3.h>
GLfloat myMaterialVertices[] = {
//顶点数据 法线
-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,
};
程序
#include <iostream>
#include "MyMaterial.hpp"
#include "MyProgram.hpp"
#include "MyMaterialShader.h"
#include "MyMaterialVertices.h"
#include "glm.hpp"
#include "matrix_transform.hpp"
#include "type_ptr.hpp"
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_STATIC
#include "stb_image.h"
int runMyMaterialCube() {
int result = glfwInit();
if (result == GL_FALSE) {
printf("glfwInit 初始化失败");
return -1;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
GLFWwindow *window = glfwCreateWindow(600, 400, "My Opengl Window", NULL, NULL);
if(!window) {
printf("window 创建失败");
}
glfwMakeContextCurrent(window);
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
//切换为纹理着色器程序
MyProgram myProgram = MyProgram(myMaterialVertexShaderStr, myMaterialFragmentShaderSrc);
///
GLuint VBO , VAO ;
unsigned int squareIndicesCount = 0;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(myMaterialVertices), myMaterialVertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(0 * sizeof(GLfloat)));
glEnableVertexAttribArray(0);
//法线
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
//解绑VAO
glBindVertexArray(0);
squareIndicesCount = sizeof(myMaterialVertices)/(sizeof(myMaterialVertices[0]) * 5);
glEnable(GL_DEPTH_TEST);
//进行绘制
while(!glfwWindowShouldClose(window)){
glfwPollEvents();
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(myProgram.program);
//================================================
glm::mat4 model = glm::mat4(1.0f);
glm::mat4 view = glm::mat4(1.0f);
glm::mat4 projection = glm::mat4(1.0f);
GLint myModelLoc = glGetUniformLocation(myProgram.program,"myModel");
GLint myViewLoc = glGetUniformLocation(myProgram.program,"myView");
GLint myProjectionLoc = glGetUniformLocation(myProgram.program,"myProjection");
projection = glm::perspective(glm::radians(60.0f), 1.0f, 0.01f, 100.f);//投影矩阵
glUniformMatrix4fv(myProjectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
// model = glm::rotate(model,(GLfloat)glfwGetTime() * 1.0f, glm::vec3(1.0f,0.0f,0.0f));//以x,y轴旋转
glUniformMatrix4fv(myModelLoc, 1, GL_FALSE, glm::value_ptr(model));
// Material
glm::vec3 MaterialEye = glm::vec3(2.0f, 2.0f, 2.0f);
glm::vec3 MaterialCenter = glm::vec3(0.0f, 0.0f, 0.0f);
glm::vec3 MaterialUp = glm::vec3(0.0f, 1.0f, 0.0f);
glBindVertexArray(VAO);
view = glm::lookAt(MaterialEye, //摄像机位置
MaterialCenter, //目标
MaterialUp); //上向量
//================================================
//================================================
//材质
GLint matAmbientLoc = glGetUniformLocation(myProgram.program, "material.ambient");
GLint matDiffuseLoc = glGetUniformLocation(myProgram.program, "material.diffuse");
GLint matSpecularLoc = glGetUniformLocation(myProgram.program, "material.specular");
GLint matShineLoc = glGetUniformLocation(myProgram.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, 64.0f);
//光照强度
GLint lightAmbientStrengthLoc = glGetUniformLocation(myProgram.program, "light.ambientStrength");
GLint lightDiffuseStrengthLoc = glGetUniformLocation(myProgram.program, "light.diffuseStrength");
GLint lightSpecularStrengthLoc = glGetUniformLocation(myProgram.program, "light.specularStrength");
glUniform3f(lightAmbientStrengthLoc, 0.2f, 0.2f, 0.2f);
glUniform3f(lightDiffuseStrengthLoc, 0.5f, 0.5f, 0.5f);
glUniform3f(lightSpecularStrengthLoc, 1.0f, 1.0f, 1.0f);
//光源位置
GLint myLightPosLoc = glGetUniformLocation(myProgram.program,"lightPos");
glUniform3f(myLightPosLoc,1.0f,0.0f,4.0f); //
//镜面反射
GLint myViewPosLoc = glGetUniformLocation(myProgram.program,"viewPos");
glUniform3f(myViewPosLoc,0.0,0.0f,3.0f); //
//光照颜色
GLint lightColorLoc = glGetUniformLocation(myProgram.program,"lightColor");
glUniform3f(lightColorLoc,1.0f,1.0f,1.0f); //白光
//动态改变环境光和漫反射光颜色
glm::vec3 lightColor = glm::vec3(1.0f,1.0f,1.0f);
lightColor.x = sin(glfwGetTime() * 2.0f);
lightColor.y = sin(glfwGetTime() * 0.7f);
lightColor.z = sin(glfwGetTime() * 1.3f);
glm::vec3 ambientColor = lightColor * glm::vec3(0.5f);
glm::vec3 diffuseColor = lightColor * glm::vec3(0.5f);
glUniform3f(matAmbientLoc,ambientColor.x,ambientColor.y,ambientColor.z);
glUniform3f(matDiffuseLoc,diffuseColor.x,diffuseColor.y,diffuseColor.z);
//================================================
glUniformMatrix4fv(myViewLoc, 1, GL_FALSE, glm::value_ptr(view));
glDrawArrays(GL_TRIANGLES, 0, squareIndicesCount);
glBindVertexArray(0);
glfwSwapBuffers(window);
}
//程序销毁
glfwTerminate();
return 1;
}
效果

趣味效果: 动态改变环境光照和漫反射
//动态改变环境光和漫反射光颜色
glm::vec3 lightColor = glm::vec3(1.0f,1.0f,1.0f);
lightColor.x = sin(glfwGetTime() * 2.0f);
lightColor.y = sin(glfwGetTime() * 0.7f);
lightColor.z = sin(glfwGetTime() * 1.3f);
glm::vec3 ambientColor = lightColor * glm::vec3(0.5f);
glm::vec3 diffuseColor = lightColor * glm::vec3(0.5f);
glUniform3f(matAmbientLoc,ambientColor.x,ambientColor.y,ambientColor.z);
glUniform3f(matDiffuseLoc,diffuseColor.x,diffuseColor.y,diffuseColor.z);
