代码之家  ›  专栏  ›  技术社区  ›  Zolly

如何更改片段着色器以允许再使用两个聚光灯?

  •  2
  • Zolly  · 技术社区  · 7 年前

    我的程序是一个中心有聚光灯的房间(由球体描绘)。

    enter image description here

    我想在房间的角落里再加两盏灯,但我不知道该怎么换 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 回复  |  直到 7 年前
        1
  •  0
  •   Rabbid76    6 年前

    创建一个新的统一变量,该变量包含光源的数量:

    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;    
    }