2016-11-22 2 views
0

Ich versuche Schattenkarten für Punktlichter zu implementieren. Im Grunde erstelle ich einen Framebuffer und rendere dann alle Shadow Casters auf jeder Seite einer Cubemap-Textur (was 6 Mal ist) und lese sie dann im regulären Rendering-Durchlauf und bestimme, welches Pixel im Schatten ist. Ich habe mehrere Fragen:OpenGL Cubemap FrameBuffer Tiefenvergleich

  1. Warum muss ich zusätzlich zu einer Tiefe Komponente, um für meine Cubemap eine Farbe Befestigung enthalten, um irgendetwas zu gemacht werden? Ich habe es ohne den Farbzusatz ausprobiert und es hat nicht funktioniert.

  2. Nachdem ich den Farbzusatz hinzugefügt habe, kann ich meine Schattenrollen in der Cubemap sehen, aber es scheint, dass der Schattenvergleich falsch ist. Ich vermute, dass einer in NDC ist, während der andere nicht.

Hier ist, wie ich meine Framebuffer mit dem Schatten Cubemap initialisieren:

// Create the depth buffer 
    glGenTextures(1, &mDepthTextureID); 
    glBindTexture(GL_TEXTURE_2D, mDepthTextureID); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
    glBindTexture(GL_TEXTURE_2D, 0); 

    //Create the cubemap texture 
    glGenTextures(1, &mCubemapTextureID); 
    glBindTexture(GL_TEXTURE_CUBE_MAP, mCubemapTextureID); 
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); 
    for (GLuint i = 0; i < 6; ++i) 
    { 
     glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_R32F, width, height, 0, GL_RED, GL_FLOAT, 0); 
    } 
    glBindTexture(GL_TEXTURE_CUBE_MAP, 0); 

    //Create the framebuffer and attach the cubemap texture to it 
    glGenFramebuffers(1, &mFrameBufferObjectID); 
    glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferObjectID); 
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, mDepthTextureID, 0); 

    //Disable writes to the color buffer 
    glDrawBuffer(GL_NONE); 
    //Disable reads from the color buffer 
    glReadBuffer(GL_NONE); 

    GLenum Status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 
    if (Status != GL_FRAMEBUFFER_COMPLETE) 
    { 
     switch(Status) 
     { 
      case GL_FRAMEBUFFER_UNSUPPORTED: 
       printf("FrameBuffer unsupported error"); 
       return false; 
       break; 
      case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: 
       printf("FrameBuffer incomplete attachement"); 
       return false; 
       break; 
      default: 
       printf("GLShadowCubemap error, status: 0x%x\n", Status); 
       return false; 
     } 
    } 

    //Unbind this 
    glBindFramebuffer(GL_FRAMEBUFFER, 0); 

Hier ist mein Schatten des Vertex-Shader: (Nur der Position Attribut verwendet wird)

#version 330 core 

layout (location = 0) in vec3 Position; 
layout (location = 1) in vec3 Normal; 
layout (location = 2) in vec2 TexCoord; 
layout (location = 3) in vec3 Tangent; 

uniform mat4 gModelMatrix; 
uniform mat4 gModelViewProjectionMatrix; 

out vec3 WorldPosition; 

/* 
* Below needs a GS and using layered rendering 
void main() 
{ 
    gl_Position = gModelMatrix * vec4(Position, 1.0); 
} 
*/ 

void main() 
{ 
    vec4 pos4 = vec4(Position, 1.0); 
    gl_Position = gModelViewProjectionMatrix * pos4; 
    WorldPosition = (gModelMatrix * pos4).xyz; 
} 

Hier ist mein Schatten Fragment Shader:

#version 330 core 

in vec3 WorldPosition; 

uniform vec3 gLightPosition; 

out float Fragment; 

void main() 
{ 
    // get distance between fragment and light source 
    float dist_to_light = length(WorldPosition - gLightPosition); 
    //gl_FragDepth = dist_to_light; 
    Fragment = dist_to_light; 
} 

Zusätzliche Frage hier:

Ich sah, dass viele gesagt haben, dass gl_FragDepth eine schlechte Idee ist. Ich weiß irgendwie warum, aber was ist seltsam hier ist, dass, wenn ich die gl_FragDepth manuell überschreiben würde, nichts in die Cubemap geschrieben wird. Warum?

Hier ist, wie ich alle regulären Sachen machen (die Variable i ein Index für meine Lichter Array)

mShadowCubemapFBOs[i].ViewportChange(); 
    mShadowMapTechnique.SetLightPosition(light.Position); 
    const float shadow_aspect = (static_cast<float>(mShadowWidth)/mShadowHeight); 
    const mat4 shadow_projection_matrix = glm::perspective(90.f, shadow_aspect, 1.f, mShadowFarPlane); 
    const vector<MeshComponent>& meshes = ComponentManager::Instance().GetMeshComponentPool().GetPool(); 
       for(int layer = 0; layer < 6; ++layer) 
       { 
        GLenum cubemap_face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer; 
        mShadowCubemapFBOs[i].Bind(cubemap_face); 
        glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 
        for(const MeshComponent& mesh : meshes) 
        { 
//the transform_component is referenced ahead of time. 
         const mat4 model_transform = transform_component->GetTransformMatrix(); 
           mShadowMapTechnique.SetModelViewProjectionMatrix(light.Position, cubemap_face, shadow_projection_matrix, model_transform); 
         mShadowMapTechnique.SetModelMatrix(model_transform); 
         mesh.Render(); 
        } 
       } 

Schließlich ist hier die regelmäßige Rendering Shader:

#version 330 core 

const int MAX_LIGHTS = 8; 
const int LIGHT_TYPE_DIRECTIONAL = 0; 
const int LIGHT_TYPE_POINT = 1; 
const int LIGHT_TYPE_SPOT = 2; 

in vec2 TexCoord0; 
in vec3 WorldNormal0; 
in vec3 WorldPos0; 
in vec3 WorldTangent0; 

out vec4 FragmentColor; 

struct Material 
{ 
    vec4 Emissive; 
    vec4 Ambient; 
    vec4 Diffuse; 
    vec4 Specular; 
    float SpecularPower; 
    bool UseTexture; 
}; 

struct Light 
{ 
    vec3 Position; 
    vec3 Direction; 
    vec4 Color;     //RGBA 
    float SpotAngle; 
    float ConstantAttenuation; 
    float LinearAttenuation; 
    float QuadraticAttenuation; 
    int LightType; 
    samplerCube ShadowMap; //Cubemap shadows 
    bool Enabled; 
}; 

struct LightingResult 
{ 
    vec4 Diffuse; 
    vec4 Specular; 
}; 

uniform Material gMaterial; 
uniform Light gLights[MAX_LIGHTS]; 
uniform sampler2D gTextureSampler0; 
uniform sampler2D gNormalMap; 
uniform bool gEnableNormalMap; 
uniform vec3 gEyeWorldPos; 

float CalculateShadowFactor(vec3 frag_pos, Light light) 
{ 
    vec3 fragment_to_light = frag_pos - light.Position; 
    float sample_distance = texture(light.ShadowMap, fragment_to_light).r; 
    float distance = length(fragment_to_light); 
    if (distance < sample_distance + 0.001) 
    { 
     return 1.0; // Inside the light 
    } 
    else 
    { 
     return 0.5; // Inside the shadow 
    } 
} 

//L - Light direction vector from pixel to light source 
//N - Normal at the pixel 
vec4 CalculateDiffuse(Light light, vec3 L, vec3 N) 
{ 
    float n_dot_l = max(0, dot(N, L)); 
    return light.Color * n_dot_l; 
} 

//V - View vector 
//L - Light direction vector from pixel to light source 
//N - Normal at the pixel 
vec4 CalculateSpecular(Light light, vec3 V, vec3 L, vec3 N) 
{ 
    //Phong lighting 
    vec3 R = normalize(reflect(-L, N)); 
    float r_dot_v = max(0, dot(R, V)); 
    return light.Color * pow(r_dot_v, max(0.4, gMaterial.SpecularPower)); 
} 

float CalculateAttenuation(Light light, float distance) 
{ 
    return 1.0/(light.ConstantAttenuation + light.LinearAttenuation * distance + light.QuadraticAttenuation * distance * distance); 
} 

//V - View vector 
//P - Position of pixel 
//N - Normal of pixel 
LightingResult CalculatePointLight(Light light, vec3 V, vec3 P, vec3 N) 
{ 
    LightingResult result; 
    result.Diffuse = vec4(0.0, 0.0, 0.0, 1.0); 
    result.Specular = vec4(0.0, 0.0, 0.0, 1.0); 

    vec3 L = light.Position - P; 
    float distance = length(L); 
    L = normalize(L); 

    float attenuation = CalculateAttenuation(light, distance); 
    result.Diffuse = CalculateDiffuse(light, L, N) * attenuation; 
    result.Specular = CalculateSpecular(light, V, L, N) * attenuation; 

    return result; 
} 

//V - View vector 
//P - Position of pixel 
//N - Normal of pixel 
LightingResult CalculateDirectionalLight(Light light, vec3 V, vec3 P, vec3 N) 
{ 
    LightingResult result; 
    result.Diffuse = vec4(0.0, 0.0, 0.0, 1.0); 
    result.Specular = vec4(0.0, 0.0, 0.0, 1.0); 

    vec3 L = -light.Direction; 

    result.Diffuse = CalculateDiffuse(light, L, N); 
    result.Specular = CalculateSpecular(light, V, L, N); 

    return result; 
} 

//L - Light vector 
//Smoothness increases as angle gets larger 
float CalculateSpotCone(Light light, vec3 L) 
{ 
    //cos are in radians 
    float min_cos = cos(light.SpotAngle); 
    float max_cos = (min_cos + 1.0f)/2.0f; 
    float cos_angle = dot(light.Direction, -L); //negated L such that as we move towards the edge, intensity decreases 
    return smoothstep(min_cos, max_cos, cos_angle); 
} 

//V - View vector 
//P - Position of pixel 
//N - Normal of pixel 
LightingResult CalculateSpotLight(Light light, vec3 V, vec3 P, vec3 N) 
{ 
    LightingResult result; 
    result.Diffuse = vec4(0.0, 0.0, 0.0, 1.0); 
    result.Specular = vec4(0.0, 0.0, 0.0, 1.0); 

    vec3 L = light.Position - P; 
    float distance = length(L); 
    L = normalize(L); 

    float attenuation = CalculateAttenuation(light, distance); 
    float spot_intensity = CalculateSpotCone(light, L); 
    result.Diffuse = CalculateDiffuse(light, L, N) * attenuation * spot_intensity; 
    result.Specular = CalculateSpecular(light, V, L, N) * attenuation * spot_intensity; 

    return result; 
} 

//P - Position of pixel 
//N - Normal of pixel 
LightingResult CalculateLighting(vec3 P, vec3 N) 
{ 
    vec3 V = normalize(gEyeWorldPos - P); 

    LightingResult total_result; 
    total_result.Diffuse = vec4(0, 0, 0, 1.0); 
    total_result.Specular = vec4(0, 0, 0, 1.0); 

    for(int i = 0; i < MAX_LIGHTS; ++i) 
    { 
     if(!gLights[i].Enabled) 
     { 
      continue; 
     } 

     LightingResult result; 
     result.Diffuse = vec4(0, 0, 0, 1.0); 
     result.Specular = vec4(0, 0, 0, 1.0); 
     float shadow_factor = 1.0; 

     switch(gLights[i].LightType) 
     { 
      case LIGHT_TYPE_DIRECTIONAL: 
       result = CalculateDirectionalLight(gLights[i], V, P, N); 
       break; 
      case LIGHT_TYPE_POINT: 
       result = CalculatePointLight(gLights[i], V, P, N); 
       shadow_factor = CalculateShadowFactor(P, gLights[i]); 
       break; 
      case LIGHT_TYPE_SPOT: 
       result = CalculateSpotLight(gLights[i], V, P, N); 
       shadow_factor = CalculateShadowFactor(P, gLights[i]); 
       break; 
     } 
     total_result.Diffuse += (result.Diffuse * shadow_factor); 
     total_result.Specular += (result.Specular * shadow_factor); 
    } 

    total_result.Diffuse = clamp(total_result.Diffuse, 0, 1); 
    total_result.Specular = clamp(total_result.Specular, 0, 1); 

    return total_result; 
} 

vec3 CalculateNormalMapNormal() 
{ 
    vec3 normal = normalize(WorldNormal0); 
    vec3 tangent = normalize(WorldTangent0); 
    tangent = normalize(tangent - dot(tangent, normal) * normal); //remove components from the normal vector. This is needed for non-uniform scaling 
    vec3 bi_tangent = cross(tangent, normal); 
    vec3 bump_map = texture(gNormalMap, TexCoord0).xyz; 
    bump_map = 2.0 * bump_map - vec3(1.0, 1.0, 1.0); //Remaps the values 
    mat3 TBN = mat3(tangent, bi_tangent, normal); 
    vec3 actual_normal = TBN * bump_map; 
    return normalize(actual_normal); 
} 

void main() 
{ 
    vec3 pixel_normal = normalize(WorldNormal0); 
    vec4 texture_color = vec4(0, 0, 0, 1); 

    if(gMaterial.UseTexture) 
    { 
     texture_color = texture(gTextureSampler0, TexCoord0); 
    } 

    if(gEnableNormalMap) 
    { 
     pixel_normal = CalculateNormalMapNormal(); 
    } 

    LightingResult light_result = CalculateLighting(WorldPos0, pixel_normal); 
    vec4 diffuse_color = gMaterial.Diffuse * light_result.Diffuse; 
    vec4 specular_color = gMaterial.Specular * light_result.Specular; 

    FragmentColor = (gMaterial.Emissive + gMaterial.Ambient + diffuse_color + specular_color) * texture_color; 
    //FragmentColor = texture_color; 

    //temp test 
    //vec3 fragment_to_light = WorldPos0 - gLights[1].Position; 
    //FragmentColor = vec4(vec3(texture(gLights[1].ShadowMap, fragment_to_light).r/gFarPlane), 1.0); 
} 

Was mache ich falsch ? Ich sehe, dass ich den Abstand von Fragment zu Licht im Weltraum speichere und es in einen Farbpuffer (nicht den Tiefenpuffer) geschrieben wird und es sollte daher nicht in NDC sein. Schließlich, wenn ich es vergleiche, ist es auch im Weltall .... Warum sind die Schatten ausgeschaltet? Es scheint, als wären die Schatten viel größer als sie sein sollten, so dass die gesamte Szene mit Schatten bedeckt ist und es scheint, dass die Größe des Schattens tatsächlich mit Licht bedeckt ist.

Bild des Schattens Cubemap:

enter image description here

Bild von der Szene (nur der Hubschrauber werfen Schatten):

enter image description here

Dank!

Antwort

0

Nach einiger Fehlersuche, fand ich meine Probleme heraus:

  1. glPerspective nimmt FOV als Radiant nicht Grad, obwohl es Dokumentation ist sagt, dass es nur in Radiant wenn FORCE_RADIANS definiert (das habe ich nicht definieren)

  2. Die Cubemap für Shadow erfordert die eindeutige Farbe (FLT_MAX, FLT_MAX, FLT_MAX, 1.0), so dass standardmäßig nicht alles im Schatten ist.

Verwandte Themen