使用阴影贴图优化景观渲染

时间:2018-07-16 11:05:34

标签: opengl glsl shader shadow

在我的场景上,我渲染风景(从高度图上绘制大约 522000 个三角形,高度图的所有点都用于创建三角形网格),并且阴影贴图/模糊处于活动状态。我注意到FPS大幅下降。目前,我有一个光源-一种“太阳”。因此,光源far_plane极高-512(景观的最大点为128,最小点为0)。我需要以某种方式对其进行优化以获得更好的性能。

生成的具有高度图512x512的景观的示例 Terrain

  1. 我的第一个想法是减少网格中的三角形数量。我认为对于高度图512 * 512522万的三角形来说实在太多了。 此外,在缩放时,即使没有平均法线,地形也非常平滑。这就是使地形降低为多边形的原因。

Triangle mesh Triangle mesh 2

  1. 如果我减小顶点的高度(缩放比例),并相应地减小光源的far_plane,是否可以提高性能?

我的着色器:

顶点着色器:

#version 130

in vec4 a_Position;     // Per-vertex position information we will pass in.

void main() {
    gl_Position = a_Position;
}

几何着色器:

#version 330 core
layout (triangles) in;
layout (triangle_strip, max_vertices=3) out;

uniform mat4 u_Model, u_View, u_Projection;
uniform float greenValue = 64;
uniform float greyValue = 96;

out vec3 norm;
out vec4 v_Position;
out mat4 model, view, projection;
out vec4 ambientColor;
out vec4 diffuseColor;
out vec4 specularColor;

void main() {
    vec4 v1Eye = u_View * u_Model * gl_in[0].gl_Position;
    vec4 v2Eye = u_View * u_Model * gl_in[1].gl_Position;
    vec4 v3Eye = u_View * u_Model * gl_in[2].gl_Position;

    vec4 v1v2 = v1Eye - v2Eye;
    vec4 v2v3 = v2Eye - v3Eye;
    vec3 normal = cross(vec3(v1v2), vec3(v2v3));
    normal = normalize(normal);
    if (normal.z < 0) normal = -normal;

    mat4 MVPMatrix = u_Projection * u_View * u_Model;

    for (int i = 0; i < gl_in.length(); i++) {
        v_Position = gl_in[i].gl_Position;
        gl_Position = MVPMatrix * gl_in[i].gl_Position;

        model = u_Model;
        view = u_View;
        projection = u_Projection;
        norm = normal;

        if (v_Position.y < greenValue) {
            ambientColor = vec4(0, 1, 0, 1);
            diffuseColor = ambientColor;
            specularColor = vec4(0, 0, 0, 1);
        } else if (v_Position.y < greyValue) {
            ambientColor = vec4(0.4, 0.4, 0.4, 1);
            diffuseColor = ambientColor;
            specularColor = vec4(0, 0, 0, 1);
        } else {
            ambientColor = vec4(1, 1, 1, 1);
            diffuseColor = ambientColor;
            specularColor = ambientColor;
        }

        EmitVertex();
    }
    EndPrimitive();
}

片段着色器:

#version 330 core

precision mediump float;                    // Set the default precision to medium. We don't need as high of a
                                            // precision in the fragment shader.

#define MAX_LAMPS_COUNT 8                   // Max lamps count.

uniform vec3 u_ViewPos;                     // Camera position
uniform int u_LampsCount;                   // Lamps count
uniform float brightnessThreshold = 0.3;    // brightness threshold variable
uniform float far_plane;                    // shadow matrix far plane

in mat4 model, view, projection;
in vec4 v_Position;                     // Position for this fragment in world space

in vec4 ambientColor;
in vec4 diffuseColor;
in vec4 specularColor;
in vec3 norm;

struct Lamp {
    float ambientStrength;
    float diffuseStrength;
    float specularStrength;
    float kc; // constant term
    float kl; // linear term
    float kq; // quadratic term
    int shininess;
    vec3 lampPos; // in world space
    vec3 lampColor;
};

uniform samplerCube shadowMaps[MAX_LAMPS_COUNT];
uniform Lamp u_Lamps[MAX_LAMPS_COUNT];

vec3 fragPos;
vec3 fragWorldPos;
vec3 lampEyePos; // Transformed lamp position into eye space
float shadow;

// for PCF
vec3 sampleOffsetDirections[20] = vec3[] (
        vec3(1, 1, 1), vec3(1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1),
        vec3(1, 1, -1), vec3(1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1),
        vec3(1, 1, 0), vec3(1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0),
        vec3(1, 0, 1), vec3(-1, 0, 1), vec3(1, 0, -1), vec3(-1, 0, -1),
        vec3(0, 1, 1), vec3(0, -1, 1), vec3(0, -1, -1), vec3(0, 1, -1)
);

// output colors
layout(location = 0) out vec4 fragColor;
layout(location = 1) out vec4 fragBrightColor;

float calculateShadow(vec3 lightDir, int index) {
    // get vector between fragment position and light position
    vec3 fragToLight = fragWorldPos - u_Lamps[index].lampPos;
    // now get current linear depth as the length between the fragment and light position
    float currentDepth = length(fragToLight);
    // now test for shadows
    //float bias = max(0.5 * (1.0 - dot(norm, lightDir)), 0.005);
    float bias = 1;

    // PCF
    float viewDistance = length(u_ViewPos - fragWorldPos);
    float diskRadius = (1.0 + (viewDistance / far_plane)) / 25.0;
    for (int i = 0; i < 20; ++i) {
        float closestDepth = texture(shadowMaps[index], fragToLight + sampleOffsetDirections[i] * diskRadius).r;
        closestDepth *= far_plane; // Undo mapping [0;1]
        if(currentDepth - bias > closestDepth) shadow += 1.0;
    }
    shadow /= 20;

    //fragColor = vec4(vec3(closestDepth / far_plane), 1.0); // visualizing
    return shadow;
}

float calculateAttenuation(Lamp lamp) {
    float distance = length(lampEyePos - fragPos);
    return 1.0 / (
                    lamp.kc +
                    lamp.kl * distance +
                    lamp.kq * (distance * distance)
            );
}

vec4 toVec4(vec3 v) {
    return vec4(v, 1);
}

// The entry point for our fragment shader.
void main() {
    fragWorldPos = vec3(model * v_Position);
     // Transform the vertex into eye space
    mat4 mvMatrix = view * model;
    fragPos = vec3(mvMatrix * v_Position);

    vec3 viewDir = normalize(u_ViewPos - fragPos);

    vec3 ambientResult = vec3(0, 0, 0); // result of ambient lighting for all lamps
    vec3 diffuseResult = vec3(0, 0, 0); // result of diffuse lighting for all lamps
    vec3 specularResult = vec3(0, 0, 0); // result of specular lighting for all lamps

    for (int i = 0; i<u_LampsCount; i++) {
        lampEyePos = vec3(view * toVec4(u_Lamps[i].lampPos));
        // attenuation
        float attenuation = calculateAttenuation(u_Lamps[i]);

        // ambient
        vec3 ambient = u_Lamps[i].ambientStrength * u_Lamps[i].lampColor * attenuation;

        // diffuse
        vec3 lightDir = normalize(lampEyePos - fragPos);
        float diff = max(dot(norm, lightDir), 0.0);
        vec3 diffuse = u_Lamps[i].diffuseStrength * diff * u_Lamps[i].lampColor * attenuation;

        // specular
        vec3 reflectDir = reflect(-lightDir, norm);
        float spec = pow(max(dot(viewDir, reflectDir), 0.0), u_Lamps[i].shininess);
        vec3 specular = u_Lamps[i].specularStrength * spec * u_Lamps[i].lampColor * attenuation;

        // calculate shadow
        shadow = calculateShadow(lightDir, i);

        // result for this(i) lamp
        ambientResult += ambient;
        diffuseResult += diffuse * (1-shadow);
        specularResult += specular * (1-shadow);
    }

    fragColor =
            toVec4(ambientResult) * ambientColor +
            toVec4(diffuseResult) * diffuseColor +
            toVec4(specularResult) * specularColor;

    // brightness calculation
    float brightness = dot(fragColor.rgb, vec3(0.2126, 0.7152, 0.0722));
    if (brightness > brightnessThreshold) fragBrightColor = vec4(fragColor.rgb, 1.0);
}

和我的阴影着色器

顶点着色器:

#version 130

attribute vec3 a_Position;
uniform mat4 u_ModelMatrix;

void main() {
    gl_Position = u_ModelMatrix * vec4(a_Position, 1.0);
}

几何着色器:

#version 330 core
layout (triangles) in;
layout (triangle_strip, max_vertices=18) out;

uniform mat4 shadowMatrices[6];

out vec4 fragPos; // FragPos from GS (output per emitvertex)

void main() {
    for(int face = 0; face < 6; face++) {
        gl_Layer = face; // built-in variable that specifies to which face we render.
        // for each triangle's vertices
        for(int i = 0; i < 3; i++) {
            fragPos = gl_in[i].gl_Position;
            gl_Position = shadowMatrices[face] * fragPos;
            EmitVertex();
        }
        EndPrimitive();
    }
}

片段着色器:

#version 330 core
in vec4 fragPos; // world space

uniform vec3 lightPos; // world space
uniform float far_plane; // shadow matrix far plane

void main()
{
    float lightDistance = length(fragPos.xyz - lightPos);

    // map to [0;1] range by dividing by far_plane
    lightDistance = lightDistance / far_plane;

    // write this as modified depth
    gl_FragDepth = lightDistance;
}

希望您能帮助您优化此场景。

0 个答案:

没有答案