zoukankan      html  css  js  c++  java
  • 光照

    使用光照时,我们无需自行指定顶点的颜色。Direct3D会将顶点送入光照的计算引擎,依据光源类型,材质以及物体表面相对光源的朝向,计算出每个顶点的颜色值。

    1.光照的组成

    在Direct3D的光照模型中,有3种类型的光。

    1.1环境光。这种类型的光经其他表面反射到达物体表面,并照亮整个场景。

    1.2漫射光。当光到达某一表面时,将沿着各个方向均匀反射。从各个方向观察,亮度均相同。

    1.3镜面光。当光到达某一表面时,将沿着特定方向反射。只能在一定的角度才能看到高亮度。镜面光计算量较大,默认情况下Direct3D禁用镜面反射。启用镜面光的方法:

    Device->SetRenderState(D3DRS_SPECULARENABLE,true);

    每一种类型的光都可以用结构D3DCOLORVALUE和D3DXCOLOR来表示。这些类型描述了光线的颜色。描述光线颜色时,D3DXCOLOR结构中的Alpha值都将被忽略。

    D3DXCOLOR WhiteCo(1.0f,1.0f, 1.0f, 1.0f)

    2.材质

    在现实世界中物体的颜色是由物体所反射的光的颜色决定的。例如红色的球会反射所有的红色入射光,并吸收非红色的光。在Direct3D中,通过定义物体的材质来模拟此现象。

    typedef struct D3DMATERIAL9 {
        D3DCOLORVALUE Diffuse;  //材质多漫射光的反射率
        D3DCOLORVALUE Ambient;   //材质对环境光的反射率
        D3DCOLORVALUE Specular;  //材质对镜面光的反射率
        D3DCOLORVALUE Emissive;   //用于增强物体的亮度
        float Power; //指定镜面高光点的锐度。
    } D3DMATERIAL9, *LPD3DMATERIAL9;
    顶点结构中不含有材质属性,我们可以用函数对材质进行设定。
    HRESULT  IDirect3DDevice9::SetMaterial(
      CONST D3DMATERIAL9 * pMaterial
    );
    3.顶点法线
    顶点法线描述的是构成多边形的各个顶点的法线。顶点法线的FVF标志D3DFVF_NORMAL.
    使顶点法向量重新规范化:Device->SetRenderState(D3DRS_NORMALIZENORMALS,true);

    4.光源。Direct3D支持3种类型的光源

    4.1点光源 在世界坐标系中有固定位置,向各个方向发射光线。

    4.2方向光 光源没有位置信息,发射的光线平行的沿某一方向走。

    4.3聚光灯 光源有位置信息,光源锥形的沿特定方向传播。有内部锥形,外部锥形。

    光源用D3DLIGHT9表示。

    typedef struct D3DLIGHT9 {
     D3DLIGHTTYPE Type; //光源类型 D3DLIGHT_POINT,D3DLIGHT_SPOT,D3DLIGHT_DIRECTIONAL
        D3DCOLORVALUE Diffuse; //光源发出的漫射光的颜色
        D3DCOLORVALUE Specular; //光源发出的镜面光的颜色
        D3DCOLORVALUE Ambient; //光源发出的环境光的颜色
        D3DVECTOR Position;  //光源在世界坐标系中的位置向量,对方向光无意义
        D3DVECTOR Direction; //光在世界坐标系中传播方向的向量,对点光源无意义。
        float Range; //光线消亡前所能到达的最大光程。最大取值(FLT_MAX开平方), 对方向光无意义
        float Falloff; //仅用于聚光灯。定义光强从内锥形到外锥形的衰减。一般取值1.0f.
        float Attenuation0; //紧接着的3个参数定义了光强随距离的衰减方式
        float Attenuation1;
        float Attenuation2;
        float Theta; //仅用于聚光灯,定义了内锥形的圆锥角,单位弧度
        float Phi; //仅用于聚光灯,定义了外锥形的圆锥角,单位弧度。
    } D3DLIGHT9, *LPD3DLIGHT;
     
    #ifndef __d3dUtilityH__
    #define __d3dUtilityH__
    
    #include <d3dx9.h>
    #include <string>
    
    namespace d3d
    {
        bool InitD3D(
            HINSTANCE hInstance,       // [in] Application instance.
            int width, int height,     // [in] Backbuffer dimensions.
            bool windowed,             // [in] Windowed (true)or full screen (false).
            D3DDEVTYPE deviceType,     // [in] HAL or REF
            IDirect3DDevice9** device);// [out]The created device.
    
        int EnterMsgLoop( 
            bool (*ptr_display)(float timeDelta));
    
        LRESULT CALLBACK WndProc(
            HWND hwnd,
            UINT msg, 
            WPARAM wParam,
            LPARAM lParam);
    
        template<class T> void Release(T t)
        {
            if( t )
            {
                t->Release();
                t = 0;
            }
        }
            
        template<class T> void Delete(T t)
        {
            if( t )
            {
                delete t;
                t = 0;
            }
        }
    
        const D3DXCOLOR      WHITE( D3DCOLOR_XRGB(255, 255, 255) );
        const D3DXCOLOR      BLACK( D3DCOLOR_XRGB(  0,   0,   0) );
        const D3DXCOLOR        RED( D3DCOLOR_XRGB(255,   0,   0) );
        const D3DXCOLOR      GREEN( D3DCOLOR_XRGB(  0, 255,   0) );
        const D3DXCOLOR       BLUE( D3DCOLOR_XRGB(  0,   0, 255) );
        const D3DXCOLOR     YELLOW( D3DCOLOR_XRGB(255, 255,   0) );
        const D3DXCOLOR       CYAN( D3DCOLOR_XRGB(  0, 255, 255) );
        const D3DXCOLOR    MAGENTA( D3DCOLOR_XRGB(255,   0, 255) );
    
        D3DMATERIAL9 InitMtrl(D3DXCOLOR a,D3DXCOLOR d,D3DXCOLOR s,D3DXCOLOR e,float p);
    
        const D3DMATERIAL9 White_Mtrl=InitMtrl(WHITE,WHITE,WHITE,BLACK,8.0f);
        const D3DMATERIAL9 Red_Mtrl=InitMtrl(RED,RED,RED,BLACK,8.0f);
        const D3DMATERIAL9 Green_Mtrl=InitMtrl(GREEN,GREEN,GREEN,BLACK,8.0f);
        const D3DMATERIAL9 Blue_Mtrl=InitMtrl(BLUE,BLUE,BLUE,BLACK,8.0f);
    
        D3DLIGHT9 InitDirectionalLight(D3DVECTOR* direction,D3DXCOLOR * color);
        D3DLIGHT9 InitPointLight(D3DXVECTOR3* position,D3DXCOLOR * color);
        D3DLIGHT9 InitSpotLight(D3DXVECTOR3* position, D3DXVECTOR3* direction, D3DXCOLOR* color);
    }
    
    #endif // __d3dUtilityH__
    d3dUtility.h
    #include "d3dUtility.h"
    
    bool d3d::InitD3D(
        HINSTANCE hInstance,
        int width, int height,
        bool windowed,
        D3DDEVTYPE deviceType,
        IDirect3DDevice9** device)
    { 
        WNDCLASS wc;
    
        wc.style         = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc   = (WNDPROC)d3d::WndProc; 
        wc.cbClsExtra    = 0;
        wc.cbWndExtra    = 0;
        wc.hInstance     = hInstance;
        wc.hIcon         = LoadIcon(0, IDI_APPLICATION);
        wc.hCursor       = LoadCursor(0, IDC_ARROW);
        wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        wc.lpszMenuName  = 0;
        wc.lpszClassName = "Direct3D9App";
    
        if( !RegisterClass(&wc) ) 
        {
            ::MessageBox(0, "RegisterClass() - FAILED", 0, 0);
            return false;
        }
            
        HWND hwnd = 0;
        hwnd = ::CreateWindow("Direct3D9App", "Direct3D9App", 
            WS_EX_TOPMOST,
            0, 0, width, height,
            0 /*parent hwnd*/, 0 /* menu */, hInstance, 0 /*extra*/); 
    
        if( !hwnd )
        {
            ::MessageBox(0, "CreateWindow() - FAILED", 0, 0);
            return false;
        }
    
        ::ShowWindow(hwnd, SW_SHOW);
        ::UpdateWindow(hwnd);
    
        //
        // Init D3D: 
        //
    
        HRESULT hr = 0;
    
        // Step 1: Create the IDirect3D9 object.
    
        IDirect3D9* d3d9 = 0;
        d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
    
        if( !d3d9 )
        {
            ::MessageBox(0, "Direct3DCreate9() - FAILED", 0, 0);
            return false;
        }
    
        // Step 2: Check for hardware vp.
    
        D3DCAPS9 caps;
        d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, deviceType, &caps);
    
        int vp = 0;
        if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )
            vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
        else
            vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
    
        // Step 3: Fill out the D3DPRESENT_PARAMETERS structure.
     
        D3DPRESENT_PARAMETERS d3dpp;
        d3dpp.BackBufferWidth            = width;
        d3dpp.BackBufferHeight           = height;
        d3dpp.BackBufferFormat           = D3DFMT_A8R8G8B8;
        d3dpp.BackBufferCount            = 1;
        d3dpp.MultiSampleType            = D3DMULTISAMPLE_NONE;
        d3dpp.MultiSampleQuality         = 0;
        d3dpp.SwapEffect                 = D3DSWAPEFFECT_DISCARD; 
        d3dpp.hDeviceWindow              = hwnd;
        d3dpp.Windowed                   = windowed;
        d3dpp.EnableAutoDepthStencil     = true; 
        d3dpp.AutoDepthStencilFormat     = D3DFMT_D24S8;
        d3dpp.Flags                      = 0;
        d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
        d3dpp.PresentationInterval       = D3DPRESENT_INTERVAL_IMMEDIATE;
    
        // Step 4: Create the device.
    
        hr = d3d9->CreateDevice(
            D3DADAPTER_DEFAULT, // primary adapter
            deviceType,         // device type
            hwnd,               // window associated with device
            vp,                 // vertex processing
            &d3dpp,             // present parameters
            device);            // return created device
    
        if( FAILED(hr) )
        {
            // try again using a 16-bit depth buffer
            d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
            
            hr = d3d9->CreateDevice(
                D3DADAPTER_DEFAULT,
                deviceType,
                hwnd,
                vp,
                &d3dpp,
                device);
    
            if( FAILED(hr) )
            {
                d3d9->Release(); // done with d3d9 object
                ::MessageBox(0, "CreateDevice() - FAILED", 0, 0);
                return false;
            }
        }
    
        d3d9->Release(); // done with d3d9 object
        
        return true;
    }
    
    int d3d::EnterMsgLoop( bool (*ptr_display)(float timeDelta) )
    {
        MSG msg;
        ::ZeroMemory(&msg, sizeof(MSG));
    
        static float lastTime = (float)timeGetTime(); 
    
        while(msg.message != WM_QUIT)
        {
            if(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
            {
                ::TranslateMessage(&msg);
                ::DispatchMessage(&msg);
            }
            else
            {    
                float currTime  = (float)timeGetTime();
                float timeDelta = (currTime - lastTime)*0.001f;
    
                ptr_display(timeDelta);
    
                lastTime = currTime;
            }
        }
        return msg.wParam;
    }
    
    D3DMATERIAL9 d3d::InitMtrl(D3DXCOLOR a,D3DXCOLOR d,D3DXCOLOR s,D3DXCOLOR e,float p)
    {
        D3DMATERIAL9 mtrl;
        mtrl.Ambient=a;
        mtrl.Diffuse =d;
        mtrl.Emissive =e;
        mtrl.Power =p;
        mtrl.Specular=s;
        return mtrl;
    }
    
    D3DLIGHT9 d3d::InitDirectionalLight(D3DVECTOR* direction,D3DXCOLOR* color)
    {
        D3DLIGHT9 light;
        memset(&light,0,sizeof(light));
        light.Type=D3DLIGHT_DIRECTIONAL;
        light.Ambient=*color * 0.4f;
        light.Diffuse=*color;
        light.Specular=*color * 0.6f;
        light.Direction= *direction;
       return light;
    }
    
    D3DLIGHT9 d3d::InitPointLight(D3DXVECTOR3* position,D3DXCOLOR * color)
    {    
        D3DLIGHT9 light;
        memset(&light,0,sizeof(light));
        light.Type=D3DLIGHT_POINT;
        light.Ambient=*color * 0.4f;
        light.Diffuse=*color;
        light.Specular=*color * 0.6f; 
        light.Position=*position;
        light.Range        = 1000.0f;
        light.Falloff      = 1.0f;
        light.Attenuation0 = 1.0f;
        light.Attenuation1 = 0.0f;
        light.Attenuation2 = 0.0f;
       return light;
    }
    
    D3DLIGHT9 d3d::InitSpotLight(D3DXVECTOR3* position, D3DXVECTOR3* direction, D3DXCOLOR* color)
    {
        D3DLIGHT9 light;
        memset(&light,0,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;
        light.Attenuation0 = 1.0f;
        light.Attenuation1 = 0.0f;
        light.Attenuation2 = 0.0f;
        light.Theta        = 0.4f;
        light.Phi          = 0.9f;
       return light;}
    d3dUtility.cpp
    #include "d3dUtility.h"
    
    IDirect3DDevice9* Device = 0; 
    
    const int Width  = 640;
    const int Height = 480;
    
    IDirect3DVertexBuffer9* vb = 0; 
    D3DXMATRIX WorldMatrix;
    
    struct Vertex //顶点结构:位置和顶点法线
    {
        Vertex(){}
    
        Vertex(float x, float y, float z,float nx,float ny,float nz)
        {
            _x = x;     _y = y;  _z = z;
            _nx=nx;_ny=ny;_nz=nz;
        }
    
        float _x, _y, _z;
        float _nx,_ny,_nz;
    
        static const DWORD FVF;
    };
    const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL;
    
    //
    // Framework Functions
    //
    bool Setup()
    {
        Device->SetRenderState(D3DRS_LIGHTING, true);  //设置光照可用
        Device->CreateVertexBuffer(               //创建顶点缓存
            12 * sizeof(Vertex), // size in bytes
            D3DUSAGE_WRITEONLY, // flags
            Vertex::FVF,        // vertex format
            D3DPOOL_MANAGED,    // managed memory pool
            &vb,          // return create vertex buffer
            0);                 // not used - set to 0
    
        Vertex* vertices;
        vb->Lock(0, 0, (void**)&vertices, 0);        //获取指向顶点缓存内容的指针
    
        vertices[0] = Vertex(-1.0f, 0.0f, -1.0f,0.0f,0.707f,-0.707f);
        vertices[1] = Vertex( 0.0f, 1.0f, 0.0f,0.0f,0.707f,-0.707f);
        vertices[2] = Vertex( 1.0f, 0.0f, -1.0f,0.0f,0.707f,-0.707f);
    
        vertices[3] = Vertex(-1.0f, 0.0f, 1.0f,-0.707f,0.707f,0.0f);
        vertices[4] = Vertex( 0.0f, 1.0f, 0.0f,-0.707f,0.707f,0.0f);
        vertices[5] = Vertex( -1.0f, 0.0f, -1.0f,-0.707f,0.707f,0.0f);
    
        vertices[6] = Vertex( 1.0f, 0.0f, -1.0f, 0.707f, 0.707f, 0.0f);
        vertices[7] = Vertex( 0.0f, 1.0f,  0.0f, 0.707f, 0.707f, 0.0f);
        vertices[8] = Vertex( 1.0f, 0.0f,  1.0f, 0.707f, 0.707f, 0.0f);
     
        vertices[9]  = Vertex( 1.0f, 0.0f,  1.0f, 0.0f, 0.707f, 0.707f);
        vertices[10] = Vertex( 0.0f, 1.0f,  0.0f, 0.0f, 0.707f, 0.707f);
        vertices[11] = Vertex(-1.0f, 0.0f,  1.0f, 0.0f, 0.707f, 0.707f);
    
        vb->Unlock();
    
        D3DMATERIAL9 Mtrl;  //定义材质,设置材质对各种光的反射率
        Mtrl.Ambient =d3d::RED;
        Mtrl.Diffuse=d3d::BLUE;
        Mtrl.Specular=d3d::CYAN;
        Mtrl.Emissive=d3d::BLACK;
        Mtrl.Power=5.0f;
    
        Device->SetMaterial(&Mtrl); 
    
        D3DLIGHT9 light;   //设置方向光,并对其值赋值
        memset(&light,0,sizeof(light));
        light.Type=D3DLIGHT_DIRECTIONAL;
        light.Diffuse=d3d::BLUE;
        light.Specular=d3d::BLUE;
        light.Ambient=d3d::BLUE;
        light.Direction=D3DXVECTOR3(1.0f,0.0f,0.0f);
        Device->SetLight(0,&light);
        Device->LightEnable(0,true);
        Device->SetRenderState(D3DRS_NORMALIZENORMALS,true); //使顶点法向量重新规范化
        Device->SetRenderState(D3DRS_SPECULARENABLE,true); //启用镜面光
    
        D3DXVECTOR3 pos(0.0f, 1.0f, -3.0f);
        D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
        D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
        D3DXMATRIX V;
        D3DXMatrixLookAtLH(&V, &pos, &target, &up); //取景变换矩阵,设置摄像机在时间坐标系中位置,界坐标系的被观察点,世界坐标系中表示“向上”方向的向量
        Device->SetTransform(D3DTS_VIEW, &V); //转换成观察者坐标系
    
        //
        // Set the projection matrix.
        //
    
        D3DXMATRIX proj;
        D3DXMatrixPerspectiveFovLH(
                &proj,
                D3DX_PI * 0.5f, // 90 - degree
                (float)Width / (float)Height,
                1.0f,
                1000.0f);
        Device->SetTransform(D3DTS_PROJECTION, &proj); //投影
        return true;
    }
    void Cleanup()
    {
        d3d::Release<IDirect3DVertexBuffer9*>(vb);
    }
    
    bool Display(float timeDelta)
    {
        if( Device )
        {
            D3DXMATRIX yRot;
    
            static float y = 0.0f;
    
            D3DXMatrixRotationY(&yRot, y);
            y += timeDelta;
    
            if( y >= 6.28f )
                y = 0.0f;
    
            Device->SetTransform(D3DTS_WORLD, &yRot);
    
            Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
            Device->BeginScene();
    
            Device->SetStreamSource(0, vb, 0, sizeof(Vertex));
            Device->SetFVF(Vertex::FVF);
            Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 4); //画出顶点缓存
            Device->SetFVF(Vertex::FVF); 
    
            Device->EndScene();
            Device->Present(0, 0, 0, 0);
        }
        return true;
    }
    
    
    //
    // WndProc
    //
    LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
        switch( msg )
        {
        case WM_DESTROY:
            ::PostQuitMessage(0);
            break;
            
        case WM_KEYDOWN:
            if( wParam == VK_ESCAPE )
                ::DestroyWindow(hwnd);
            break;
        }
        return ::DefWindowProc(hwnd, msg, wParam, lParam);
    }
    
    //
    // WinMain
    //
    int WINAPI WinMain(HINSTANCE hinstance,
                       HINSTANCE prevInstance, 
                       PSTR cmdLine,
                       int showCmd)
    {
        if(!d3d::InitD3D(hinstance,
            Width, Height, true, D3DDEVTYPE_HAL, &Device))
        {
            ::MessageBox(0, "InitD3D() - FAILED", 0, 0);
            return 0;
        }
            
        if(!Setup())
        {
            ::MessageBox(0, "Setup() - FAILED", 0, 0);
            return 0;
        }
    
        d3d::EnterMsgLoop( Display );
    
        Cleanup();
    
        Device->Release();
    
        return 0;
    }
    main.cpp
  • 相关阅读:
    k8s笔记0528-基于KUBERNETES构建企业容器云手动部署集群记录-4
    k8s笔记0528-基于KUBERNETES构建企业容器云手动部署集群记录-2
    Mysql索引最佳实践笔记0524
    Mysql 5.6 编译报错
    MySQL 源码安装规范
    CentOS 7.3安装Zabbix3.2
    Mysql for Mac 安装及环境配置
    win10下Resin安装--入门(1)
    React---入门(1)
    SVN简介与安装
  • 原文地址:https://www.cnblogs.com/hometown/p/3654838.html
Copyright © 2011-2022 走看看