如何更改片段着色器以允许再增加2个聚光灯?

时间:2017-08-16 07:05:28

标签: opengl glfw glm-math

我的节目是一个聚光灯在中心的房间(由球体描绘)。

enter image description here

我想在房间的角落再添加2个灯,但我不知道如何更改片段着色器中的main功能以允许此操作。我编辑了我的主程序来设置2个新灯的属性并将它们绑定到片段着色器。

片段着色器

#version 330 core

#define MAX_MATERIALS 12
#define MAX_LIGHTS 3

// interpolated values from the vertex shaders
in vec3 vNormal;
in vec3 vPosition;

// uniform input data
struct LightProperties
{
    vec4 position;
    vec4 ambient;
    vec4 diffuse;
    vec4 specular;
    float shininess;
    vec3 attenuation;
    float cutoffAngle;
    vec3 direction;
};

struct MaterialProperties
{
    vec4 ambient;
    vec4 diffuse;
    vec4 specular;
};

uniform int uMaterialIndex;
uniform LightProperties uLightingProperties[MAX_LIGHTS];
uniform MaterialProperties uMaterialProperties[MAX_MATERIALS];
uniform vec3 uViewPoint;

// output data
out vec3 fColor;

void main()
{
    // calculate vectors for lighting
    vec3 N = normalize(vNormal);
    vec3 L;
    float attenuation = 1.0f;

    // calculate the attenuation based on distance
    L = (uLightingProperties.position).xyz - vPosition;
    float distance = length(L);
    L = normalize(L);
    attenuation = 1/(uLightingProperties.attenuation.x 
        + uLightingProperties.attenuation.y * distance 
        + uLightingProperties.attenuation.z * distance * distance);

    vec3 V = normalize(uViewPoint - vPosition);
    vec3 R = reflect(-L, N);

    // the direction of the spotlight
    vec3 direction = normalize(uLightingProperties.direction);
    // the angle between the vector from the light to the fragment’s position and the spotlight’s direction
    float angle = degrees(acos(dot(-L, direction)));

    vec3 colour = vec3(0.0f, 0.0f, 0.0f);

    // only compute if angle is less than the cutoff angle
    if(angle <= uLightingProperties.cutoffAngle)
    {
        int i = uMaterialIndex;

        // calculate Phong lighting
        vec4 ambient  = uLightingProperties.ambient * uMaterialProperties[i].ambient;
        vec4 diffuse  = uLightingProperties.diffuse * uMaterialProperties[i].diffuse * max(dot(L, N), 0.0);
        vec4 specular = vec4(0.0f, 0.0f, 0.0f, 1.0f);

        if(dot(L, N) > 0.0f)
        {
            specular = uLightingProperties.specular * uMaterialProperties[i].specular 
                * pow(max(dot(V, R), 0.0), uLightingProperties.shininess);
        }

        colour = (attenuation * (diffuse + specular)).rgb + ambient.rgb;
        // fade the spotlight's intensity linearly with angle
        colour *= 1.0f - angle/uLightingProperties.cutoffAngle;
    }

    // set output color
    fColor = colour;    
}

主程序

#define MAX_LIGHTS 3
#define MAX_MATERIALS 12

// struct for lighting properties
struct LightProperties
{
    vec4 position;
    vec4 ambient;
    vec4 diffuse;
    vec4 specular;
    float shininess;
    vec3 attenuation;
    float cutoffAngle;
    vec3 direction;
};

// struct for material properties
struct MaterialProperties
{
    vec4 ambient;
    vec4 diffuse;
    vec4 specular;
};

LightProperties g_lightProperties[MAX_LIGHTS];
MaterialProperties g_materialProperties[MAX_MATERIALS];

// Meshes
Vertex* g_pMeshVertices[MAX_MESH] = { NULL };   // pointer to mesh vertices
GLint g_numberOfVertices[MAX_MESH] = { 0 };     // number of vertices in the mesh
GLint* g_pMeshIndices[MAX_MESH] = { NULL };     // pointer to mesh indices
GLint g_numberOfFaces[MAX_MESH] = { 0 };        // number of faces in the mesh

GLuint g_IBO[4];                // index buffer object identifier
GLuint g_VBO[5];                // vertex buffer object identifier
GLuint g_VAO[5];                // vertex array object identifier
GLuint g_shaderProgramID = 0;   // shader program identifier

// Values for spotlight
glm::vec3 g_spotlight_ambient(0.2f, 0.2f, 0.2f);
glm::vec3 g_spotlight_diffuse(0.5f, 0.5f, 0.5f);
glm::vec3 g_spotlight_specular(0.0f, 0.5f, 0.5f);

// locations in shader
GLuint g_MVP_Index;
GLuint g_M_Index = 0;
GLuint g_viewPointIndex = 0;
GLuint g_lightPositionIndex[MAX_LIGHTS];
GLuint g_lightAmbientIndex[MAX_LIGHTS];
GLuint g_lightDiffuseIndex[MAX_LIGHTS];
GLuint g_lightSpecularIndex[MAX_LIGHTS];
GLuint g_lightShininessIndex[MAX_LIGHTS];
GLuint g_lightAttenuationIndex[MAX_LIGHTS];
GLuint g_lightCutoffAngleIndex[MAX_LIGHTS];
GLuint g_lightDirectionIndex[MAX_LIGHTS];
GLuint g_materialIndex = 0;
GLuint g_materialAmbientIndex[MAX_MATERIALS];
GLuint g_materialDiffuseIndex[MAX_MATERIALS];
GLuint g_materialSpecularIndex[MAX_MATERIALS];

static void init(GLFWwindow* window)
{
    glEnable(GL_DEPTH_TEST);    // enable depth buffer test

    // create and compile our GLSL program from the shader files
    g_shaderProgramID = loadShaders("PerFragLightingVS.vert", "PerFragLightingFS.frag");

    // find the location of shader variables
    GLuint positionIndex = glGetAttribLocation(g_shaderProgramID, "aPosition");
    GLuint normalIndex = glGetAttribLocation(g_shaderProgramID, "aNormal");
    g_MVP_Index = glGetUniformLocation(g_shaderProgramID, "uModelViewProjectionMatrix");
    g_M_Index = glGetUniformLocation(g_shaderProgramID, "uModelMatrix");
    g_viewPointIndex = glGetUniformLocation(g_shaderProgramID, "uViewPoint");

    g_lightPositionIndex[0] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[0].position");
    g_lightAmbientIndex[0] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[0].ambient");
    g_lightDiffuseIndex[0] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[0].diffuse");
    g_lightSpecularIndex[0] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[0].specular");
    g_lightShininessIndex[0] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[0].shininess");
    g_lightAttenuationIndex[0] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[0].attenuation");
    g_lightCutoffAngleIndex[0] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[0].cutoffAngle");
    g_lightDirectionIndex[0] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[0].direction");

    g_lightPositionIndex[1] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[1].position");
    g_lightAmbientIndex[1] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[1].ambient");
    g_lightDiffuseIndex[1] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[1].diffuse");
    g_lightSpecularIndex[1] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[1].specular");
    g_lightShininessIndex[1] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[1].shininess");
    g_lightAttenuationIndex[1] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[1].attenuation");
    g_lightCutoffAngleIndex[1] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[1].cutoffAngle");
    g_lightDirectionIndex[1] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[1].direction");

    g_lightPositionIndex[2] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[2].position");
    g_lightAmbientIndex[2] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[2].ambient");
    g_lightDiffuseIndex[2] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[2].diffuse");
    g_lightSpecularIndex[2] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[2].specular");
    g_lightShininessIndex[2] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[2].shininess");
    g_lightAttenuationIndex[2] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[2].attenuation");
    g_lightCutoffAngleIndex[2] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[2].cutoffAngle");
    g_lightDirectionIndex[2] = glGetUniformLocation(g_shaderProgramID, "uLightingProperties[2].direction");

    g_materialIndex = glGetUniformLocation(g_shaderProgramID, "uMaterialIndex");    // to change the index for material in fragment shader

    // Find location for uniform matrix (material properties)
    for (int i = 0; i < MAX_MATERIALS; i++) {
        std::string str = "uMaterialProperties[" + std::to_string(i);
        g_materialAmbientIndex[i] = glGetUniformLocation(g_shaderProgramID, (str + "].ambient").data());
        g_materialDiffuseIndex[i] = glGetUniformLocation(g_shaderProgramID, (str + "].diffuse").data());
        g_materialSpecularIndex[i] = glGetUniformLocation(g_shaderProgramID, (str + "].specular").data());
    }

    ...

// initialise light and material properties
    g_lightProperties[0].position = glm::vec4(0.0f, 2.0f, 0.0f, 1.0f);
    g_lightProperties[0].ambient = glm::vec4(g_spotlight_ambient[0], g_spotlight_ambient[1], g_spotlight_ambient[2], 1.0f);
    g_lightProperties[0].diffuse = glm::vec4(g_spotlight_diffuse[0], g_spotlight_diffuse[1], g_spotlight_diffuse[2], 1.0f);
    g_lightProperties[0].specular = glm::vec4(g_spotlight_specular[0], g_spotlight_specular[1], g_spotlight_specular[2], 1.0f);
    g_lightProperties[0].shininess = 10.0f;
    g_lightProperties[0].attenuation = glm::vec3(1.0f, 0.0f, 0.0f);
    g_lightProperties[0].cutoffAngle = 150.0f;
    g_lightProperties[0].direction = glm::vec3(0.0f, -1.0f, 0.0f);

    g_lightProperties[1].position = glm::vec4(-2.0f, 2.0f, 0.0f, 1.0f);
    g_lightProperties[1].ambient = glm::vec4(g_spotlight_ambient[0], g_spotlight_ambient[1], g_spotlight_ambient[2], 1.0f);
    g_lightProperties[1].diffuse = glm::vec4(g_spotlight_diffuse[0], g_spotlight_diffuse[1], g_spotlight_diffuse[2], 1.0f);
    g_lightProperties[1].specular = glm::vec4(g_spotlight_specular[0], g_spotlight_specular[1], g_spotlight_specular[2], 1.0f);
    g_lightProperties[1].shininess = 10.0f;
    g_lightProperties[1].attenuation = glm::vec3(1.0f, 0.0f, 0.0f);
    g_lightProperties[1].cutoffAngle = 150.0f;
    g_lightProperties[1].direction = glm::vec3(0.0f, -1.0f, 0.0f);

    g_lightProperties[2].position = glm::vec4(2.0f, 2.0f, 0.0f, 1.0f);
    g_lightProperties[2].ambient = glm::vec4(g_spotlight_ambient[0], g_spotlight_ambient[1], g_spotlight_ambient[2], 1.0f);
    g_lightProperties[2].diffuse = glm::vec4(g_spotlight_diffuse[0], g_spotlight_diffuse[1], g_spotlight_diffuse[2], 1.0f);
    g_lightProperties[2].specular = glm::vec4(g_spotlight_specular[0], g_spotlight_specular[1], g_spotlight_specular[2], 1.0f);
    g_lightProperties[2].shininess = 10.0f;
    g_lightProperties[2].attenuation = glm::vec3(1.0f, 0.0f, 0.0f);
    g_lightProperties[2].cutoffAngle = 150.0f;
    g_lightProperties[2].direction = glm::vec3(0.0f, -1.0f, 0.0f);

    ...
}

// function used to render the scene
static void render_scene()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear colour buffer and depth buffer

    glUseProgram(g_shaderProgramID);    // use the shaders associated with the shader program

    glBindVertexArray(g_VAO[0]);        // make VAO active

// Set uniform matrix for material properties 
    for (int i = 0; i < MAX_MATERIALS; i++) {
        glUniform4fv(g_materialAmbientIndex[i], 1, &g_materialProperties[i].ambient[0]);
        glUniform4fv(g_materialDiffuseIndex[i], 1, &g_materialProperties[i].diffuse[0]);
        glUniform4fv(g_materialSpecularIndex[i], 1, &g_materialProperties[i].specular[0]);
    }
// Set uniform matrix for light properties
    for (int i = 0; i < MAX_LIGHTS; i++) {
        glUniform4fv(g_lightPositionIndex[i], 1, &g_lightProperties[i].position[0]);
        glUniform4fv(g_lightAmbientIndex[i], 1, &g_lightProperties[i].ambient[0]);
        glUniform4fv(g_lightDiffuseIndex[i], 1, &g_lightProperties[i].diffuse[0]);
        glUniform4fv(g_lightSpecularIndex[i], 1, &g_lightProperties[i].specular[0]);
        glUniform1fv(g_lightShininessIndex[i], 1, &g_lightProperties[i].shininess);
        glUniform3fv(g_lightAttenuationIndex[i], 1, &g_lightProperties[i].attenuation[0]);
        glUniform1fv(g_lightCutoffAngleIndex[i], 1, &g_lightProperties[i].cutoffAngle);
        glUniform3fv(g_lightDirectionIndex[i], 1, &g_lightProperties[i].direction[0]);
    }

    ...
}

int main(void)
{
    ...

    // initialise AntTweakBar
    TwInit(TW_OPENGL_CORE, NULL);

    // give tweak bar the size of graphics window
    TwWindowSize(g_windowWidth, g_windowHeight);
    TwDefine(" TW_HELP visible=false ");    // disable help menu
    TwDefine(" GLOBAL fontsize=3 ");        // set large font size

    // create a tweak bar
    TweakBar = TwNewBar("Main");
    TwDefine(" Main label='Controls' refresh=0.02 text=light size='220 600' ");

    // create display entries
    TwAddVarRW(TweakBar, "Wireframe", TW_TYPE_BOOLCPP, &g_wireFrame, " group='Display' ");

    // display a separator
    TwAddSeparator(TweakBar, NULL, NULL);

    // create spotlight entries
    TwAddVarRW(TweakBar, "Cutoff", TW_TYPE_FLOAT, &g_lightProperties[0].cutoffAngle, " group='Spotlight' min=-180.0 max=180.0 step=1.0 ");
    TwAddVarRW(TweakBar, "Direction: x", TW_TYPE_FLOAT, &g_lightProperties[0].direction[0], " group='Spotlight' min=-1.0 max=1.0 step=0.1");
    TwAddVarRW(TweakBar, "Direction: y", TW_TYPE_FLOAT, &g_lightProperties[0].direction[1], " group='Spotlight' min=-1.0 max=1.0 step=0.1");
    TwAddVarRW(TweakBar, "Direction: z", TW_TYPE_FLOAT, &g_lightProperties[0].direction[2], " group='Spotlight' min=-1.0 max=1.0 step=0.1");
    // create transformation entries
    TwAddVarRW(TweakBar, "A Red", TW_TYPE_FLOAT, &g_spotlight_ambient[0], " group='Ambient' min=-1.0 max=1.0 step=0.01");
    TwAddVarRW(TweakBar, "A Green", TW_TYPE_FLOAT, &g_spotlight_ambient[1], " group='Ambient' min=-1.0 max=1.0 step=0.01");
    TwAddVarRW(TweakBar, "A Blue", TW_TYPE_FLOAT, &g_spotlight_ambient[2], " group='Ambient' min=-1.0 max=1.0 step=0.01");

    TwAddVarRW(TweakBar, "D Red", TW_TYPE_FLOAT, &g_spotlight_diffuse[0], " group='Diffuse' min=-1.0 max=1.0 step=0.01");
    TwAddVarRW(TweakBar, "D Green", TW_TYPE_FLOAT, &g_spotlight_diffuse[1], " group='Diffuse' min=-1.0 max=1.0 step=0.01");
    TwAddVarRW(TweakBar, "D Blue", TW_TYPE_FLOAT, &g_spotlight_diffuse[2], " group='Diffuse' min=-1.0 max=1.0 step=0.01");

    TwAddVarRW(TweakBar, "S Red", TW_TYPE_FLOAT, &g_spotlight_specular[0], " group='Specular' min=-1.0 max=1.0 step=0.01");
    TwAddVarRW(TweakBar, "S Green", TW_TYPE_FLOAT, &g_spotlight_specular[1], " group='Specular' min=-1.0 max=1.0 step=0.01");
    TwAddVarRW(TweakBar, "S Blue", TW_TYPE_FLOAT, &g_spotlight_specular[2], " group='Specular' min=-1.0 max=1.0 step=0.01");

    TwAddVarRW(TweakBar, "Light", TW_TYPE_BOOLCPP, &g_switchOn, " group='Toggle ON/OFF' ");
    TwAddVarRW(TweakBar, "Disco", TW_TYPE_BOOLCPP, &g_disco_mode, " group='Toggle ON/OFF' ");

    // initialise rendering states
    init(window);

    // the rendering loop
    while (!glfwWindowShouldClose(window))
    {
        g_camera.update(window);    // update camera

        if (g_wireFrame)
            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

        update_scene();     // update the scene
        render_scene();     // render the scene

        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

        TwDraw();           // draw tweak bar(s)

        glfwSwapBuffers(window);    // swap buffers
        glfwPollEvents();           // poll for events
    }

    ...
}

1 个答案:

答案 0 :(得分:0)

由于您已经有一系列光源,您只需要总结单个光源的光色计算。

创建一个新的统一变量,用于保存光源的数量:

uniform int u_noOfLights;

设置灯光属性时不要忘记设置制服。

在函数中移动计算光源光源颜色的所有代码。 该函数应该有一个输入参数,其中可以传递要计算的光源的索引。

vec3 Light( vec3 N, int index )
{
    float attenuation = 1.0f;

    // calculate the attenuation based on distance
    vec3 L = (uLightingProperties[index].position).xyz - vPosition;
    float distance = length(L);
    L = normalize(L);
    attenuation = 1/(uLightingProperties[index].attenuation.x 
        + uLightingProperties[index].attenuation.y * distance 
        + uLightingProperties[index].attenuation.z * distance * distance);

    vec3 V = normalize(uViewPoint - vPosition);
    vec3 R = reflect(-L, N);

    // the direction of the spotlight
    vec3 direction = normalize(uLightingProperties[index].direction);
    // the angle between the vector from the light to the fragment’s position and the spotlight’s direction
    float angle = degrees(acos(dot(-L, direction)));

    vec3 colour = vec3(0.0f, 0.0f, 0.0f);

    // only compute if angle is less than the cutoff angle
    if(angle <= uLightingProperties[index].cutoffAngle)
    {
        int i = uMaterialIndex;

        // calculate Phong lighting
        vec4 ambient  = uLightingProperties[index].ambient * uMaterialProperties[i].ambient;
        vec4 diffuse  = uLightingProperties[index].diffuse * uMaterialProperties[i].diffuse * max(dot(L, N), 0.0);
        vec4 specular = vec4(0.0f, 0.0f, 0.0f, 1.0f);

        if(dot(L, N) > 0.0f)
        {
            specular = uLightingProperties[index].specular * uMaterialProperties[i].specular 
                * pow(max(dot(V, R), 0.0), uLightingProperties[index].shininess);
        }

        colour = (attenuation * (diffuse + specular)).rgb + ambient.rgb;
        // fade the spotlight's intensity linearly with angle
        colour *= 1.0f - angle/uLightingProperties[index].cutoffAngle;
    }
    return colour;
}

在片段的main中,您必须实现一个for循环,该循环迭代光源并总结 由功能计算的浅色:

void main()
{
    vec3 N = normalize(vNormal);
    vec3 colour = vec3(0.0f, 0.0f, 0.0f);
    for ( int i = 0; i < u_noOfLights; ++i )
        colour += Light( N, i );

    // set output color
    fColor = colour;    
}