第十一章 OpenGL ES 基础-基础光照

第十一章 OpenGL ES 基础-基础光照

第一章 OpenGL ES 基础-屏幕、纹理、顶点坐标
第二章 OpenGL ES 基础-GLSL语法简单总结
第三章 OpenGL ES 基础-GLSL渲染纹理
第四章 OpenGL ES 基础-位移、缩放、旋转原理
第五章 OpenGL ES 基础-透视投影矩阵与正交投影矩阵
第六章 OpenGL ES 基础-FBO、VBO理解与运用
第七章 OpenGL ES 基础-输入输出框架思维
第八章 OpenGL ES 基础-MVP矩阵理解
第九章 OpenGL ES 基础-高斯模糊原理
第十章 OpenGL ES 基础-图像USM锐化
第十一章 OpenGL ES 基础-基础光照
第十二章 OpenGL ES 基础-色温、色调、亮度、对比度、饱和度、高光
第十三章 OpenGL ES-RGB、HSV、HSL模型介绍
第十四章 OpenGL ES-方框模糊(均值模糊)
第十五章 OpenGL ES-VR 全景模式原理
第十六章 OpenGL ES-桶形畸变算法-常用VR

冯氏光照模型

现实世界中的光照是极其复杂,难以计算的,因此OpenGL的光照使用的是简化的模型,其中一个模型被称为冯氏光照模型。

冯氏光照模型的主要结构由三个分量组成:
1、环境(Ambient)光照
2、漫反射(Diffuse)光照
3、镜面(Specular)光照
在这里插入图片描述

环境(Ambient)光照

环境光通常都不是来自于同一个光源,而是来自于我们周围分散的很多光源,即使它们可能并不是那么显而易见。它可以向很多方向发散并反弹,所以现实环境周围通常总会有些光亮,对应的物体通常都会反射些微弱的光。lightColor为光源的颜色,ambientStrength为强度,objectColor为物体颜色。

//环境光的计算
void main()
{
    float ambientStrength = 0.1;
    vec3 ambient = ambientStrength * lightColor;

    vec3 result = ambient * objectColor;
    FragColor = vec4(result, 1.0);
}

漫反射(Diffuse)光照

环境光和漫反射光最大的区别在于:漫反射光依赖于光源的方向,而环境光和光源方向完全无关,环境光在场景中是均匀分布的,对场景中的所有物体都有效,而漫反射光在物体朝向光源的一面才有光照效果,在背面则没有光照效果。除了光源方向,漫反射光还和物体表面的法向有关。
在这里插入图片描述
上图中2个光束的强度都是一样的,唯一不同的只是方向,则在左边的图中,物体表面光照要亮一些,因为光线是直射,而右边的图中,物体表面光照要弱一些,因为有因为有一个角度。

在这里插入图片描述
有四道光A,B,C,D,注意:物体表面法向和A重合,但方向相反。光线A和法向的夹角是0,余弦值就是1,所以A光速光照的强度最大,B次之,C和法向夹角是90度,所以光照强度是0,而D作用与物体的背面,余弦值是个负值,光照强度不可能是个负值,所以D的光照强度也是0,也就是说,光源要在物体表面有光照效果,光源方向和物体表面法向夹角必须是0-90度之间。
如果物体表面是个平面,那么法向就是一个固定的向量,但真实物体表面往往并不是平面,所以物体表面的法向是不断变化的,如下图中的两个法向。
在这里插入图片描述
对三角形面来说,可以取它的面法向计算光照,此时三角形面上的光照是均匀的,但这种光照效果并不好,我们通常都是对每个顶点定义法向,而三角形面光栅化后的每个像素,它的法向是由顶点法向插值得到。这种光照模型称作 Phong Shading, 下面就是顶点法向插值后的效果:
在这里插入图片描述

attribute vec4 aPosition;
attribute vec2 aCoord;
attribute vec3 aNormal;//每个顶点定义法向
uniform mat4 uMatrix; // 物体的矩阵
uniform vec4 uBaseColor; // 物体颜色    物体有a,所以是4个颜色
uniform vec3 uLightColor; // 光源颜色    光源是没有a,所以是3个颜色
uniform float uAmbientStrength;//默认0.3 光强度
uniform float uDiffuseStrength;//默认0.5
uniform float uSpecularStrength;//默认0.8
uniform vec3 uLightPosition;  // 光源位置
varying vec4 vColor;

//在片元着色器中计算光照会获得更好更真实的光照效果,但是会比较耗性能
//在片元着色器里面只需要赋值颜色就可以了


//漫反射的计算
vec4 diffuseColor(){
    //模型变换后的位置
    vec3 fragPos=(uMatrix*aPosition).xyz;
    //光照方向
    vec3 direction=normalize(uLightPosition-fragPos);
    //模型变换后的法线向量
    vec3 normal=normalize(mat3(uMatrix)*aNormal);
    //max(cos(入射角),0)
    float diff = max(dot(normal,direction), 0.0);
    //材质的漫反射系数*max(cos(入射角),0)*光照颜色
    vec3 diffuse=uDiffuseStrength * diff * uLightColor;
    return vec4(diffuse,1.0);
}

   vec3 specular=uSpecularStrength*diff*uLightColor;
    return vec4(specular,1.0);
}

void main(){
    gl_Position=uMatrix*aPosition;
    vColor=diffuseColor()* uBaseColor;
}

镜面(Specular)光照

和漫反射光照一样,镜面光照也决定于光的方向向量和物体的法向量,但是它也决定于观察方向,例如玩家是从什么方向看向这个片段的。镜面光照决定于表面的反射特性。如果我们把物体表面设想为一面镜子,那么镜面光照最强的地方就是我们看到表面上反射光的地方。你可以在下图中看到效果:
在这里插入图片描述
为此我们还需要一个观察者坐标(即摄像机)。光的反射向量与观察方向之间夹角越小,镜面光照效果越强。
物体片段着色器部分代码:


attribute vec4 aPosition;
attribute vec2 aCoord;
attribute vec3 aNormal;//每个顶点定义法向
uniform mat4 uMatrix; // 物体的矩阵
uniform vec4 uBaseColor; // 物体颜色    物体有a,所以是4个颜色
uniform vec3 uLightColor; // 光源颜色    光源是没有a,所以是3个颜色
uniform float uAmbientStrength;//默认0.3 光强度
uniform float uDiffuseStrength;//默认0.5
uniform float uSpecularStrength;//默认0.8
uniform vec3 uLightPosition;  // 光源位置
varying vec4 vColor;

//在片元着色器中计算光照会获得更好更真实的光照效果,但是会比较耗性能
//在片元着色器里面只需要赋值颜色就可以了




//镜面光计算,镜面光计算有两种方式,一种是冯氏模型,一种是Blinn改进的冯氏模型
//这里使用的是改进的冯氏模型,基于Half-Vector的计算方式
vec4 specularColor(){
    //模型变换后的位置
    vec3 fragPos=(uMatrix*aPosition).xyz;
    //光照方向
    vec3 lightDirection=normalize(uLightPosition-fragPos);
    //模型变换后的法线向量
    vec3 normal=normalize(mat3(uMatrix)*aNormal);
    //观察方向,这里将观察点固定在(0,0,uLightPosition.z)处
    vec3 viewDirection=normalize(vec3(0,0,uLightPosition.z)-fragPos);
    //观察向量与光照向量的半向量
    vec3 hafVector=normalize(lightDirection+viewDirection);
    //max(0,cos(半向量与法向量的夹角)^粗糙度
    float diff=pow(max(dot(normal,hafVector),0.0),4.0);
    //材质的镜面反射系数*max(0,cos(反射向量与观察向量夹角)^粗糙度*光照颜色
    //材质的镜面反射系数*max(0,cos(半向量与法向量的夹角)^粗糙度*光照颜色
    vec3 specular=uSpecularStrength*diff*uLightColor;
    return vec4(specular,1.0);
}

void main(){
    gl_Position=uMatrix*aPosition;
    vColor=specularColor()* uBaseColor;
}

具体使用

整个冯氏光照模型的代码如下:

attribute vec4 aPosition;
attribute vec2 aCoord;
attribute vec3 aNormal;
uniform mat4 uMatrix; // 物体的矩阵
uniform vec4 uBaseColor; // 物体颜色    物体有a,所以是4个颜色
uniform vec3 uLightColor; // 光源颜色    光源是没有a,所以是3个颜色
uniform float uAmbientStrength;//默认0.3 光强度
uniform float uDiffuseStrength;//默认0.5
uniform float uSpecularStrength;//默认0.8
uniform vec3 uLightPosition;  // 光源位置
varying vec4 vColor;

//在片元着色器中计算光照会获得更好更真实的光照效果,但是会比较耗性能
//在片元着色器里面只需要赋值颜色就可以了


//环境光的计算
vec4 ambientColor(){
    vec3 ambient = uAmbientStrength * uLightColor;
    return vec4(ambient,1.0);
}

//漫反射的计算
vec4 diffuseColor(){
    //模型变换后的位置
    vec3 fragPos=(uMatrix*aPosition).xyz;
    //光照方向
    vec3 direction=normalize(uLightPosition-fragPos);
    //模型变换后的法线向量
    vec3 normal=normalize(mat3(uMatrix)*aNormal);
    //max(cos(入射角),0)
    float diff = max(dot(normal,direction), 0.0);
    //材质的漫反射系数*max(cos(入射角),0)*光照颜色
    vec3 diffuse=uDiffuseStrength * diff * uLightColor;
    return vec4(diffuse,1.0);
}

//镜面光计算,镜面光计算有两种方式,一种是冯氏模型,一种是Blinn改进的冯氏模型
//这里使用的是改进的冯氏模型,基于Half-Vector的计算方式
vec4 specularColor(){
    //模型变换后的位置
    vec3 fragPos=(uMatrix*aPosition).xyz;
    //光照方向
    vec3 lightDirection=normalize(uLightPosition-fragPos);
    //模型变换后的法线向量
    vec3 normal=normalize(mat3(uMatrix)*aNormal);
    //观察方向,这里将观察点固定在(0,0,uLightPosition.z)处
    vec3 viewDirection=normalize(vec3(0,0,uLightPosition.z)-fragPos);
    //观察向量与光照向量的半向量
    vec3 hafVector=normalize(lightDirection+viewDirection);
    //max(0,cos(半向量与法向量的夹角)^粗糙度
    float diff=pow(max(dot(normal,hafVector),0.0),4.0);
    //材质的镜面反射系数*max(0,cos(反射向量与观察向量夹角)^粗糙度*光照颜色
    //材质的镜面反射系数*max(0,cos(半向量与法向量的夹角)^粗糙度*光照颜色
    vec3 specular=uSpecularStrength*diff*uLightColor;
    return vec4(specular,1.0);
}

void main(){
    gl_Position=uMatrix*aPosition;
    vColor=(ambientColor() + diffuseColor() + specularColor())* uBaseColor;
}



precision highp float;

//uniform sampler2D uTexture;
varying vec4 vColor;

void main(){
    gl_FragColor=vColor;
}
package com.opengles.book.es2_0.light;

import android.content.res.Resources;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;

import com.opengles.book.es2_0.utils.BufferUtils;
import com.opengles.book.es2_0.utils.MatrixUtils;
import com.opengles.book.es2_0.utils.ShaderUtils;

import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;


public class LightRenderer implements GLSurfaceView.Renderer {

    private Resources res;
    private int glProgramId;

    private int glAPosition;
    private int glACoord;
    private int glANormal;

    private int glUMatrix;
    private int glUBaseColor;
    private int glULightColor;
    private int glUAmbientStrength;
    private int glUDiffuseStrength;
    private int glUSpecularStrength;
    private int glULightPosition;

    private float[] mvpMatrix; // 物体的矩阵
    private float[] lambMatrix; // 光源的矩阵
    private FloatBuffer vertexBuffer;
    private float lx = 0f, ly = 0.8f, lz = -1f; // 光源位置


    private final float DEFAULT_AMBIENT = 0.3f;
    private final float DEFAULT_DIFFUSE = 0.5f;
    private final float DEFAULT_SPECULAR = 0.8f;

    private float ambientStrength = 0;
    private float diffuseStrength = 0;
    private float specularStrength = 0;


    // 包含了顶点数据,法线数据
    private final float[] data = new float[]{
            -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
    };

    public LightRenderer(Resources res) {
        this.res = res;
        vertexBuffer = BufferUtils.arr2FloatBuffer(data);
    }

    public void setAmbientStrength(boolean isChecked) {
        this.ambientStrength = isChecked ? DEFAULT_AMBIENT : 0;
    }

    public void setDiffuseStrength(boolean isChecked) {
        this.diffuseStrength = isChecked ? DEFAULT_DIFFUSE : 0;
    }

    public void setSpecularStrength(boolean isChecked) {
        this.specularStrength = isChecked ? DEFAULT_SPECULAR : 0;
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        GLES20.glEnable(GLES20.GL_DEPTH_TEST);

        GLES20.glEnable(GLES20.GL_CULL_FACE);
        GLES20.glCullFace(GLES20.GL_FRONT);
        GLES20.glFrontFace(GLES20.GL_CW);

        glProgramId = ShaderUtils.createProgram(res, "light/light.vert", "light/light.frag");

        glAPosition = GLES20.glGetAttribLocation(glProgramId, "aPosition");
        glACoord = GLES20.glGetAttribLocation(glProgramId, "aCoord");
        glANormal = GLES20.glGetAttribLocation(glProgramId, "aNormal");

        glUMatrix = GLES20.glGetUniformLocation(glProgramId, "uMatrix");
        glUBaseColor = GLES20.glGetUniformLocation(glProgramId, "uBaseColor");
        glULightColor = GLES20.glGetUniformLocation(glProgramId, "uLightColor");

        glUAmbientStrength = GLES20.glGetUniformLocation(glProgramId, "uAmbientStrength");
        glUDiffuseStrength = GLES20.glGetUniformLocation(glProgramId, "uDiffuseStrength");
        glUSpecularStrength = GLES20.glGetUniformLocation(glProgramId, "uSpecularStrength");

        glULightPosition = GLES20.glGetUniformLocation(glProgramId, "uLightPosition");
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        // 整体缩小0.5f,相当于置于正中心
        mvpMatrix = MatrixUtils.getOriginalMatrix();
        Matrix.scaleM(mvpMatrix, 0, 0.5f, 0.5f * width / (float) height, 0.5f);

        // 平移指定距离,确定光源位置,并整体缩小0.09
        lambMatrix = MatrixUtils.getOriginalMatrix();
        Matrix.translateM(lambMatrix, 0, lx, ly, lz);
        Matrix.scaleM(lambMatrix, 0, 0.09f, 0.09f * width / (float) height, 0.09f);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
        GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);

        GLES20.glUseProgram(glProgramId);
        Matrix.rotateM(mvpMatrix, 0, 2, -1, -1, 1); // 绕xy旋转
        GLES20.glUniformMatrix4fv(glUMatrix, 1, false, mvpMatrix, 0);


        // ---------------- 设置光 start  -----------------
        //环境光强度
        GLES20.glUniform1f(glUAmbientStrength, ambientStrength);
        //漫反射光强度
        GLES20.glUniform1f(glUDiffuseStrength, diffuseStrength);
        //镜面光强度
        GLES20.glUniform1f(glUSpecularStrength, specularStrength);
        //光源颜色
        GLES20.glUniform3f(glULightColor, 0.0f, 0.0f, 1.0f);   // 物体默认颜色是blue
        //物体颜色
        GLES20.glUniform4f(glUBaseColor, 1.0f, 1.0f, 1.0f, 1.0f); // 物体默认颜色是黑色
        //光源位置
        GLES20.glUniform3f(glULightPosition, lx, ly, lz);
        // ---------------- 设置光 end  -----------------


        //传入顶点信息
        vertexBuffer.position(0);
        GLES20.glEnableVertexAttribArray(glAPosition);
        GLES20.glVertexAttribPointer(glAPosition, 3, GLES20.GL_FLOAT, false,
                6*4, //  跨度,一般情况下写0系统会自动识别。识别方式为size*sizeof(数组定义时报类型) 6*4,此处不传跨度会绘制不出来图形,不知为何???
                vertexBuffer);

        //传入法线信息
        vertexBuffer.position(3);
        GLES20.glEnableVertexAttribArray(glANormal);
        GLES20.glVertexAttribPointer(glANormal, 3, GLES20.GL_FLOAT, false,
                6*4, //  跨度,一般情况下写0系统会自动识别。识别方式为size*sizeof(数组定义时报类型) 6*4,此处不传跨度会绘制不出来图形,不知为何???
                vertexBuffer);

        // 绘制缓冲区的图形
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES,0,data.length/6);

        // 再绘制一个立方体,标记光源位置
        GLES20.glUniformMatrix4fv(glUMatrix,1,false,lambMatrix,0);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES,0,data.length/6);

        //释放资源
//        GLES20.glDisable(GLES20.GL_CULL_FACE);
//        GLES20.glDisable(GLES20.GL_DEPTH_TEST);
        GLES20.glDisableVertexAttribArray(glAPosition);
        GLES20.glDisableVertexAttribArray(glANormal);

    }
}

  • 10
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

baoyu45585

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值