Lesson 17: SDK文档:Tutorial 6 Lighting分析

中文翻译文档地址:
http://blog.sina.com.cn/s/blog_6e1283650102vfi8.html


在这个教程中,将介绍最基础的光照类型是方向光。方向光不论对象跟光源的距离,都受到统一的关照。当光照到一个表面时,光照的发射计算这个表面和光线的夹角大小。当光线直接照射到表面时,表面会将所有的光反射回去,显示最高的强度。然而,随着表面与光线的角度增长,反射的光照强度会慢慢暗下来。
为了算出光线照射到表面的反射强度,光线的方向和表面的向量将被用来计算。这是表面的向量将被定义为垂直于表面的向量。这个计算只要把两个向量做一个简单的点乘就可以了,这个计算将返回光线在表面向量的投影的值。如果夹角比较大,那么投影就会比较小。那么这给我们一个正确的功能来调节扩散的光线。
这里写图片描述

在这个教程中所使用的光源是一种近似的方向光。光线的向量决定了光线的方向。既然说是近似,不论一个对象在哪里,光线的方向都是一样的。就比如太阳的光线。对于任何对象,受到的太阳的光照都是一样的。除此之外,照射在各个对象上将会有不同的光照强度。
还有其他一些光:点光,辐射光,和聚光。


初始化光照
在这个教程中,有两个光源。一个放在立方体的前面向立方体照射,另一个以立方体为中心绕轨道移动。注意,轨道上的立方体用来表示光源的位置。
既然光照由渲染器计算,一些变量必须声明并绑定。在这个例子中,我们只需要光源的方向向量和它的颜色。第一个光源是灰色,第二个是红色。

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

结构体声明:

struct SimpleVertex
{
    XMFLOAT3 Pos;
    XMFLOAT3 Normal;
};


struct ConstantBuffer
{
    XMMATRIX mWorld;
    XMMATRIX mView;
    XMMATRIX mProjection;
    XMFLOAT4 vLightDir[2]; //光照的方向向量
    XMFLOAT4 vLightColor[2]; //光照的颜色
    XMFLOAT4 vOutputColor; //颜色输出
};

全局变量声明:

// ...
// 新增像素着色器接口指针
ID3D11PixelShader*      g_pPixelShaderSolid = NULL;
// ...

创建顶点缓存:

SimpleVertex vertices[] =
    {
        // 修改为24个顶点
        { XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT3( 0.0f, 1.0f, 0.0f ) },
        { XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT3( 0.0f, 1.0f, 0.0f ) },
        { XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT3( 0.0f, 1.0f, 0.0f ) },
        { XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT3( 0.0f, 1.0f, 0.0f ) },

        { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT3( 0.0f, -1.0f, 0.0f ) },
        { XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT3( 0.0f, -1.0f, 0.0f ) },
        { XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT3( 0.0f, -1.0f, 0.0f ) },
        { XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT3( 0.0f, -1.0f, 0.0f ) },

        { XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT3( -1.0f, 0.0f, 0.0f ) },
        { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT3( -1.0f, 0.0f, 0.0f ) },
        { XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT3( -1.0f, 0.0f, 0.0f ) },
        { XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT3( -1.0f, 0.0f, 0.0f ) },

        { XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT3( 1.0f, 0.0f, 0.0f ) },
        { XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT3( 1.0f, 0.0f, 0.0f ) },
        { XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT3( 1.0f, 0.0f, 0.0f ) },
        { XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT3( 1.0f, 0.0f, 0.0f ) },

        { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT3( 0.0f, 0.0f, -1.0f ) },
        { XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT3( 0.0f, 0.0f, -1.0f ) },
        { XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT3( 0.0f, 0.0f, -1.0f ) },
        { XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT3( 0.0f, 0.0f, -1.0f ) },

        { XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT3( 0.0f, 0.0f, 1.0f ) },
        { XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT3( 0.0f, 0.0f, 1.0f ) },
        { XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT3( 0.0f, 0.0f, 1.0f ) },
        { XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT3( 0.0f, 0.0f, 1.0f ) },
    };

创建索引缓存:

WORD indices[] =
    {
        // 修改索引值
        3,1,0,
        2,1,3,

        6,4,5,
        7,4,6,

        11,9,8,
        10,9,11,

        14,12,13,
        15,12,14,

        19,17,16,
        18,17,19,

        22,20,21,
        23,20,22
    };

清除设备函数:

void CleanupDevice()
{
    // ...
    // 新增了一个接口
    // if( g_pPixelShaderSolid ) g_pPixelShaderSolid->Release();
    // ...
}

渲染函数:

void Render()
{
    // Update our time
    static float t = 0.0f;
    if( g_driverType == D3D_DRIVER_TYPE_REFERENCE )
    {
        t += ( float )XM_PI * 0.0125f;
    }
    else
    {
        static DWORD dwTimeStart = 0;
        DWORD dwTimeCur = GetTickCount();
        if( dwTimeStart == 0 )
            dwTimeStart = dwTimeCur;
        t = ( dwTimeCur - dwTimeStart ) / 1000.0f;
    }

    // 原点处的立方体的世界坐标绕Y轴旋转
    // Rotate cube around the origin
    g_World = XMMatrixRotationY( t );

    // 设置光照参数
    // 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 )
    };

    // 将第二个光源进行变换
    // Rotate the second light around the origin
    // 绕Y轴旋转矩阵
    XMMATRIX mRotate = XMMatrixRotationY( -2.0f * t );
    // 获得方向向量
    XMVECTOR vLightDir = XMLoadFloat4( &vLightDirs[1] );
    // XMVector3Transform()函数用于计算向量和矩阵相乘
    vLightDir = XMVector3Transform( vLightDir, mRotate );
    // 保存变换后的方向向量
    XMStoreFloat4( &vLightDirs[1], vLightDir );

    //
    // Clear the back buffer
    //
    float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f }; // red, green, blue, alpha
    g_pImmediateContext->ClearRenderTargetView( g_pRenderTargetView, ClearColor );

    //
    // Clear the depth buffer to 1.0 (max depth)
    //
    g_pImmediateContext->ClearDepthStencilView( g_pDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0 );

    // 更新矩阵变量和光照变量
    //
    // 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 );

    //
    // Render the cube
    //
    g_pImmediateContext->VSSetShader( g_pVertexShader, NULL, 0 );
    g_pImmediateContext->VSSetConstantBuffers( 0, 1, &g_pConstantBuffer );
    g_pImmediateContext->PSSetShader( g_pPixelShader, NULL, 0 );
    g_pImmediateContext->PSSetConstantBuffers( 0, 1, &g_pConstantBuffer );
    g_pImmediateContext->DrawIndexed( 36, 0, 0 );

    // 对每种光照进行渲染
    //
    // Render each light
    //
    for( int m = 0; m < 2; m++ )
    {
        // 将光源以立方体的形式渲染出来
        // 将向量转换为矩阵形式
        XMMATRIX mLight = XMMatrixTranslationFromVector( 5.0f * XMLoadFloat4( &vLightDirs[m] ) );
        XMMATRIX mLightScale = XMMatrixScaling( 0.2f, 0.2f, 0.2f );
        mLight = mLightScale * mLight;

        // Update the world variable to reflect the current light
        cb1.mWorld = XMMatrixTranspose( mLight );
        cb1.vOutputColor = vLightColors[m];
        g_pImmediateContext->UpdateSubresource( g_pConstantBuffer, 0, NULL, &cb1, 0, 0 );

        g_pImmediateContext->PSSetShader( g_pPixelShaderSolid, NULL, 0 );
        g_pImmediateContext->DrawIndexed( 36, 0, 0 );
    }

    //
    // Present our back buffer to our front buffer
    //
    g_pSwapChain->Present( 0, 0 );
}

修改渲染着色器,使其能显示灯光:
一旦我们准备好数据,并且渲染器准备好要读入的数据。我们就可以计算出方向光作用在每个像素的结果。之前我们使用的是点乘的方法。
一旦我们将向量与光线进行点乘,然后我们就可以把结果乘以颜色和光线算出光线作用的最后结果。这些值将通过saturate函数,这个函数将颜色值控制在[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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值