OpenGLES入门笔记 :OpenGLES光照基础总结4 光照的顶点计算与片元计算

背景

随着对光照相关shader的学习,发现前面很多知识理解的并不正确。下面记录一下前段时间关于光照颜色插值的计算发现的问题。

片元中计算光照

先看一张效果图
这里写图片描述
这是我们使用片元着色器进行光照计算得出的效果。在这里我们对每个片元进行光照计算,也就是说每个点与光源的距离和角度我们都会计算,并为之赋一个准确值。于是就形成了上图的光照效果,这种方式可以比较精准地反应光照,但是计算量巨大,如果不对多光源进行特殊处理,很容易导致画面卡顿。

fragmentshader

precision mediump float;

struct LightProperties{
    bool isEnabled;
    bool isLocal;
    bool isSpot;

    vec3 ambient;
    vec3 color;
    vec3 position;
    vec3 halfVector;
    vec3 coneDirection;

    float spotCosCutoff;
    float spotExponent;
    float constantAttenuation;
    float linearAttenuation;
    float quadraticAttenuation;
};

const int MaxLights = 5;//用几个光源设置几个,开多了会卡
uniform LightProperties uLights[MaxLights];

uniform sampler2D sTexture;

varying vec2 vTextureCoord;
varying vec4 vglPositionRec;
varying vec3 vPointNormal;

varying vec3 uLightPosition;

void main(){
    vec3 scatteredLight = vec3(0.0);
    vec3 reflectedLight = vec3(0.0);

    for(int light=0; light<MaxLights; light++){
        if(! uLights[light].isEnabled){
            continue;
        }

        //vec3 halfVector;
        vec3 lightDirection = uLights[light].position;
        float attenuation = 1.0;

        if(uLights[light].isLocal){       //点光或者聚光
            lightDirection = lightDirection - vec3(vglPositionRec);
            float lightDistance = length(lightDirection);
            lightDirection = lightDirection / lightDistance;

            attenuation = 1.0/(uLights[light].constantAttenuation + 
                               uLights[light].linearAttenuation*lightDistance );                        

            if(uLights[light].isSpot){
                float spotCos = dot(lightDirection, -uLights[light].coneDirection);
                if(spotCos < uLights[light].spotCosCutoff)
                    attenuation = 0.0;
                else
                    attenuation *= pow(spotCos, uLights[light].spotExponent);
            }
        float diffuse = max(0.0, dot(vPointNormal, lightDirection));

        scatteredLight += (uLights[light].ambient + uLights[light].color * diffuse) * attenuation;                  
    }

    gl_FragColor = min(texture2D(sTexture, vTextureCoord) * vec4(scatteredLight, 1), vec4(1.0));
}

vertexshader

uniform mat4 uMVPMatrix;
uniform mat4 uMVMatrix;

attribute vec3 aPosition;
attribute vec2 aColor;
varying vec2 vTextureCoord;
varying vec4 vglPositionRec;//物体未经透视的位置

//传入点的法线
attribute vec3 aPointNormal;
varying vec3 vPointNormal;

//传入光源位置
attribute vec3 aLightPosition;
varying vec3 uLightPosition;


void main(){
    vPointNormal = normalize(aPointNormal);
    gl_Position = uMVPMatrix * vec4(aPosition,1);
    vTextureCoord = aColor;
    vglPositionRec = uMVMatrix * vec4(aPosition, 1);
}

我们在fragmentshander中对每一个坐标点都进行了运算,而非插值。vertexshader值负责坐标点传入。

顶点中计算光照

先上一张效果图

这里写图片描述

我日,这和上一张图是一个位置拍的吗,怎么成了这个鸟样子…..可见如果在顶点中计算光照,效果会不太理想。我们在顶点中只计算了天空盒的四个顶点,那么其他地方的光照颜色从哪里来的呢?对,就是上一篇文章中说的,是插值出来的。有了顶点色值和计算好的插值值,片元就直接用这些插值得到的色值。所以,这种方式效率比较高,但是效果可能在有些场合不太理想。

fragmentshader

precision mediump float;

uniform sampler2D sTexture;

varying vec2 vTextureCoord;
varying vec4 vglPositionRec;
varying vec3 vPointNormal;

varying vec3 uLightPosition;

varying vec3 vScatteredLight;

void main(){

    gl_FragColor = min(texture2D(sTexture, vTextureCoord) * vec4(vScatteredLight, 1), vec4(1.0));
}

vertexshader

uniform mat4 uMVPMatrix;
uniform mat4 uMVMatrix;

attribute vec3 aPosition;
attribute vec2 aColor;
varying vec2 vTextureCoord;
varying vec4 vglPositionRec;//物体未经透视的位置

//传入点的法线
attribute vec3 aPointNormal;
varying vec3 vPointNormal;

//传入光源位置
attribute vec3 aLightPosition;
varying vec3 uLightPosition;

struct LightProperties{
    bool isEnabled;
    bool isLocal;
    bool isSpot;

    vec3 ambient;
    vec3 color;
    vec3 position;
    vec3 halfVector;
    vec3 coneDirection;

    float spotCosCutoff;
    float spotExponent;
    float constantAttenuation;
    float linearAttenuation;
    float quadraticAttenuation;
};

const int MaxLights = 5;//用几个光源设置几个,开多了会卡
uniform LightProperties uLights[MaxLights];

varying vec3 vScatteredLight;

void main(){

    vPointNormal = normalize(aPointNormal);
    gl_Position = uMVPMatrix * vec4(aPosition,1);
    vTextureCoord = aColor;
    vglPositionRec = uMVMatrix * vec4(aPosition, 1);

    vec3 scatteredLight = vec3(0.0);

    for(int light=0; light<MaxLights; light++){
        if(! uLights[light].isEnabled){
            continue;
        }

        vec3 lightDirection = uLights[light].position;
        float attenuation = 1.0;

        if(uLights[light].isLocal){       //点光或者聚光
            lightDirection = lightDirection - vec3(vglPositionRec);
            float lightDistance = length(lightDirection);
            lightDirection = lightDirection / lightDistance;

            attenuation = 1.0/(uLights[light].constantAttenuation + 
                               uLights[light].linearAttenuation*lightDistance );//+
                               //uLights[light].quadraticAttenuation*lightDistance*lightDistance);

            if(uLights[light].isSpot){
                float spotCos = dot(lightDirection, -uLights[light].coneDirection);
                if(spotCos < uLights[light].spotCosCutoff)
                    attenuation = 0.0;
                else
                    attenuation *= pow(spotCos, uLights[light].spotExponent);
            }   
        }

        float diffuse = max(0.0, dot(vPointNormal, lightDirection));

        scatteredLight += (uLights[light].ambient + uLights[light].color * diffuse) * attenuation;
    }

    vScatteredLight = scatteredLight;
}

我们只计算额顶点处的光照值,其他的值抛给了gl,让他自己插值。gl说好,那我就线性插值吧,于是被光照的面中间基本上看不出来什么颜色。而fragmentshader则说明也不干,你上面给我什么值,我直接用就好了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值