重新自学学习openGL 之光照贴图

今天我们开始学习光照贴图.我们原始的模型如下

我们会给这个箱子进行漫散射 和镜面光处理
当前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)来解决这个问题,但这也意味着箱子钢制的边框将不再能够显示镜面高光了,我们知道钢铁应该是有一些镜面高光的。所以,我们想要让物体的某些部分以不同的强度显示镜面高光。这个问题看起来和漫反射贴图非常相似。是巧合吗?我想不是。

我们同样可以使用一个专门用于镜面高光的纹理贴图。这也就意味着我们需要生成一个黑白的(如果你想得话也可以是彩色的)纹理,来定义物体每部分的镜面光强度。

image

镜面高光的强度可以通过图像每个像素的亮度来获取。镜面光贴图上的每个像素都可以由一个颜色向量来表示,比如说黑色代表颜色向量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)-光照

参考文章

你可能感兴趣的:(重新自学学习openGL 之光照贴图)