错误的镜面位置现代OpenGL / GLSL

时间:2016-04-17 11:33:01

标签: java opengl glsl lwjgl

我正在使用现代OpenGL来创建图形引擎。使用phong和blinn-phong着色模型进行眼睛空间照明计算(法线,镜面反射......)的一切都很好。但是当我尝试实现法线贴图(使用TBN空间计算)时,我的高光照明是错误的:

Wrong specular position

这是我的渲染代码(它是java,但我认为方法和类名对所有程序员都是可以理解的):

// This method renders the given scene to the default framebuffer
public static void renderScene(Scene sce){
    Map<Model, List<Entity>> requests = new HashMap<Model, List<Entity>>();

    // Gets all entities and bind them to a model for optimization
    for(Entity e : sce.getEntities()){
        if(requests.containsKey(e.getModel())){
            requests.get(e.getModel()).add(e);
        }else{
            List<Entity> newBatch = new ArrayList<Entity>();
            newBatch.add(e);

            requests.put(e.getModel(), newBatch);
        }
    }

    Vector4f clearColor = sce.getBackgroundColor();

    // Enable some parameters...
    glEnable(GL_MULTISAMPLE);
    glEnable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);

    // Clear the buffers
    glClearColor(clearColor.x, clearColor.y, clearColor.z, clearColor.w);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Render
    renderAll(requests, sce, materialProg);

    // Clear entities and batch
    requests.clear();
}

// This method render all the given entities (1 model per entity) using the given scene properties (camera, clear color, ambient color, lights)
private static void renderAll(Map<Model, List<Entity>> requests, Scene sce, Program prog){
    Camera cam = sce.getCamera();
    Matrix4f viewMatrix = cam.getViewTransform();
    Matrix4f projMatrix = cam.getProjTransform();

    // Bind the material program
    prog.bind();

    // Sets the projection and view matrix uniforms
    prog.setUniformValue("projection", projMatrix);
    prog.setUniformValue("view", viewMatrix);

    // Sets other parameters
    prog.setUniformValue("ambientColor", sce.getAmbientColor());
    prog.setUniformValue("blinnPhong", true);

    // This is the list of enabled lights only (disabled lights are removed from sce.getLights())
    List<Light> lights = new ArrayList<Light>();

    // Add all enabled lights
    for(Light l : sce.getLights()){
        if(l.isEnabled()){
            lights.add(l);
        }
    }

    // The number of light used (MAX_LIGHTS is a constant, I've set it to 10)
    int numLights = Math.min(MAX_LIGHTS, lights.size());
    prog.setUniformValue("numLights", numLights);

    // The light matrix. Maybe the problem is here.
    // It transform the light direction from world space to eye/cam space
    Matrix3f lightMatrix = new Matrix3f(viewMatrix).invert().transpose();

    for(int i = 0; i < numLights; i++){
        Light l = lights.get(i);

        prog.setUniformValue("allLights["+i+"].color", l.getColor());

        prog.setUniformValue("allLights["+i+"].position", viewMatrix.transformPosition(l.getPosition(), new Vector3f()));
        prog.setUniformValue("allLights["+i+"].direction", lightMatrix.transformDirection(l.getDirection(), new Vector3f()));
        prog.setUniformValue("allLights["+i+"].power", l.getPower());
        prog.setUniformValue("allLights["+i+"].attenuation", l.getAttenuation());
        prog.setUniformValue("allLights["+i+"].coneAngle", l.getConeAngle());
        prog.setUniformValue("allLights["+i+"].coneBlend", l.getConeBlend());

        prog.setUniformValue("allLights["+i+"].isDirectional", l.isDirectional());
    }

    // Rendering all models
    for(Model m : requests.keySet()){
        // For each model to render
        m.getVAO().bind();

        if(m.isBackfaceCulling()){
            glEnable(GL_CULL_FACE);
        }else{
            glDisable(GL_CULL_FACE);
        }

        glPolygonMode(GL_FRONT_AND_BACK, m.getPolygonMode());

        // Material settings
        prog.setUniformValue("diffuseColor", m.getMaterial().getDiffuseColor());
        prog.setUniformValue("shininess", m.getMaterial().getShininess());
        prog.setUniformValue("specularColor", m.getMaterial().getSpecularColor());
        prog.setUniformValue("specularIntensity", m.getMaterial().getSpecularIntensity());
        prog.setUniformValue("normalMapIntensity", m.getMaterial().getNormalMapIntensity());

        prog.setUniformValue("textureRepeat", m.getMaterial().getTextureRepeat());

        if(m.getMaterial().getDiffuseTexture() != null){
            prog.setUniformValue("diffuseTex", 0, m.getMaterial().getDiffuseTexture());
            prog.setUniformValue("hasDiffuseTex", true);
        }else{
            prog.setUniformValue("hasDiffuseTex", false);
        }

        if(m.getMaterial().getNormalTexture() != null){
            prog.setUniformValue("normalTex", 1, m.getMaterial().getNormalTexture());
            prog.setUniformValue("hasNormalTex", true);
        }else{
            prog.setUniformValue("hasNormalTex", false);
        }

        for(Entity e : requests.get(m)){
            Matrix4f modelView = viewMatrix.mul(e.getTransform(), new Matrix4f());
            Matrix3f normalMatrix = new Matrix3f(modelView).invert().transpose();

            // For each entity that use this model
            prog.setUniformValue("model", e.getTransform());
            prog.setUniformValue("normalMatrix", normalMatrix);

            glDrawElements(m.getDrawMode(), m.getVertexCount(), GL_UNSIGNED_INT, 0);
        }

        m.getVAO().unbind();
    }

    prog.unbind();
}

我的着色器

顶点着色器

#version 450 core

// max lights
#define MAX_LIGHTS 10

// current number of light used
uniform int numLights;

// array of lights
uniform struct Light {
    vec3 color;

    vec3 position;
    vec3 direction;

    float power;
    float attenuation;

    float coneAngle;
    float coneBlend;

    bool isDirectional;
} allLights[MAX_LIGHTS];

uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform mat3 normalMatrix;

uniform float textureRepeat;

// Order is important:
// 1: positions
// 2: normals
// 3: uvs
// 4: tangents
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec2 uv;
layout(location = 3) in vec3 tangent;

out vec2 vUV;
out vec3 vToCamera;
out vec3 vPositionTBNSpace;
out vec3 vLightDirections[MAX_LIGHTS];
out vec3 vLightPositions[MAX_LIGHTS];

void main(){
    // Normal in camera space
    vec3 vNormalCamSpace = normalize(normalMatrix * normal);

    // Tangent in and cam space
    vec3 vTangentCamSpace = normalize(normalMatrix * tangent);

    // Bitangent in cam space
    vec3 vBitangentCamSpace = normalize(cross(vNormalCamSpace, vTangentCamSpace));

    mat3 vTBN = transpose(mat3(vTangentCamSpace, vBitangentCamSpace, vNormalCamSpace));

    // Position in camera space
    vec3 positionCamSpace = (view * model * vec4(position, 1.0)).xyz;
    vPositionTBNSpace = vTBN * positionCamSpace;
    vToCamera = normalize(vTBN * (-positionCamSpace));

    for(int i = 0; i < numLights; i++){
        vLightDirections[i] = vTBN * allLights[i].direction;
        vLightPositions[i] = vTBN * allLights[i].position;
    }

    // UV (texture coords)
    vUV = uv * textureRepeat;

    // Final position
    gl_Position = projection * vec4(positionCamSpace, 1.0);
}

片段着色器

#version 450 core

// max lights
#define MAX_LIGHTS 10

// current number of light used
uniform int numLights;

// array of lights
uniform struct Light {
    vec3 color;

    vec3 position;
    vec3 direction;

    float power;
    float attenuation;

    float coneAngle;
    float coneBlend;

    bool isDirectional;
} allLights[MAX_LIGHTS];

// the ambient color
uniform vec3 ambientColor;

// the diffuse texture
uniform bool hasDiffuseTex;
uniform sampler2D diffuseTex;

// the normal texture
uniform bool hasNormalTex;
uniform sampler2D normalTex;

// material settings
uniform bool blinnPhong;

uniform vec3 diffuseColor;
uniform vec3 specularColor;
uniform float specularIntensity;
uniform float normalMapIntensity;
uniform float shininess;

in vec2 vUV;
in vec3 vToCamera;
in vec3 vPositionTBNSpace;
in vec3 vLightDirections[MAX_LIGHTS];
in vec3 vLightPositions[MAX_LIGHTS];

out vec4 color;

// Functions
// Apply a light
vec3 applyLight(Light light, vec3 lightDirection, vec3 lightPosition, vec3 surfaceColor, vec3 normal, vec3 surfacePos, vec3 surfaceToCamera) {
    vec3 surfaceToLight;
    float attenuation = 1.0;

    if(light.isDirectional) {
        // directional light
        surfaceToLight = normalize(-lightDirection);
        attenuation = 1.0; //no attenuation for directional lights
    } else {
        // point light
        surfaceToLight = normalize(lightPosition - surfacePos);
        float distanceToLight = length(lightPosition - surfacePos);
        attenuation = 1.0 - pow(clamp(distanceToLight / light.attenuation, 0.0, 1.0), 2);

        // cone restrictions (affects attenuation)
        float lightToSurfaceAngle = degrees(acos(dot(-surfaceToLight, normalize(lightDirection))));

        if(lightToSurfaceAngle < light.coneAngle){
            // in the shape of the cone

            if(lightToSurfaceAngle > light.coneBlend){
                attenuation *= 1.0 - (lightToSurfaceAngle - light.coneBlend) / (light.coneAngle - light.coneBlend);
            }
        }else{
            attenuation = 0.0;
        }
    }

    // diffuse
    float diffuseCoefficient = clamp(dot(normal, surfaceToLight), 0.0, 1.0);
    vec3 diffuse = diffuseCoefficient * surfaceColor * light.color;

    // specular
    float specularCoefficient = 0;

    if(blinnPhong){
        specularCoefficient = pow(clamp(dot(normal, normalize(surfaceToLight + surfaceToCamera)), 0.0, 1.0), shininess) * diffuseCoefficient;
    }else{
        specularCoefficient = pow(clamp(dot(surfaceToCamera, reflect(-surfaceToLight, normal)), 0.0, 1.0), shininess) * diffuseCoefficient;
    }

    vec3 specular = specularCoefficient * specularIntensity * specularColor * light.color;

    // color
    return attenuation * (diffuse + specular) * light.power;
}

// Main
void main(){
    // Lighting and texturing
    vec3 finalColor = vec3(0);

    vec4 textureColor = vec4(diffuseColor, 1.0);
    vec3 normalTBNSpace = vec3(0.0, 0.0, 1.0);

    if(hasDiffuseTex){
        textureColor *= texture(diffuseTex, vUV);
    }

    if(hasNormalTex){
        normalTBNSpace = mix(vec3(0.0, 0.0, 1.0), normalize(texture(normalTex, vUV).rgb * 2.0 - 1.0), normalMapIntensity);
    }

    vec3 surfaceToCamera = normalize(vToCamera);
    for(int i = 0; i < numLights; i++){
        finalColor += applyLight(allLights[i], vLightDirections[i], vLightPositions[i], textureColor.rgb, normalTBNSpace, vPositionTBNSpace, surfaceToCamera);
    }

    color = vec4((ambientColor * textureColor.rgb) + finalColor, textureColor.a);
    // color = (vec4(vToCamera.xyz, 1.0) + 1) / 2;
}

感谢您的帮助。

0 个答案:

没有答案