首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >OpenGL可编程流水线点灯

OpenGL可编程流水线点灯
EN

Stack Overflow用户
提问于 2013-01-01 21:36:15
回答 2查看 894关注 0票数 2

由于内置制服(如gl_LightSource )现在在OpenGL规范的最新版本中被标记为不受欢迎,我目前正在实现一个基本的照明系统(点灯现在),该系统通过自定义的统一变量接收所有光线和材料信息。

我已经实现了一个点光的光衰减和镜面高光,它似乎工作良好,除了一个位置故障:我正在手动移动灯,改变它沿X轴的位置。然而,光源(从它投射到它下面的正方形平面上的光线判断)似乎不是沿着X轴移动,而是在X轴和Z轴上对角移动(可能也是Y,虽然它并不完全是定位错误)。

这是变形情况的屏幕截图(光线在-35,5,0,苏珊娜在0,2,0:

当光线在0,5,0时,它看起来没问题:

根据OpenGL规范,所有默认的光计算都是在眼睛坐标中进行的,这就是我在这里试图模拟的(因此光位置与vMatrix相乘)。我只使用视图矩阵,因为应用对光线渲染的顶点批处理的模型转换是没有意义的。

如果有关系的话,所有飞机的法线都指向- 0,1,0。

(注:我现在解决了这个问题,多亏了msell和myAces!下面的片段是修正后的版本。也有一个选项,添加聚光灯参数,现在(d3d风格的)

下面是我在顶点着色器中使用的代码

代码语言:javascript
复制
#version 330

uniform mat4 mvpMatrix;
uniform mat4 mvMatrix;
uniform mat4 vMatrix;

uniform mat3 normalMatrix;
uniform vec3 vLightPosition;
uniform vec3 spotDirection;
uniform bool useTexture;

uniform bool    fogEnabled;
uniform float   minFogDistance;
uniform float   maxFogDistance;

in vec4 vVertex;
in vec3 vNormal;
in vec2 vTexCoord;

smooth out vec3     vVaryingNormal;
smooth out vec3     vVaryingLightDir;
smooth out vec2     vVaryingTexCoords;
smooth out float    fogFactor;

smooth out vec4     vertPos_ec;
smooth out vec4     lightPos_ec;
smooth out vec3     spotDirection_ec;

void main() {
    // Surface normal in eye coords
    vVaryingNormal = normalMatrix * vNormal;

    vec4 vPosition4 = mvMatrix * vVertex;
    vec3 vPosition3 = vPosition4.xyz / vPosition4.w;

    vec4 tLightPos4 = vMatrix * vec4(vLightPosition, 1.0);
    vec3 tLightPos  = tLightPos4.xyz / tLightPos4.w;

    // Diffuse light
    // Vector to light source (do NOT normalize this!)
    vVaryingLightDir = tLightPos - vPosition3;

    if(useTexture) {
        vVaryingTexCoords = vTexCoord;
    }

    lightPos_ec = vec4(tLightPos, 1.0f);
    vertPos_ec = vec4(vPosition3, 1.0f);

    // Transform the light direction (for spotlights) 
    vec4 spotDirection_ec4 = vec4(spotDirection, 1.0f);
    spotDirection_ec = spotDirection_ec4.xyz / spotDirection_ec4.w; 
    spotDirection_ec = normalMatrix * spotDirection;

    // Projected vertex
    gl_Position = mvpMatrix * vVertex;

    // Fog factor
    if(fogEnabled) {
        float len = length(gl_Position);
        fogFactor = (len - minFogDistance) / (maxFogDistance - minFogDistance);
        fogFactor = clamp(fogFactor, 0, 1);
    }   
}

这是我在片段着色器中使用的代码

代码语言:javascript
复制
#version 330

uniform vec4 globalAmbient;

// ADS shading model
uniform vec4 lightDiffuse;
uniform vec4 lightSpecular;
uniform float lightTheta;
uniform float lightPhi;
uniform float lightExponent;

uniform int shininess;
uniform vec4 matAmbient;
uniform vec4 matDiffuse;
uniform vec4 matSpecular;

// Cubic attenuation parameters
uniform float constantAt;
uniform float linearAt;
uniform float quadraticAt;
uniform float cubicAt;

// Texture stuff
uniform bool useTexture;
uniform sampler2D colorMap;

// Fog
uniform bool    fogEnabled;
uniform vec4    fogColor;

smooth in vec3  vVaryingNormal;
smooth in vec3  vVaryingLightDir;
smooth in vec2  vVaryingTexCoords;
smooth in float fogFactor;
smooth in vec4  vertPos_ec;
smooth in vec4  lightPos_ec;
smooth in vec3  spotDirection_ec;

out vec4 vFragColor;

// Cubic attenuation function
float att(float d) {
    float den = constantAt + d * linearAt + d * d * quadraticAt + d * d * d * cubicAt;

    if(den == 0.0f) {
        return 1.0f;
    }

    return min(1.0f, 1.0f / den);
}

float computeIntensity(in vec3 nNormal, in vec3 nLightDir) {

    float intensity = max(0.0f, dot(nNormal, nLightDir));
    float cos_outer_cone = lightTheta;
    float cos_inner_cone = lightPhi;
    float cos_inner_minus_outer = cos_inner_cone - cos_outer_cone;

    // If we are a point light
    if(lightTheta > 0.0f) {
        float cos_cur = dot(normalize(spotDirection_ec), -nLightDir);
        // d3d style smooth edge
        float spotEffect = clamp((cos_cur - cos_outer_cone) / 
                                cos_inner_minus_outer, 0.0, 1.0);
        spotEffect = pow(spotEffect, lightExponent);
        intensity *= spotEffect;
    }   

    float attenuation = att( length(lightPos_ec - vertPos_ec) );
    intensity *= attenuation;

    return intensity;
}

/**
 *  Phong per-pixel lighting shading model.
 *  Implements basic texture mapping and fog.
 */
void main() {       
    vec3 ct, cf;
    vec4 texel;
    float at, af;

    if(useTexture) {
        texel = texture2D(colorMap, vVaryingTexCoords); 
    } else {
        texel = vec4(1.0f);
    }

    ct = texel.rgb;
    at = texel.a;

    vec3 nNormal = normalize(vVaryingNormal);
    vec3 nLightDir = normalize(vVaryingLightDir);

    float intensity = computeIntensity(nNormal, nLightDir); 
    cf = matAmbient.rgb * globalAmbient.rgb + intensity * lightDiffuse.rgb * matDiffuse.rgb;    
    af = matAmbient.a * globalAmbient.a + lightDiffuse.a * matDiffuse.a;

    if(intensity > 0.0f) {
        // Specular light
        //  -   added *after* the texture color is multiplied so that
        //      we get a truly shiny result
        vec3 vReflection = normalize(reflect(-nLightDir, nNormal));
        float spec = max(0.0, dot(nNormal, vReflection));
        float fSpec = pow(spec, shininess) * lightSpecular.a;
        cf += intensity * vec3(fSpec) * lightSpecular.rgb * matSpecular.rgb;
    }

    // Color modulation
    vFragColor = vec4(ct * cf, at * af);

    // Add the fog to the mix
    if(fogEnabled) {
        vFragColor = mix(vFragColor, fogColor, fogFactor);
    }
}

是什么数学错误导致了这种扭曲?

编辑1:

我更新了着色代码。衰减现在是计算在碎片阴影,因为它应该一直。但目前它已被禁用-- bug与衰减没有任何关系。当只渲染光的衰减因子时(见碎片着色器的最后几行),衰减计算是正确的。这意味着光线的位置被正确地转换成眼睛坐标,所以它不可能是错误的来源。

片段着色器的最后几行可以用于一些调试(稍微有点麻烦,但还是很有洞察力)--似乎每个片段的光强度都没有得到正确的计算,尽管我不知道为什么。

有趣的是,这个bug只在(非常)大的四边形上才能被注意到,比如图像中的地板。这在小型模特身上是不明显的。

编辑2:

我已经更新了着色代码到一个工作版本。现在一切都很好,我希望它能帮助任何未来的用户阅读这篇文章,因为到今天为止,我还没有看到任何glsl教程实现完全没有固定功能和秘密隐式转换(例如gl_LightSource[i].*和眼空间隐式转换)的glsl教程。

我的代码是根据BSD 2条款许可和可以在GitHub上找到许可的!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-01-03 11:52:40

最近,我遇到了一个类似的问题,在使用大多边形时,照明工作有点错误。问题是在顶点着色器中将眼睛矢量归一化,因为插值归一化值会导致不正确的结果。

变化

代码语言:javascript
复制
vVaryingLightDir = normalize( tLightPos - vPosition3 );

代码语言:javascript
复制
vVaryingLightDir = tLightPos - vPosition3;

在你的顶点着色器。您可以将规范化保存在片段着色器中。

票数 3
EN

Stack Overflow用户

发布于 2013-01-03 12:14:00

就因为我注意到:

代码语言:javascript
复制
vec3 tLightPos = (vMatrix * vec4(vLightPosition, 1.0)).xyz;

你只是在这里消除了同质坐标,而不是首先对它进行分割。这会引起一些问题。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14114437

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档