今天我们开始学习光照贴图.我们原始的模型如下
我们会给这个箱子进行漫散射 和镜面光处理
当前shader 编码
precision mediump float;
uniform vec3 viewPos;
varying lowp vec3 normal;
varying lowp vec3 FragPos;
varying lowp vec2 v_texture;
uniform sampler2D u_samplers2D[1];
void main(){
// 环境光
vec4 textureColor = texture2D(u_samplers2D[0],v_texture);
gl_FragColor = textureColor;
}
precision lowp float;
attribute vec3 beginPostion; ///开始位置
attribute vec2 a_texture; //纹理贴图
attribute vec3 a_normal; //法向量
uniform mat4 u_mvpMatrix;
uniform mat4 u_model;
uniform mat4 u_inverModel;
varying lowp vec3 normal;
varying lowp vec3 FragPos;
varying lowp vec2 v_texture;
void main(){
gl_Position =u_mvpMatrix *u_model* vec4(beginPostion, 1.0);
FragPos = vec3(u_model * vec4(beginPostion, 1.0));
normal = mat3(u_inverModel) * a_normal;;
v_texture = a_texture;
}
漫反射贴图
从上一节我们知道我们定义的材质是
struct Material{
vec3 ambient;
vec3 diffuse;
vec3 specular;
float shininess;
};
我们可以把 vec3 diffuse;
替换成纹理贴图 sampler2D diffuse;
因此,光照贴图的格式是
struct Material{
vec3 ambient;
sampler2D diffuse;
vec3 specular;
float shininess;
};
其实这里我们可以把vec3 ambient;
移除掉,因为环境光颜色在几乎所有情况下都等于漫反射颜色,所以我们不需要将它们分开储存:
最终结构我们可以定义为
struct Material{
sampler2D diffuse;
vec3 specular;
float shininess;
};
uniform Material material;
通过uniform 进行传值
这里我们获取的 diffuse 的方式是如下
vec3 diffuseT =vec3(texture2D(material.diffuse,v_texture));
之后用该值进行计算
最终shader 修改如下
precision lowp float;
attribute vec3 beginPostion; ///开始位置
attribute vec2 a_texture; //纹理贴图
attribute vec3 a_normal; //法向量
uniform mat4 u_mvpMatrix;
uniform mat4 u_model;
uniform mat4 u_inverModel;
varying lowp vec3 normal;
varying lowp vec3 FragPos;
varying lowp vec2 v_texture;
void main(){
gl_Position =u_mvpMatrix *u_model* vec4(beginPostion, 1.0);
FragPos = vec3(u_model * vec4(beginPostion, 1.0));
normal = mat3(u_inverModel) * a_normal;;
v_texture = a_texture;
}
precision mediump float;
uniform vec3 viewPos;
varying lowp vec3 normal;
varying lowp vec3 FragPos;
varying lowp vec2 v_texture;
struct Light{
vec3 lightPos;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Light light;
struct Material{
sampler2D diffuse;
vec3 specular;
float shininess;
};
uniform Material material;
void main(){
// 环境光
vec3 diffuseT =vec3(texture2D(material.diffuse,v_texture));
vec3 ambient = light.ambient * diffuseT;
// 漫反射
vec3 norm = normalize(normal);
vec3 lightDir = normalize(light.lightPos - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = light.diffuse * (diff * diffuseT);
// 镜面光
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess*128.0);
vec3 specular = light.specular * (spec * material.specular);
vec3 result = ambient + diffuse + specular;
gl_FragColor =vec4(result, 1.0);;
}
效果如下
镜面光贴图
你可能会注意到,镜面高光看起来有些奇怪,因为我们的物体大部分都是木头,我们知道木头不应该有这么强的镜面高光的。
我们可以将物体的镜面光材质设置为vec3(0.0)来解决这个问题,但这也意味着箱子钢制的边框将不再能够显示镜面高光了,我们知道钢铁应该是有一些镜面高光的。所以,我们想要让物体的某些部分以不同的强度显示镜面高光。这个问题看起来和漫反射贴图非常相似。是巧合吗?我想不是。
我们同样可以使用一个专门用于镜面高光的纹理贴图。这也就意味着我们需要生成一个黑白的(如果你想得话也可以是彩色的)纹理,来定义物体每部分的镜面光强度。
镜面高光的强度可以通过图像每个像素的亮度来获取。镜面光贴图上的每个像素都可以由一个颜色向量来表示,比如说黑色代表颜色向量vec3(0.0),灰色代表颜色向量vec3(0.5)。在片段着色器中,我们接下来会取样对应的颜色值并将它乘以光源的镜面强度。一个像素越「白」,乘积就会越大,物体的镜面光分量就会越亮。
由于箱子大部分都由木头所组成,而且木头材质应该没有镜面高光,所以漫反射纹理的整个木头部分全部都转换成了黑色。箱子钢制边框的镜面光强度是有细微变化的,钢铁本身会比较容易受到镜面高光的影响,而裂缝则不会。
其实思路一样,就是讲
vec3 specular
替换成sampler2D specular;
就可以,我们通过纹理图获取亮度
struct Material{
sampler2D diffuse;
sampler2D specular;
float shininess;
};
shader 计算方式
// 镜面光
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess*128.0);
vec3 specular = light.specular * (spec * specularT);
最终我们给木箱设置镜面光贴图的结果
镜面光的顶点着色器没有变化,变化的只是片段着色器. 如下
precision mediump float;
uniform vec3 viewPos;
varying lowp vec3 normal;
varying lowp vec3 FragPos;
varying lowp vec2 v_texture;
struct Light{
vec3 lightPos;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Light light;
struct Material{
sampler2D diffuse;
sampler2D specular;
float shininess;
};
uniform Material material;
void main(){
// 环境光
vec3 diffuseT =vec3(texture2D(material.diffuse,v_texture));
vec3 specularT =vec3(texture2D(material.specular,v_texture));
vec3 ambient = light.ambient * diffuseT;
// 漫反射
vec3 norm = normalize(normal);
vec3 lightDir = normalize(light.lightPos - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = light.diffuse * (diff * diffuseT);
// 镜面光
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess*128.0);
vec3 specular = light.specular * (spec * specularT);
vec3 result = ambient + diffuse + specular;
gl_FragColor =vec4(result, 1.0);;
}
最终重点代码汇总
#import "GLBaseViewController.h"
NS_ASSUME_NONNULL_BEGIN
@interface SpecularLightTextureViewController : GLBaseViewController
@end
NS_ASSUME_NONNULL_END
#import "SpecularLightTextureViewController.h"
#import "SpecularLightTextureBindObject.h"
#import "CubeManager.h"
@interface SpecularLightTextureViewController ()
@property (nonatomic ,strong) Vertex * vertexPostion ;
@property (nonatomic ,strong) Vertex * vertexTexture ;
@property (nonatomic ,strong) Vertex * vertexNormal ;
@property (nonatomic ,strong) TextureUnit * textureDiffuse ;
@property (nonatomic ,strong) TextureUnit * textureSpecular ;
@end
@implementation SpecularLightTextureViewController
-(void)initSubObject{
//生命周期三秒钟
__weakSelf
self.bindObject = [SpecularLightTextureBindObject new];
self.bindObject.uniformSetterBlock = ^(GLuint program) {
weakSelf.bindObject->uniforms[MVPMatrix] = glGetUniformLocation(self.shader.program, "u_mvpMatrix");
weakSelf.bindObject->uniforms[SLT_SpecluarLightTextureUniformLocationModel] = glGetUniformLocation(self.shader.program, "u_model");
weakSelf.bindObject->uniforms[SLT_SpecluarLightTextureUniformLocationInvermodel] = glGetUniformLocation(self.shader.program, "u_inverModel");
weakSelf.bindObject->uniforms[SLT_SpecluarLightTextureUniformLocationviewPos] = glGetUniformLocation(self.shader.program, "viewPos");
weakSelf.bindObject->uniforms[SLT_MaterialTextureUniformLocationMaterialTextureDiffuse] = glGetUniformLocation(self.shader.program, "material.diffuse");
weakSelf.bindObject->uniforms[SLT_MaterialTextureUniformLocationMaterialTextureSpecular] = glGetUniformLocation(self.shader.program, "material.specular");
weakSelf.bindObject->uniforms[SLT_MaterialTextureUniformLocationMaterialTextureShininess] = glGetUniformLocation(self.shader.program, "material.shininess");
weakSelf.bindObject->uniforms[SLT_SpecluarLightTextureUniformLocationSpecluarLightTexturePos] = glGetUniformLocation(self.shader.program, "light.lightPos");
weakSelf.bindObject->uniforms[SLT_SpecluarLightTextureUniformLocationSpecluarLightTextureAmbient] = glGetUniformLocation(self.shader.program, "light.ambient");
weakSelf.bindObject->uniforms[SLT_SpecluarLightTextureUniformLocationSpecluarLightTexturesSpecular] = glGetUniformLocation(self.shader.program, "light.specular");
weakSelf.bindObject->uniforms[SLT_SpecluarLightTextureUniformLocationSpecluarLightTextureDiffuse] = glGetUniformLocation(self.shader.program, "light.diffuse");
};
}
-(void)createShader{
__weakSelf
self.shader = [Shader new];
[self.shader compileLinkSuccessShaderName:self.bindObject.getShaderName completeBlock:^(GLuint program) {
[self.bindObject BindAttribLocation:program];
}];
if (self.bindObject.uniformSetterBlock) {
self.bindObject.uniformSetterBlock(self.shader.program);
}
}
-(void)createTextureUnit{
UIImage * image = [UIImage imageNamed:@"container2.png"];
self.textureDiffuse = [TextureUnit new];
[self.textureDiffuse setImage:image IntoTextureUnit:GL_TEXTURE0 andConfigTextureUnit:nil];
image = [UIImage imageNamed:@"container2_specular.png"];
self.textureSpecular =[TextureUnit new];
[self.textureSpecular setImage:image IntoTextureUnit:GL_TEXTURE1 andConfigTextureUnit:nil];
}
-(void)loadVertex{
//顶点数据缓存
self.vertexPostion= [Vertex new];
int vertexNum =[CubeManager getTextureNormalVertexNum];
[self.vertexPostion allocVertexNum:vertexNum andEachVertexNum:3];
for (int i=0; iuniforms[SLT_MaterialTextureUniformLocationMaterialTextureDiffuse]];
[self.textureSpecular bindtextureUnitLocationAndShaderUniformSamplerLocation:self.bindObject->uniforms[SLT_MaterialTextureUniformLocationMaterialTextureSpecular]];
glUniform3fv(self.bindObject->uniforms[SLT_MaterialTextureUniformLocationMaterialTextureSpecular], 1, &material.specular);
glUniform1fv(self.bindObject->uniforms[SLT_MaterialTextureUniformLocationMaterialTextureShininess], 1, &material.shininess);
SLT_Light light;
light.lightPos = GLKVector3Make(5.0, 0.0,0);
light.ambient =GLKVector3Make(0.2,0.2,0.2);
light.diffuse =GLKVector3Make(0.5,0.5,0.5);
light.specular =GLKVector3Make(1.0,1.0,1.0);
glUniform3fv(self.bindObject->uniforms[SLT_SpecluarLightTextureUniformLocationSpecluarLightTexturePos], 1, &light.lightPos);
glUniform3fv(self.bindObject->uniforms[SLT_SpecluarLightTextureUniformLocationSpecluarLightTextureAmbient], 1, &light.ambient);
glUniform3fv(self.bindObject->uniforms[SLT_SpecluarLightTextureUniformLocationSpecluarLightTexturesSpecular], 1, &light.specular);
glUniform3fv(self.bindObject->uniforms[SLT_SpecluarLightTextureUniformLocationSpecluarLightTextureDiffuse], 1, &light.diffuse);
}
-(GLKMatrix4)getMVP{
GLfloat aspectRatio= CGRectGetWidth([UIScreen mainScreen].bounds) / CGRectGetHeight([UIScreen mainScreen].bounds);
GLKMatrix4 projectionMatrix =
GLKMatrix4MakePerspective(
GLKMathDegreesToRadians(85.0f),
aspectRatio,
0.1f,
20.0f);
GLKMatrix4 modelviewMatrix =
GLKMatrix4MakeLookAt(
0.0, 0.0, 2.0, // Eye position
0.0, 0.0, 0.0, // Look-at position
0.0, 1.0, 0.0); // Up direction
return GLKMatrix4Multiply(projectionMatrix,modelviewMatrix);
}
-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glClearColor(1, 1, 1, 1);
GLKMatrix4 mvp= [self getMVP];
static GLfloat angle=0;
angle ++ ;
angle = 47;
GLKMatrix4 mode =GLKMatrix4MakeRotation(angle*M_PI/180, 0, 1, 0);
glUniformMatrix4fv(self.bindObject->uniforms[MVPMatrix], 1, 0,mvp.m);
glUniformMatrix4fv(self.bindObject->uniforms[SLT_SpecluarLightTextureUniformLocationModel], 1, 0,mode.m);
bool isSuccess = YES;
mode = GLKMatrix4InvertAndTranspose(mode,&isSuccess);
glUniformMatrix4fv(self.bindObject->uniforms[SLT_SpecluarLightTextureUniformLocationInvermodel], 1, 0,mode.m);
GLKVector3 viewPos = GLKVector3Make(.0, 0.0,2.0);
glUniform3fv(self.bindObject->uniforms[SLT_SpecluarLightTextureUniformLocationviewPos], 1,viewPos.v);
[self.vertexPostion drawVertexWithMode:GL_TRIANGLES startVertexIndex:0 numberOfVertices:[CubeManager getNormalVertexNum]];
}
@end
#import "GLBaseBindObject.h"
NS_ASSUME_NONNULL_BEGIN
typedef enum {
SLT_SpecluarLightTextureBindAttribLocationBegin = BaseBindLocationEnd,
SLT_SpecluarLightTextureBindAttribLocationTexture,
SLT_SpecluarLightTextureBindAttribLocationNormal
}SLT_SpecluarLightTextureBindAttribLocation;
typedef union {
struct {
BaseBindAttribType baseBindAttrib;
GLKVector2 texture;
GLKVector3 normal;
};
float t[8];
}SLT_SpecluarLightTextureBindAttrib;
typedef union{
struct {
GLKVector3 lightPos;
GLKVector3 ambient;
GLKVector3 diffuse;
GLKVector3 specular;
};
float m[12];
}SLT_Light;
typedef struct{
int diffuse;
int specular;
float shininess;
}SLT_Material;
typedef enum {
SLT_SpecluarLightTextureUniformLocationBegin = BaseUniformLocationEnd,
SLT_SpecluarLightTextureUniformLocationModel,
SLT_SpecluarLightTextureUniformLocationInvermodel,
SLT_SpecluarLightTextureUniformLocationviewPos,
SLT_SpecluarLightTextureUniformLocationSpecluarLightTexturePos, //
SLT_SpecluarLightTextureUniformLocationSpecluarLightTextureAmbient, //材质
SLT_SpecluarLightTextureUniformLocationSpecluarLightTextureDiffuse,
SLT_SpecluarLightTextureUniformLocationSpecluarLightTexturesSpecular,
SLT_MaterialTextureUniformLocationMaterialTextureDiffuse,
SLT_MaterialTextureUniformLocationMaterialTextureSpecular,
SLT_MaterialTextureUniformLocationMaterialTextureShininess
}SLT_SpecluarLightTextureUniformLocation;
@interface SpecularLightTextureBindObject : GLBaseBindObject
@end
NS_ASSUME_NONNULL_END
#import "SpecularLightTextureBindObject.h"
@implementation SpecularLightTextureBindObject
-(void)BindAttribLocation:(GLuint)program{
glBindAttribLocation(program, BeginPosition, "beginPostion");
glBindAttribLocation(program, SLT_SpecluarLightTextureBindAttribLocationNormal, "a_normal");
glBindAttribLocation(program, SLT_SpecluarLightTextureBindAttribLocationTexture, "a_texture");
}
-(NSString *)getShaderName{
return @"SpecluarLightTexture";
}
@end
precision lowp float;
attribute vec3 beginPostion; ///开始位置
attribute vec2 a_texture; //纹理贴图
attribute vec3 a_normal; //法向量
uniform mat4 u_mvpMatrix;
uniform mat4 u_model;
uniform mat4 u_inverModel;
varying lowp vec3 normal;
varying lowp vec3 FragPos;
varying lowp vec2 v_texture;
void main(){
gl_Position =u_mvpMatrix *u_model* vec4(beginPostion, 1.0);
FragPos = vec3(u_model * vec4(beginPostion, 1.0));
normal = mat3(u_inverModel) * a_normal;;
v_texture = a_texture;
}
precision mediump float;
uniform vec3 viewPos;
varying lowp vec3 normal;
varying lowp vec3 FragPos;
varying lowp vec2 v_texture;
struct Light{
vec3 lightPos;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Light light;
struct Material{
sampler2D diffuse;
sampler2D specular;
float shininess;
};
uniform Material material;
void main(){
// 环境光
vec3 diffuseT =vec3(texture2D(material.diffuse,v_texture));
vec3 specularT =vec3(texture2D(material.specular,v_texture));
vec3 ambient = light.ambient * diffuseT;
// 漫反射
vec3 norm = normalize(normal);
vec3 lightDir = normalize(light.lightPos - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = light.diffuse * (diff * diffuseT);
// 镜面光
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess*128.0);
vec3 specular = light.specular * (spec * specularT);
vec3 result = ambient + diffuse + specular;
gl_FragColor =vec4(result, 1.0);;
}
箱子顶点
unsigned int cubetextureNormalNormalNumVerts = 36;
float textureNormalvertices[] = {
// positions // normals // texture coords
-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
};
源码地址 对应的demo是OpenGLZeroStudyDemo(7)-光照
参考文章