OpenGL ES的基础光照模型,目前opengl还无法模拟现实世界的复杂光照效果,但是为了效果上的逼真,还是引入了一些简单的模型来模拟光照效果,
这里介绍冯氏光照模型(Phong Lighting Model)模型,他是由三种元素光组成的,环境光,散射光,镜面光。
环境光:四面八方照射到物体上且各个方向都均匀的光,不依赖于光源位置,没有方向性。
要把环境光照添加到场景里,只需用光的颜色乘以一个(数值)很小常量环境因子,再乘以物体的颜色,然后使用它作为片段的颜色:
void main()
{
float ambientStrength = 0.1f; //常量环境因子
vec3 ambient = ambientStrength * lightColor; //环境光强度
vec3 result = ambient * objectColor;
color = vec4(result, 1.0f);
}
散射光:散射光表示从物体表面向各个方向均匀反射的光。散射光的强度与入射光的强度及入射角密切相关,所以当光源位置发生变化,散射光效果也会发生明显变化。
out vec3 fragPos;//当前片段坐标
out vec3 normal; //当前片段法向量
uniform vec3 lightPos;//光源位置
void main()
{
float diffuseStrength = 0.5f; //材质反射系数
vec3 norm = normalize(normal); // 归一化
vec3 lightDir = normalize(lightPos - fragPos);//当前片段光源照射方向向量
float diff = max(dot(norm, lightDir), 0.0);// dot 表示两个向量的点乘
vec3 diffuse = diffuseStrength * diff * lightColor; //散射光最终强度
vec3 result = diffuse * objectColor;
color = vec4(result, 1.0f);
}
镜面光:镜面光是由光滑物体表面反射的方向比较集中的光,镜面光强度不仅依赖于入射光与法向量的夹角,也依赖于观察者的位置。
out vec3 fragPos;//当前片段坐标
out vec3 normal; //当前片段法向量
uniform vec3 lightPos;//光源位置
void main()
{
float specularStrength = 0.5f;
vec3 norm = normalize(normal); // 归一化
vec3 viewDir = normalize(viewPos - FragPos); //视线方向向量
vec3 reflectDir = reflect(-lightDir, norm); //镜面反射光向量
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
//视线方向向量与镜面反射光向量点乘的32次幂,这个32是高光的发光值(Shininess)。一个物体的发光值越高,反射光的能力越强,散射得越少,高光点越小。
vec3 specular = specularStrength * spec * lightColor; //镜面光最终强度
vec3 result = specular * objectColor;
color = vec4(result, 1.0f);
}
java部分与坐标系统是一致的,都有利用触摸来旋转的功能。主要是C++不一样。
这里新引入一种绘画方法:glDrawArrays
//提供绘制功能,从数组数据中提取数据渲染基本图元
//GL_TRIANGLES:把每三个顶点作为一个独立的三角形,顶点3n-2、3n-1和3n定义了第n个三角形,总共绘制N/3个三角形
glDrawArrays(GL_TRIANGLES, 0, 36);
提供了很多顶点坐标然后通过这种绘制,将3个顶点绘制成一个三角形,一个正方形两个三角形,一个立方体是六个正方形。因此绘制一个立方体需要36个顶点数据。
顶点着色器
#version 300 es
precision mediump float;//默认float 片段着色器需要指定
layout (location = 0) in vec4 a_position;
layout (location = 1) in vec2 a_texCoord;
layout(location = 2) in vec3 a_normal;
uniform mat4 u_MVPMatrix;//坐标变化矩阵
uniform mat4 u_ModelMatrix;//光照模型
uniform vec3 lightPos;//光照坐标
uniform vec3 lightColor;//光照颜色
uniform vec3 viewPos;//观察者坐标
out vec2 v_texCoord;//输出到片段着色器的纹理坐标
out vec3 ambient;//环境光
out vec3 diffuse;//散光
out vec3 specular;//反射
void main()
{
gl_Position = u_MVPMatrix * a_position;
vec3 fragPos = vec3(u_ModelMatrix * a_position);
// Ambient环境光
float ambientStrength = 0.1;
ambient = ambientStrength * lightColor;
// Diffuse散光
float diffuseStrength = 0.5;
vec3 unitNormal = normalize(vec3(u_ModelMatrix * vec4(a_normal, 1.0)));
vec3 lightDir = normalize(lightPos - fragPos);
float diff = max(dot(unitNormal, lightDir), 0.0);
diffuse = diffuseStrength * diff * lightColor;
// Specular镜面
float specularStrength = 0.9;
vec3 viewDir = normalize(viewPos - fragPos);
vec3 reflectDir = reflect(-lightDir, unitNormal);
float spec = pow(max(dot(unitNormal, reflectDir), 0.0), 16.0);
specular = specularStrength * spec * lightColor;
v_texCoord = a_texCoord;
}
片段着色器
#version 300 es
precision mediump float;
layout(location = 0) out vec4 outColor;
in vec2 v_texCoord;
in vec3 ambient;
in vec3 diffuse;
in vec3 specular;
uniform sampler2D s_TextureMap;
void main()
{
vec4 objectColor = texture(s_TextureMap, v_texCoord);
vec3 finalColor = (ambient + diffuse + specular) * vec3(objectColor);
outColor = vec4(finalColor, 1.0);;
}
Basiclighting.h
//
// Created by CreatWall_zhouwen on 2023/5/10.
//
#ifndef SEVENBASICLIGHTING_BASICLIGHTING_H
#define SEVENBASICLIGHTING_BASICLIGHTING_H
#include
#include
#include
#define MATH_PI 3.1415926535897932384626433832802
class Basiclighting {
public:
Basiclighting(){
program = 0;
vertexShaderHandle = 0;
fragShaderHandle = 0;
m_ModelMatrix = glm::mat4(0.0f);
m_AngleX = 0;
m_AngleY = 0;
m_ScaleX = 1.0f;
m_ScaleY = 1.0f;
m_ModelMatrix = glm::mat4(0.0f);
};
~Basiclighting(){};
void CreateProgram(const char *ver, const char *frag);
void Draw();
void getTexturedata(unsigned char *data, int width, int height);
static Basiclighting* GetInstance();
static void DestroyInstance();
void OnSurfaceChanged(int width, int height);
void UpdateTransformMatrix(float rotateX, float rotateY, float scaleX, float scaleY);
void UpdateMVPMatrix(glm::mat4 &mvpMatrix, int angleX, int angleY, float ratio);
private:
GLuint program;
GLuint vertexShaderHandle;
GLuint fragShaderHandle;
GLuint m_VaoId;//存放顶点数据
GLuint m_VboId;//顶点缓冲区
unsigned int m_TextureId;
unsigned char *texturedata;
int texturewidth, textureheight;
int srceenWidth, srceenHeight;//屏幕宽高
GLint m_SamplerLoc;
GLint m_MVPMatLoc;
GLint m_ModelMatrixLoc;
GLint m_LightPosLoc;
GLint m_LightColorLoc;
GLint m_ViewPosLoc;
glm::mat4 m_MVPMatrix;
glm::mat4 m_ModelMatrix;
int m_AngleX;
int m_AngleY;
float m_ScaleX;
float m_ScaleY;
};
#endif //SEVENBASICLIGHTING_BASICLIGHTING_H
Basiclighting.cpp
//
// Created by CreatWall_zhouwen on 2023/5/10.
//
#include "Basiclighting.h"
#include "Util.h"
#include "GLUtil.h"
#include
Basiclighting* m_pContext = nullptr;
#define TAG "DRAWTEXTURE"
GLfloat vertices[] = {
//position //texture coord //normal
-0.5f, -0.5f, -0.5f, 0.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, 1.0f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 1.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, 0.0f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, 0.5f, 0.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, 1.0f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.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, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.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, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.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, 1.0f, 0.0f, 1.0f, 0.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, 1.0f, 1.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, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.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, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.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, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
};
void Basiclighting::CreateProgram(const char *ver, const char *frag) {
LOGD("CreateProgram Enter");
// 编译链接用于离屏渲染的着色器程序
program = CreateGLProgram(ver, frag, vertexShaderHandle, fragShaderHandle);
if (program == GL_NONE)
{
LOGD("FBOSample::Init m_ProgramObj == GL_NONE");
return;
}
LOGD("CreateGLProgram Success");
m_SamplerLoc = glGetUniformLocation(program, "s_TextureMap");
m_MVPMatLoc = glGetUniformLocation(program, "u_MVPMatrix");
m_ModelMatrixLoc = glGetUniformLocation(program, "u_ModelMatrix");
m_LightPosLoc = glGetUniformLocation(program, "lightPos");
m_LightColorLoc = glGetUniformLocation(program, "lightColor");
m_ViewPosLoc = glGetUniformLocation(program, "viewPos");
//创建VBO
glGenBuffers(1, &m_VboId);
glBindBuffer(GL_ARRAY_BUFFER, m_VboId);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//创建VAO绑定VAO和纹理
glGenVertexArrays(1, &m_VaoId);
glBindVertexArray(m_VaoId);
glBindBuffer(GL_ARRAY_BUFFER, m_VboId);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (const void *) 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (const void *) (3* sizeof(GLfloat)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (const void *) (5* sizeof(GLfloat)));
glBindBuffer(GL_ARRAY_BUFFER, GL_NONE);
glGenTextures(1, &m_TextureId);
glBindTexture(GL_TEXTURE_2D, m_TextureId);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//绑定纹理数据
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texturewidth, textureheight, 0, GL_RGB, GL_UNSIGNED_BYTE, texturedata);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, GL_NONE);
}
void Basiclighting::Draw() {
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glClearColor(0.2f, 0.9f, 0.3f, 1.0f);
UpdateMVPMatrix(m_MVPMatrix, m_AngleX, m_AngleY, (float) srceenWidth / srceenHeight);
glEnable(GL_DEPTH_TEST);//启用深度测试,注意glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);也要进行清除
glUseProgram(program);
glBindVertexArray(m_VaoId);
//设置参数
glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
glUniformMatrix4fv(m_ModelMatrixLoc, 1, GL_FALSE, &m_ModelMatrix[0][0]);
glUniform3f(m_LightColorLoc, 1.0f, 1.0f, 1.0f);
glUniform3f(m_LightPosLoc, -2.0f, 0.0f, 2.0f);
glUniform3f(m_ViewPosLoc, -3.0f, 0.0f, 3.0f);
//绑定纹理
glBindTexture(GL_TEXTURE_2D, m_TextureId);
glUniform1i(m_SamplerLoc, 0);
//提供绘制功能,从数组数据中提取数据渲染基本图元
//GL_TRIANGLES:把每三个顶点作为一个独立的三角形,顶点3n-2、3n-1和3n定义了第n个三角形,总共绘制N/3个三角形
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
}
Basiclighting *Basiclighting::GetInstance() {
if (m_pContext == nullptr)
{
m_pContext = new Basiclighting();
}
return m_pContext;
}
void Basiclighting::DestroyInstance() {
if (m_pContext)
{
delete m_pContext;
m_pContext = nullptr;
}
}
void Basiclighting::getTexturedata(unsigned char *data, int width, int height) {
texturedata = data;
texturewidth = width;
textureheight = height;
}
void Basiclighting::OnSurfaceChanged(int width, int height) {
glViewport(0, 0, width, height);
srceenWidth = width;
srceenHeight = height;
}
void Basiclighting::UpdateTransformMatrix(float rotateX, float rotateY, float scaleX, float scaleY) {
m_AngleX = static_cast(rotateX);
m_AngleY = static_cast(rotateY);
m_ScaleX = scaleX;
m_ScaleY = scaleY;
}
void Basiclighting::UpdateMVPMatrix(glm::mat4 &mvpMatrix, int angleX, int angleY, float ratio) {
LOGD("BasicLightingSample::UpdateMVPMatrix angleX = %d, angleY = %d, ratio = %f", angleX,
angleY, ratio);
angleX = angleX % 360;
angleY = angleY % 360;
//转化为弧度角
float radiansX = static_cast(MATH_PI / 180.0f * angleX);
float radiansY = static_cast(MATH_PI / 180.0f * angleY);
// Projection matrix
//glm::mat4 Projection = glm::ortho(-ratio, ratio, -1.0f, 1.0f, 0.0f, 100.0f);
//glm::mat4 Projection = glm::frustum(-ratio, ratio, -1.0f, 1.0f, 4.0f, 100.0f);
glm::mat4 Projection = glm::perspective(45.0f, ratio, 0.1f, 100.f);
// View matrix
glm::mat4 View = glm::lookAt(
glm::vec3(-3, 0, 3), // Camera is at (0,0,1), in World Space
glm::vec3(0, 0, 0), // and looks at the origin
glm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down)
);
// Model matrix
glm::mat4 Model = glm::mat4(1.0f);
Model = glm::scale(Model, glm::vec3(m_ScaleX, m_ScaleX, m_ScaleX));
Model = glm::rotate(Model, radiansX, glm::vec3(1.0f, 0.0f, 0.0f));
Model = glm::rotate(Model, radiansY, glm::vec3(0.0f, 1.0f, 0.0f));
Model = glm::translate(Model, glm::vec3(0.0f, 0.0f, 0.0f));
m_ModelMatrix = Model;
mvpMatrix = Projection * View * Model;
}