Direct3D 11 Tutorial 6:Lighting_Direct3D 11 教程6:燈光

概述

在之前的教程中,世界看起來很無聊,因爲所有對象都以相同的方式點亮。 本教程將介紹簡單照明的概念及其應用方法。 使用的技術將是朗伯照明。

本教程的結果將修改前面的示例以包含光源。 該光源將附在軌道上的立方體上。 可以在中心立方體上看到光的影響。

資源目錄

(SDK root)\Samples\C++\Direct3D11\Tutorials\Tutorial06

Github

燈光

在本教程中,將介紹最基本的照明類型:朗伯照明。 無論距離光線的距離如何,朗伯照明都具有均勻的強度。 當光照射到表面時,通過光在表面上的入射角計算反射的光量。 當光直接照射在表面上時,它顯示出以最大強度反射所有光。 然而,隨着光的角度增加,光的強度將逐漸消失。

爲了計算光在表面上的強度,必須計算光方向與表面法線之間的角度。 表面的法線定義爲垂直於表面的矢量。 角度的計算可以通過簡單的點積來完成,該點積將光方向矢量的投影返回到法線上。 角度越寬,投影越小。 因此,這爲我們提供了調製漫射光的正確功能。

本教程中使用的光源是定向照明的近似值。 描述光源的矢量確定光的方向。 由於它是近似值,無論物體在哪裏,光線照射到它的方向都是相同的。 這種光源的一個例子是太陽。 對於場景中的所有物體,總是看到太陽朝同一方向發光。 另外,不考慮單個物體上的光強度。

其他類型的光包括從中心輻射均勻光的點光源和在所有物體上方向但不均勻的聚光燈。

初始化燈光

在本教程中,將有兩個光源。 一個將靜態地放置在立方體的上方和後方,另一個將圍繞中心立方體進行軌道運行。 請注意,上一個教程中的軌道立方體已替換爲此光源。

由於光照是由着色器計算的,因此必須聲明變量,然後將其綁定到技術中的變量。 在此示例中,我們只需要光源的方向以及顏色值。 第一盞燈是灰色而不移動,而第二盞是軌道紅燈。

// Setup our lighting parameters
    XMFLOAT4 vLightDirs[2] =
    {
        XMFLOAT4( -0.577f, 0.577f, -0.577f, 1.0f ),
        XMFLOAT4( 0.0f, 0.0f, -1.0f, 1.0f ),
    };
    XMFLOAT4 vLightColors[2] =
    {
        XMFLOAT4( 0.5f, 0.5f, 0.5f, 1.0f ),
        XMFLOAT4( 0.5f, 0.0f, 0.0f, 1.0f )
    };

在上一個教程中,軌道光的旋轉方式與立方體一樣。 應用的旋轉矩陣將改變光的方向,以顯示它始終朝向中心發光的效果。 注意,函數XMVector3Transform用於將矩陣與向量相乘。 在上一個教程中,我們將轉換矩陣乘以世界矩陣,然後傳遞到着色器進行轉換。 但是,爲簡單起見,在這種情況下,我們實際上正在對CPU中的光進行世界變換。

// Rotate the second light around the origin
    XMMATRIX mRotate = XMMatrixRotationY( -2.0f * t );
    XMVECTOR vLightDir = XMLoadFloat4( &vLightDirs[1] );
    vLightDir = XMVector3Transform( vLightDir, mRotate );
    XMStoreFloat4( &vLightDirs[1], vLightDir );

燈光的方向和顏色都像矩陣一樣傳遞到着色器。 調用關聯變量進行設置,並傳入參數。

    //
    // Update matrix variables and lighting variables
    //
    ConstantBuffer cb1;
    cb1.mWorld = XMMatrixTranspose( g_World );
    cb1.mView = XMMatrixTranspose( g_View );
    cb1.mProjection = XMMatrixTranspose( g_Projection );
    cb1.vLightDir[0] = vLightDirs[0];
    cb1.vLightDir[1] = vLightDirs[1];
    cb1.vLightColor[0] = vLightColors[0];
    cb1.vLightColor[1] = vLightColors[1];
    cb1.vOutputColor = XMFLOAT4(0, 0, 0, 0);
    g_pImmediateContext->UpdateSubresource( g_pConstantBuffer, 0, NULL, &cb1, 0, 0 );

渲染像素着色器中的燈光

一旦我們設置了所有數據並且着色器正確地提供了數據,我們就可以計算來自光源的每個像素的朗伯照明術語。 我們將使用之前討論過的點積規則。

一旦我們將光線與正常光線的點積相乘,就可以將其與光線的顏色相乘,以計算光線的效果。 該值通過飽和函數傳遞,該函數將範圍轉換爲[0,1]。 最後,將兩個單獨的燈的結果相加在一起以創建最終的像素顏色。

考慮到表面本身的材料沒有考慮到這個光計算中。 表面的最終顏色是燈光顏色的結果。

    //
    // Pixel Shader
    //
    float4 PS( PS_INPUT input) : SV_Target
    {
        float4 finalColor = 0;
        
        //do NdotL lighting for 2 lights
        for(int i=0; i<2; i++)
        {
            finalColor += saturate( dot( (float3)vLightDir[i],input.Norm) * vLightColor[i] );
        }
        return finalColor;
    }

 一旦通過像素着色器,像素將被光調製,您可以看到每個光在立方體表面上的效果。 請注意,在這種情況下,光看起來很平,因爲同一表面上的像素將具有相同的法線。 漫反射是一種非常簡單易用的計算照明模型。 您可以使用更復雜的照明模型來獲得更豐富,更真實的材料。

最終效果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章