首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

OpenGL GLSL 多光源光照實作:平行光、點光源與聚光燈完整著色器解析

     編輯:程式設計疑難解答

需求背景

在 LearnOpenGL 教學的 Multiple Lights 章節中,需實現:1 個平行光、4 個點光源、1 個聚光燈對 10 個箱子的光照效果。註解掉聚光燈後物體變黑,表示平行光與點光源計算異常。

著色器架構總覽

// 材質
struct Material { sampler2D texture0, texture1, texture2; float shininess; };

// 聚光燈
struct FlashLight { vec3 ambient, diffuse, specular, position, directional; float cutoff, outcutoff, constant, linear, quadratic; };

// 點光源
struct PointLight { vec3 ambient, diffuse, specular, position; float constant, linear, quadratic; };

// 平行光
struct DirectLight { vec3 ambient, diffuse, specular, directional; };

uniform Material material;
uniform PointLight pointlight[4];
uniform FlashLight flashlight;
uniform DirectLight directlight;
uniform vec3 cameraPos;

主函數光照累加邏輯

void main() {
    vec3 normal = normalize(Normal);
    vec3 viewDir = normalize(cameraPos - fragPos);

    vec3 result = calcDirectLight(directlight, normal, viewDir);
    for (int i = 0; i < 4; i++)
        result += calcPointLight(pointlight[i], fragPos, normal, viewDir);
    result += calcFlashLight(flashlight, fragPos, normal, viewDir);

    color = vec4(result, 1.0);
}

關鍵問題排查清單

  1. Uniform 變數是否正確傳遞:CPU 端需為每個光源結構體的所有欄位設定值(glUniform3fv, glUniform1f 等),特別是 directlight.directional、pointlight[i].position、衰減係數等。若未設定,預設為 0 導致光照為黑。
  2. 材質屬性是否設定:material.shininess、貼圖單元 texture0/1/2 是否綁定並賦值?
  3. 法線向量是否正確:模型匯入或生成時法線是否歸一化?頂點著色器是否正確傳遞 Normal 到片段著色器?
  4. 視角向量計算:viewDir = normalize(cameraPos - fragPos),確認 cameraPos 為世界座標且正確傳入。
  5. 平行光方向向量:directlight.directional 應為「光線傳播方向」(從光源指向場景),片段著色器中使用 normalize(-light.directional) 取得入射方向,確認 CPU 傳入方向正確。
  6. 點光源位置空間一致性:pointlight[i].position 必須與 fragPos 在同一空間(通常為世界空間)。
  7. 衰減係數合理性:constant=1.0, linear=0.09, quadratic=0.032 為常見預設值,過大會導致光照極快衰減至 0。

除錯建議

  • 先只啟用平行光,觀察是否有光照;再逐一加入點光源、聚光燈。
  • 在片段著色器中輸出中間變數顏色(如 color = vec4(normal * 0.5 + 0.5, 1.0))驗證法線正確性。
  • 使用 glGetError() 或 RenderDoc 捕獲幀進行 Uniform 檢查。

常見錯誤修正範例

平行光計算修正:確保 directional 為單位向量且方向正確。

vec3 calcDirectLight(DirectLight light, vec3 normal, vec3 viewDir) {
    vec3 lightDir = normalize(-light.directional); // 入射方向
    float diff = max(dot(normal, lightDir), 0.0);
    // ... ambient, diffuse, specular 計算
    return ambient + diffuse + specular; // 平行光無衰減
}

CPU 端設定範例:

// 平行光
glUniform3fv(glGetUniformLocation(shader, "directlight.directional"), 1, glm::value_ptr(glm::normalize(glm::vec3(-0.2f, -1.0f, -0.3f))));
glUniform3fv(glGetUniformLocation(shader, "directlight.ambient"), 1, glm::value_ptr(glm::vec3(0.05f)));
glUniform3fv(glGetUniformLocation(shader, "directlight.diffuse"), 1, glm::value_ptr(glm::vec3(0.4f)));
glUniform3fv(glGetUniformLocation(shader, "directlight.specular"), 1, glm::value_ptr(glm::vec3(0.5f)));
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved