3D游戏编程(四)

今天才发现, 原来金容俊的<3D游戏编程>第一篇的体系和内容是和DX SDK一样的, 这本书上的例子基本就是SDK的例子. 尽管如此, 我还是决定按部就班的实践一番. 这一次, 就来创建一个圆筒, 并加上光源.

第五步: 光源

(一) 材质类型

由多边形组成的三维物体, 称为网格 (Mesh), 网格对于对象是缺乏表现力的, 需要用材质填充其表面, 并以光源使其更加真实.

1. 环境光 (ambient): 物体只具有整体亮度;

2. 漫反射光 (diffuse): 均匀照射在物体表面;

3. 镜面反射光 (specular): 发射到特定方向的光, 光源与摄像机位置不同;

4. 放射光 (emissive): 物体自发光, 不对其他网格产生影响.

(二) 光源类型

1. 环境光源 (ambient light): 与三维空间内网格配置, 位置无关, 没有方向和位置, 只有颜色和强度;

2. 点光源 (point light): 光从一个点发出, 光源位置, 方向不同, 强度也不同;

3. 方向光源 (directional light): 光源的方向是定向的 (如太阳), 和光源位置无关, 方向是最重要的因素;

4. 聚光光源 (spot light): 只对固定位置和方向进行照射, 有方向和强弱, 电影, 舞台的光源就是聚光光源.

这些光源模型只在调用D3D固定函数管道时有效, 如使用HLSL, 顶点着色, 像素着色时就不再有效.

struct  CUSTOMVERTEX
{
    D3DXVECTOR3 position;            
// 顶点三维坐标

    D3DXVECTOR3 normal;            // 顶点法线向量
}
;

BOOL InitD3D(HWND hWnd)
{
    .......
    D3Dpp.EnableAutoDepthStencil 
=
 TRUE;
    D3Dpp.AutoDepthStencilFormat 
=
 D3DFMT_D16;
    .......
    // 卷起, 渲染三角形前面及后面

    g_pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

    
// 起到Z缓冲的作用

    g_pD3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE);

    
return
 S_OK;
}


HRESULT InitGeometry()
{
    
// 创建顶点缓冲

    if(FAILED(g_pD3DDevice->CreateVertexBuffer(100 * sizeof(CUSTOMVERTEX),
            
0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &
g_pVB, NULL)))
    
{
        
return
 E_FAIL;
    }


    
// 使用算法绘制气缸
    CUSTOMVERTEX *pVertices;
    
if(FAILED(g_pVB->Lock(00, (void **)&pVertices, 0
)))
    
{
        
return
 E_FAIL;
    }

    
for(DWORD i=0; i<99; i+=2)
    
{
        FLOAT theta 
= (2 * D3DX_PI * i) / (50 -1
);
        pVertices[i
+0].position = D3DXVECTOR3(sinf(theta), -1.0f, cosf(theta));    // 气缸上方圆

        pVertices[i+0].normal = D3DXVECTOR3(sinf(theta), 0.0f, cosf(theta));    // 气缸上方圆法线
        pVertices[i+1].position = D3DXVECTOR3(sinf(theta), 1.0f, cosf(theta));    // 气缸下方圆
        pVertices[i+1].normal = D3DXVECTOR3(sinf(theta), 0.0f, cosf(theta));    // 气缸下方圆法线
    }

    g_pVB
->Unlock();

    
return
 S_OK;
}


void  SetupMatrices()
{
    
// 世界矩阵

    D3DXMATRIXA16 matWorld;

    D3DXMatrixIsIdentity(
&matWorld);            // 设定世界矩阵为单位矩阵


    D3DXMatrixRotationX(
&matWorld, timeGetTime()/500.0f);    // 绕X轴旋转
    g_pD3DDevice->SetTransform(D3DTS_WORLD, &matWorld);
    .......
}


void  SetupLight()
{
    
// 创建材质 

    D3DMATERIAL9 mtrl;
    ZeroMemory(
&mtrl,sizeof
(D3DMATERIAL9));

    mtrl.Diffuse.a 
= mtrl.Ambient.a = 1.0f
;
    mtrl.Diffuse.r 
= mtrl.Ambient.r = 1.0f
;
    mtrl.Diffuse.g 
= mtrl.Ambient.g = 1.0f
;
    mtrl.Diffuse.b 
= mtrl.Ambient.b = 0.0f
;

    
// 创建光源

    D3DXVECTOR3 vecDir;                    // 方向光源的照射方向
    D3DLIGHT9 light;                    // 光源结构体

    ZeroMemory(
&light, sizeof(D3DLIGHT9));
    light.Type 
= D3DLIGHT_DIRECTIONAL;            // 光源类型为方向光源

    light.Diffuse.r = 1.0f;
    light.Diffuse.g 
= 1.0f
;
    light.Diffuse.b 
= 1.0f
;

    vecDir 
= D3DXVECTOR3(cosf(timeGetTime()/350.0f),    // 光源方向

                        1.0f,
                        sinf(timeGetTime()
/350.0f
));
    D3DXVec3Normalize((D3DXVECTOR3 
*)&light.Direction, &vecDir);    // 将光源方向设为单位向量

    light.Range = 1000.0f;                    // 光源能够照射到的最远距离
    g_pD3DDevice->SetLight(0&light);            // 在设备设置0号光源
    g_pD3DDevice->LightEnable(0, TRUE);            // 打开0号光源
    g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE);    // 打开光源设置
    g_pD3DDevice->SetRenderState(D3DRS_AMBIENT, 0x00202020);    // 设定环境光源的值
}


void  Render()
{
    .......
    // 开始渲染

    if(SUCCEEDED(g_pD3DDevice->BeginScene()))
    
{
        
// 创建光源

        SetupLight();

        
// 创建矩阵

        SetupMatrices();
    .......
        // 输出

        g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 090);
        
// 结束渲染

        g_pD3DDevice->EndScene();
    }


    
// 显示后置缓冲的画面
    g_pD3DDevice->Present(NULL, NULL, NULL, NULL);
}

我的程序出来的圆筒居然是黑色的, 没有光线.

显然应该是SetLight函数出了问题, 原来, 定义的材质没有使用:-(. 在对mtrl初始化之后加上这样一句:

                g_pD3DDevice->SetMaterial(&mtrl);

搞定! :-)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值