Direct3D开启光照和使用材质绘制物体

光照的设置不仅要设置光照操作函数,还需要设置光照渲染状态。  

// 设置灯光索引和灯光
    Device->SetLight(0, &light);
     // 启用设置的灯光编号
    Device->LightEnable(0, true);

    // 如不需要光照,关闭光照,默认是开启的
    //Device->SetRenderState(D3DRS_LIGHTING, false);

    // 因为需要光照,所以将所有顶点单位化一下
    Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);
    // 设置启用镜面高光,镜面高光性能开销比较大,一般不开启,开启后旋转物体会导致闪烁
    //Device->SetRenderState(D3DRS_SPECULARENABLE, false);
    // 设置全景抗锯齿,旋转中还是会存在锯齿
    Device->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE);


一、Direct3D光照和材质基本概念

如果开启光照(默认是开启的),那么就不用指定顶点的颜色。而是Direct3D将顶点送入light engine, 根据光源类型、材质material和物体表面相对光源的朝向,计算出每个顶点的颜色值。

1.光源的分量

光照模型中,光源发出来的光由3个分量(或者类型)组成:

1)Ambient Light环境光,通过其它物体(非光源)反射到物体上的光。

2)Diffuse Light漫反射光,只需要考虑光源传播的方向和物体表面的朝向,不需要考虑观察者的位置。

3)Specular Light镜面反射光,需要考虑光源的位置传播的方向,物体表面的朝向,以及观察者的位置。

镜面反射计算消耗比较大,开启关照后,镜面反射需要特别开启或关闭。

使用:

Device->LightEnable(0, true);// 默认光照是开启的,如果不需要关照那么可以关闭光照提高性能
Device->SetRenderState(D3DRS_SPECULARENABLE, false);

2.材质

材质指定的光是指物体表面反射的光,如果反射的光是红光,光源发出的光是蓝光,那么物体不会显示颜色,因为物体表面吸收了蓝色的光。

物体的三角网格中的三角顶点结构中没有指定材质属性,那么可以用SetMaterial来指定全局材质,绘制物体,然后再更换材质来绘制物体。

typedef struct _D3DMATERIAL9 {
    D3DCOLORVALUE   Diffuse;        /* Diffuse color RGBA */ // 可以反射的漫反射光的比例[0,1]
    D3DCOLORVALUE   Ambient;        /* Ambient color RGB */可以反射的环境光的比例[0,1],RGB中等于零的意思是全部被吸收了
    D3DCOLORVALUE   Specular;       /* Specular 'shininess' */ // 可以反射的反射光的比例
    D3DCOLORVALUE   Emissive;       /* Emissive color RGB */ // 增强亮度,使其看起来像自发光
    float           Power;          /* Sharpness if specular highlight */ // 高光点的锐度,值越大高光点锐度越大

/*Power -镜面高光,它的值是高光的锐利值,该值越大表示高光强度与周围亮度相差越大,也就是表面的光泽度,越大光斑越小,越小光斑越大

*/
} D3DMATERIAL9;


注意:

1)材质在环境光,漫反射光,反射光中可以调节各种光线的比例,来控制反射那些光的比例,相反的即是吸收的光(为0的是说明全部吸收那些光)。

2)  材质的最终颜色还要考虑到光源的颜色,如果光源是蓝色,材质是反射红色,吸收蓝色,那么最终材质在该光源下将显示为黑色。

使用:

D3DMATERIAL9 d3d::InitMtrl(D3DXCOLOR a, D3DXCOLOR d, D3DXCOLOR s, D3DXCOLOR e, float p)
{
    D3DMATERIAL9 mtrl;
    mtrl.Ambient  = a;
    mtrl.Diffuse  = d;
    mtrl.Specular = s;
    mtrl.Emissive = e;
    mtrl.Power    = p;
    return mtrl;
}

const D3DMATERIAL9 WHITE_MTRL  = InitMtrl(WHITE, WHITE, WHITE, BLACK, 2.0f);
const D3DMATERIAL9 RED_MTRL    = InitMtrl(RED, RED, RED, BLACK, 2.0f);
const D3DMATERIAL9 GREEN_MTRL  = InitMtrl(GREEN, GREEN, GREEN, BLACK, 2.0f);
const D3DMATERIAL9 BLUE_MTRL   = InitMtrl(BLUE, BLUE, BLUE, BLACK, 2.0f);
 const D3DMATERIAL9 YELLOW_MTRL = InitMtrl(YELLOW, YELLOW, YELLOW, BLACK, 2.0f);


  Device->SetMaterial(&WHITE_MTRL); // 绘制多个材质的多个物品,那么设置一个材质绘制一个物品,设置第二个材质绘制第二个物品


3.顶点法向量

三角网格顶点结构中,因为指定了光照需要的顶点法向量,所以不需要指定顶点颜色了,通过光照引擎计算顶点颜色即可,但是不清楚是否还需要顶点的纹理,应该光照和纹理不存在冲突。

进行光照的时候需要计算顶点法向量,用三角网格的共享顶点计算即可,如果顶点之间的纹理不一样那么需要点拆分,然后计算顶点的法向量,计算完顶点的法向量后需要用

SetRenderState(D3DRS_NORMALIZENORMALS, true);重新规范化顶点的法向量。


因为启用光照以后,光照引擎需要计算每个顶点的颜色,因此需要知道每个网格中三角形顶点的法向量,用该法向量计算顶点的颜色。

计算顶点法向量的方法:

1)三角形三个顶点的法向量等于三角形的法向量,法向量的方向是从三角形的正面(顺时针)射出来的。

vn = (V2 - V1) x (V3 - v1)

v1 = v2 = v3 = vn

2) 对于网格类型的复杂物体,需要更加精确,顶点的法向量用共享该顶点的所有三个三角形的面法向量求平均得到。

Vn = 1/3(V1 + V2 + V3);

经过计算后的顶点法向量可能最后不是规范化的了,因此最后需要使用绘制状态使所有的法向量都重新规范化:

Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);


4. 光源

Direct3D支持三种类型的光源:

位置,方向,衰减是光线基本的属性。

1) 点光源 :  考虑位置和衰减。

2) 平行光 : 只考虑方向。

3)聚光灯:  需要考虑位置,方向,衰减,内部锥形角和外部锥形角.

typedef struct _D3DLIGHT9 {
    D3DLIGHTTYPE    Type;            /* Type of light source */ 光源类型 D3DLIGHT_POINT, D3DLIGHT_DIRECTIONAL, D3DLIGHT_SPOT
    D3DCOLORVALUE   Diffuse;         /* Diffuse color of light */
    D3DCOLORVALUE   Specular;        /* Specular color of light */
    D3DCOLORVALUE   Ambient;         /* Ambient color of light */
    D3DVECTOR       Position;         /* Position in world space */光源位置,平行光没有位置.
    D3DVECTOR       Direction;        /* Direction in world space */光线的方向,点光源没有方向.
    float           Range;            /* Cutoff range */ 光线消亡前的最大光程,最大为根号FLT_MAX,平行光没有range.
    float           Falloff;          /* Falloff */ 聚光灯从内锥形到外锥形的衰减方式,一般为1.0f。
    float           Attenuation0;     /* Constant attenuation */  点光源和锥形光的光源到顶点的衰减后强度:
    float           Attenuation1;     /* Linear attenuation */                                    attenuation =       ________1______  (D 是光源到顶点的距离,D2是D平分, A0-A2是系数)  
    float           Attenuation2;     /* Quadratic attenuation */                                                               A0 + A1D + A2D2        
    float           Theta;            /* Inner angle of spotlight cone */ 聚光灯的内部锥形角
    float           Phi;              /* Outer angle of spotlight cone */ 聚光灯的外部锥形角
} D3DLIGHT9;


D3DLIGHT9 d3d::InitPointLight(D3DXVECTOR3* position, D3DXCOLOR* color)
{
    D3DLIGHT9 light;
    ::ZeroMemory(&light, sizeof(light));

    light.Type      = D3DLIGHT_POINT;
    light.Ambient   = *color * 0.6f;
    light.Diffuse   = *color;
    light.Specular  = *color * 0.6f;
    light.Position  = *position; // 位置, 不考虑方向
    light.Range        = 1000.0f; // 衰减

    light.Falloff      = 1.0f;  // Falloff-灯光从内圆锥到外圆锥之间的强度衰减(仅对聚光灯有效),该值通常设为1.0f。
    light.Attenuation0 = 1.0f; // 光照的衰减,点光源和聚光灯才有,衰减方式为:1 / (A0 + A1*D + A2*D^2)的等比例来衰减,一般A0 = 1, A1 = A2 = 0即可。
    light.Attenuation1 = 0.0f;
    light.Attenuation2 = 0.0f;

    return light;
}

D3DLIGHT9 d3d::InitDirectionalLight(D3DXVECTOR3* direction, D3DXCOLOR* color)
{
    D3DLIGHT9 light;
    ::ZeroMemory(&light, sizeof(light));

    light.Type      = D3DLIGHT_DIRECTIONAL;
    light.Ambient   = *color * 0.6f;
    light.Diffuse   = *color;
    light.Specular  = *color * 0.6f;
    light.Direction = *direction; // 只考虑方向

    return light;
}

D3DLIGHT9 d3d::InitSpotLight(D3DXVECTOR3* position, D3DXVECTOR3* direction, D3DXCOLOR* color)
{
    D3DLIGHT9 light;
    ::ZeroMemory(&light, sizeof(light));

    light.Type      = D3DLIGHT_SPOT;
    light.Ambient   = *color * 0.0f;
    light.Diffuse   = *color;
    light.Specular  = *color * 0.6f;
    light.Position  = *position; // 位置
    light.Direction = *direction; // 方向
    light.Range        = 1000.0f; // 衰减

    light.Falloff      = 1.0f; // Falloff-灯光从内圆锥到外圆锥之间的强度衰减(仅对聚光灯有效),该值通常设为1.0f。
    light.Attenuation0 = 1.0f;
    light.Attenuation1 = 0.0f;
    light.Attenuation2 = 0.0f;
    light.Theta        = 0.4f; // 聚光灯类似圆环的形式,全部内锥角大小theta从[0,Phi], Phi是外锥角大小从[0,D3DX_PI]。
    light.Phi          = 0.9f;

    return light;
}

二、使用实例:

1.开启光照

    // 1).创建点光源

    D3DXVECTOR3 pos(0.0f, 0.0f, 0.0f);
    D3DXCOLOR   c = d3d::WHITE;
    D3DLIGHT9 point = d3d::InitPointLight(&pos, &c);

    // 2).设置光源,启用光照
    // Set and Enable the light.
    //
    D3DLIGHT9;
    Device->SetLight(0, &point); // 0 是 light list的列表元素下标, &point是光源。
    Device->LightEnable(0, true); // 对light list下标为0的元素的光源,开启光照(默认光照是开启的,如果不需要关照那么可以关闭光照提高性能)。

  Device->SetRenderState( D3DRS_LIGHTING, TRUE);


// 3).规范化顶点法向量,开启镜面高光
    // Set lighting related render states.
    //
    Device->SetRenderState(D3DRS_NORMALIZENORMALS, true); // 规范化所有的顶点法向量
    Device->SetRenderState(D3DRS_SPECULARENABLE, false); // 开启反射光线(镜面高光)

2. 使用材质绘制物体

// 设置材质,使用光照来照明材质
 Device->BeginScene();
  // 对每个绘制的物体设置材质和坐标位置,绘制新的位置重新设置材质和位置即可
        for(int i = 0; i < 4; i++)
        {
            // set material and world matrix for ith object, then render
            // the ith object.
            Device->SetMaterial(&Mtrls[i]);
            Device->SetTransform(D3DTS_WORLD, &Worlds[i]);
            Objects[i]->DrawSubset(0);
        }

        Device->EndScene();
        Device->Present(0, 0, 0, 0);



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值