以文本方式查看主题

-  计算机科学论坛  (http://bbs.xml.org.cn/index.asp)
--  『 C/C++编程思想 』  (http://bbs.xml.org.cn/list.asp?boardid=61)
----  高级纹理映射技术(2)  (http://bbs.xml.org.cn/dispbbs.asp?boardid=61&rootid=&id=70034)


--  作者:卷积内核
--  发布时间:12/3/2008 8:28:00 AM

--  高级纹理映射技术(2)
发光映射

发光映射(glowing mapping)与黑暗映射正好相反,它对于模拟那些具有独立于基础贴图的发光部分的物体很有用,比如模拟发光二极管、按钮、建筑物内的灯光、太空船上的灯光等。发光映射应仅影响基础贴图上的发光区域,而不影响其他部分。因此需要对发光效果做加法,而不是做乘法。

pd3dDevice->SetTexture(0, g_base_texture);
pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);

pd3dDevice->SetTexture(1, g_dark_texture);
pd3dDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 0);
pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_ADD);

运行效果:

按此在新窗口浏览图片

细节映射

如果要模拟一块粗糙的石灰泥墙壁,可以通过细节映射(detail mapping)来实现。实现过程是:将基础贴图(也就是第一张纹理)的颜色未经修改便作为第二个纹理操作阶段中的第二个参数,然后通过D3DTOP_ADDSIGNED将灰色的细节纹理与基础贴图相加。这个操作本质上是做了一个加法,只是使用了有符号的颜色值来代替平时使用的无符号值。在对两张纹理的像素颜色进行D3DTOP_ADDSIGNED操作时,它将参数的每个成分相加后再减去偏移量0.5,从而使有效值域变为-0.5 ~ 0.5。对一些比较旧的显卡,当其不能支持D3DTOP_ADDSIGNED操作时,可以使用D3DTOP_MODULATE2X代替D3DTOP_ADDSIGNED操作进行模拟。

在细节贴图中较亮的灰色纹理元素会使基础贴图变得更亮,而较暗的灰色纹理元素会使基础贴图变得更暗。由此可使物体呈现出粗糙的表面,从而使之看上去更为真实。示例代码如下:

pd3dDevice->SetTexture(0, g_base_texture);pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1,  D3DTA_TEXTURE);  pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP,  D3DTOP_SELECTARG1);
pd3dDevice->SetTexture(1, g_detail_texture);pd3dDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 0);pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG1,  D3DTA_TEXTURE);pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG2,  D3DTA_CURRENT);
hr = pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_ADDSIGNED);
if(FAILED(hr)) pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE2X);
按此在新窗口浏览图片
物体纹理
按此在新窗口浏览图片
细节纹理

运行效果:

按此在新窗口浏览图片


--  作者:卷积内核
--  发布时间:12/3/2008 8:29:00 AM

--  
主程序:


#include "dxstdafx.h"
#include "resource.h"

#pragma warning(disable : 4127 4995 4996)

#define release_com(p)    do { if(p) { (p)->Release(); (p) = NULL; } } while(0)

struct sCustomVertex
{
    float x, y, z;
    float u, v;
};

#define D3DFVF_CUSTOM_VERTEX    (D3DFVF_XYZ | D3DFVF_TEX1)

#define IDC_TOGGLE_FULLSCREEN        1
#define IDC_TOGGLE_REF                2
#define IDC_CHANGE_DEVICE            3

#define BLEND_DARK                    1
#define BLEND_DARK_ANIM                2
#define BLEND_TEXTURE_DIFFUSE        3
#define BLEND_DARK_DIFFUSE            4
#define BLEND_GLOW                    5
#define BLEND_DETAIL                6

#define BLEND_INFO_DARK                L"Dark Blend"
#define BLEND_INFO_DARK_ANIM        L"Dark Blend Animation"
#define BLEND_INFO_TEXTURE_DIFFUSE    L"Blend Texture and Vertex Diffuse Color"
#define BLEND_INFO_DARK_DIFFUSE        L"Blend Texture and Vertex Diffuse Color and Dark"
#define BLEND_INFO_GLOW                L"Glow Mapping"
#define BLEND_INFO_DETAIL            L"Detail Mapping"

const D3DXCOLOR FONT_COLOR(0.85f, 0.85f, 0.85f, 1.0f);

CDXUTDialogResourceManager    g_dlg_resource_manager;
CD3DSettingsDlg                g_settings_dlg;
CDXUTDialog                    g_button_dlg;

IDirect3DVertexBuffer9*        g_vertex_buffer;
IDirect3DTexture9*            g_base_texture;
IDirect3DTexture9*            g_dark_texture;
IDirect3DTexture9*            g_detail_texture;

ID3DXFont*        g_font;
ID3DXSprite*    g_text_sprite;
bool            g_show_help = true;
D3DLIGHT9        g_light;
D3DMATERIAL9    g_material;
int                g_blend_flag = BLEND_DARK;
WCHAR            g_blend_info[128] = BLEND_INFO_DARK;

//--------------------------------------------------------------------------------------
// Rejects any devices that aren't acceptable by returning false
//--------------------------------------------------------------------------------------
bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat,
                                  D3DFORMAT BackBufferFormat, bool bWindowed, void* pUserContext )
{
    // Typically want to skip backbuffer formats that don't support alpha blending

    IDirect3D9* pD3D = DXUTGetD3DObject();

    if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType, AdapterFormat,
                    D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
        return false;

    // check whether device support multi textures render
    if(pCaps->MaxTextureBlendStages <= 1)
        return false;

    return true;
}


//--------------------------------------------------------------------------------------
// Before a device is created, modify the device settings as needed.
//--------------------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps, void* pUserContext )
{
    // If video card does not support hardware vertex processing, then uses sofaware vertex processing.
    if((pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0)
        pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;

    static bool is_first_time = true;

    if(is_first_time)
    {
        is_first_time = false;

        // if using reference device, then pop a warning message box.
        if(pDeviceSettings->DeviceType == D3DDEVTYPE_REF)
            DXUTDisplaySwitchingToREFWarning();
    }

    return true;
}


//--------------------------------------------------------------------------------------
// Create any D3DPOOL_MANAGED resources here
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice,
                                 const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
                                 void* pUserContext )
{
    HRESULT    hr;

    V_RETURN(g_dlg_resource_manager.OnCreateDevice(pd3dDevice));
    V_RETURN(g_settings_dlg.OnCreateDevice(pd3dDevice));

    D3DXCreateFont(pd3dDevice, 18, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
                   DEFAULT_PITCH | FF_DONTCARE, L"Arial", &g_font);

    V_RETURN(D3DXCreateTextureFromFile(pd3dDevice, L"wall.bmp",    &g_base_texture));
    V_RETURN(D3DXCreateTextureFromFile(pd3dDevice, L"dark.bmp",    &g_dark_texture));
    V_RETURN(D3DXCreateTextureFromFile(pd3dDevice, L"detail.bmp",  &g_detail_texture));

    // create vertex buffer and fill data

    sCustomVertex vertices[] =     
    {
        { -3.0f, -3.0f,  0.0f,  0.0f, 1.0f},
        { -3.0f,  3.0f,  0.0f,  0.0f, 0.0f},
        {  3.0f, -3.0f,  0.0f,  1.0f, 1.0f},
        {  3.0f,  3.0f,  0.0f,  1.0f, 0.0f}
    };

    pd3dDevice->CreateVertexBuffer(sizeof(vertices), 0, D3DFVF_CUSTOM_VERTEX, D3DPOOL_MANAGED, &g_vertex_buffer, NULL);

    void* ptr;
    g_vertex_buffer->Lock(0, sizeof(vertices), (void**)&ptr, 0);
    memcpy(ptr, vertices, sizeof(vertices));
    g_vertex_buffer->Unlock();

    return S_OK;
}


//--------------------------------------------------------------------------------------
// Create any D3DPOOL_DEFAULT resources here
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice,
                                const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
                                void* pUserContext )
{
    HRESULT hr;

    V_RETURN(g_dlg_resource_manager.OnResetDevice());
    V_RETURN(g_settings_dlg.OnResetDevice());
    V_RETURN(g_font->OnResetDevice());
    V_RETURN(D3DXCreateSprite(pd3dDevice, &g_text_sprite));

    // set dialog position and size

    g_button_dlg.SetLocation(pBackBufferSurfaceDesc->Width - 170, 0);
    g_button_dlg.SetSize(170, 170);

    // setup view matrix

    D3DXMATRIX mat_view;
    D3DXVECTOR3 eye(0.0f, 0.0f, -10.0f);
    D3DXVECTOR3  at(0.0f, 0.0f,  0.0f);
    D3DXVECTOR3  up(0.0f, 1.0f,  0.0f);

    D3DXMatrixLookAtLH(&mat_view, &eye, &at, &up);
    pd3dDevice->SetTransform(D3DTS_VIEW, &mat_view);

    // set projection matrix
    D3DXMATRIX mat_proj;
    float aspect = (float)pBackBufferSurfaceDesc->Width / pBackBufferSurfaceDesc->Height;
    D3DXMatrixPerspectiveFovLH(&mat_proj, D3DX_PI/4, aspect, 1.0f, 100.0f);
    pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_proj);

    // setup light

    ZeroMemory(&g_light, sizeof(D3DLIGHT9));

    g_light.Type      = D3DLIGHT_DIRECTIONAL;
    g_light.Diffuse.r = 0.5f;
    g_light.Diffuse.g = 0.5f;
    g_light.Diffuse.b = 0.5f;

    D3DXVECTOR3 light_dir(0, 0, 10);
    D3DXVec3Normalize((D3DXVECTOR3*) &g_light.Direction, &light_dir);

    // setup material

    ZeroMemory(&g_material, sizeof(D3DMATERIAL9));

    g_material.Ambient.r = 1.0f;
    g_material.Ambient.g = 1.0f;
    g_material.Ambient.b = 1.0f;
    g_material.Ambient.a = 1.0f;
    g_material.Diffuse.r = 0.7f;
    g_material.Diffuse.g = 0.7f;
    g_material.Diffuse.b = 0.7f;
    g_material.Diffuse.a = 0.5f;

    // set texture sample method
    pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
    pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
    pd3dDevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
    pd3dDevice->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);

    return S_OK;
}

//--------------------------------------------------------------------------------------
// Release resources created in the OnResetDevice callback here
//--------------------------------------------------------------------------------------
void CALLBACK OnLostDevice( void* pUserContext )
{
    g_dlg_resource_manager.OnLostDevice();
    g_settings_dlg.OnLostDevice();
    g_font->OnLostDevice();

    release_com(g_text_sprite);
}


//--------------------------------------------------------------------------------------
// Release resources created in the OnCreateDevice callback here
//--------------------------------------------------------------------------------------
void CALLBACK OnDestroyDevice( void* pUserContext )
{
    g_dlg_resource_manager.OnDestroyDevice();
    g_settings_dlg.OnDestroyDevice();    

    release_com(g_font);
    release_com(g_vertex_buffer);
    release_com(g_base_texture);
    release_com(g_dark_texture);
    release_com(g_detail_texture);
}

//--------------------------------------------------------------------------------------
// Handle updates to the scene
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
{
    HRESULT hr = S_OK;

    if(g_blend_flag == BLEND_DARK)
    {
        pd3dDevice->SetTexture(0, g_base_texture);
        pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX,    0);
        pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1,        D3DTA_TEXTURE);
        pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP,            D3DTOP_SELECTARG1);

        pd3dDevice->SetTexture(1, g_dark_texture);
        pd3dDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX,    0);
        pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG1,        D3DTA_TEXTURE);
        pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG2,        D3DTA_CURRENT);
        pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP,            D3DTOP_MODULATE);

        wcscpy(g_blend_info, BLEND_INFO_DARK);
    }
    else if(g_blend_flag == BLEND_DARK_ANIM)
    {
        pd3dDevice->SetTexture(0, g_base_texture);
        pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX,    0);
        pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1,        D3DTA_TEXTURE);
        pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP,            D3DTOP_SELECTARG1);

        pd3dDevice->SetTexture(1, g_dark_texture);
        pd3dDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX,    0);
        pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG1,        D3DTA_TEXTURE);
        pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG2,        D3DTA_CURRENT);

        static double last_time = 0.0f;
        double interval = fTime - last_time;

        if(interval < 0.5f)
            pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
        else if(interval > 0.5f && interval < 1.0f)
            pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE2X);
        else if(interval > 1.0f && interval < 1.5f)
            pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE4X);
        else if(interval > 1.5f)
            last_time = fTime;

        wcscpy(g_blend_info, BLEND_INFO_DARK_ANIM);
    }
    else if(g_blend_flag == BLEND_TEXTURE_DIFFUSE)
    {
        pd3dDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
        pd3dDevice->SetRenderState(D3DRS_AMBIENT,  0x00808080);
        pd3dDevice->SetLight(0, &g_light);
        pd3dDevice->LightEnable(0, TRUE);
        pd3dDevice->SetMaterial(&g_material);

        pd3dDevice->SetTexture(0, g_base_texture);
        pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX,    0);
        pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1,        D3DTA_TEXTURE);
        pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2,        D3DTA_DIFFUSE);
        pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP,            D3DTOP_ADD);
        pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP,            D3DTOP_DISABLE);
        
        wcscpy(g_blend_info, BLEND_INFO_TEXTURE_DIFFUSE);
    }
    else if(g_blend_flag == BLEND_DARK_DIFFUSE)
    {
        pd3dDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
        pd3dDevice->SetRenderState(D3DRS_AMBIENT,  0x0080FFFF);
        pd3dDevice->SetLight(0, &g_light);
        pd3dDevice->LightEnable(0, TRUE);
        pd3dDevice->SetMaterial(&g_material);

        pd3dDevice->SetTexture(0, g_base_texture);
        pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX,    0);
        pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1,        D3DTA_TEXTURE);
        pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2,        D3DTA_DIFFUSE);
        pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP,            D3DTOP_MODULATE);
        
        pd3dDevice->SetTexture(1, g_dark_texture);
        pd3dDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX,    0);
        pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG1,        D3DTA_TEXTURE);
        pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG2,        D3DTA_CURRENT);
        pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP,            D3DTOP_MODULATE);

        wcscpy(g_blend_info, BLEND_INFO_DARK_DIFFUSE);
    }
    else if(g_blend_flag == BLEND_GLOW)
    {
        pd3dDevice->SetTexture(0, g_base_texture);
        pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX,    0);
        pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1,        D3DTA_TEXTURE);        
        pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP,            D3DTOP_SELECTARG1);

        pd3dDevice->SetTexture(1, g_dark_texture);
        pd3dDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX,    0);
        pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG1,        D3DTA_TEXTURE);
        pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG2,        D3DTA_CURRENT);
        pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP,            D3DTOP_ADD);

        wcscpy(g_blend_info, BLEND_INFO_GLOW);        
    }
    else if(g_blend_flag == BLEND_DETAIL)
    {
        pd3dDevice->SetTexture(0, g_base_texture);
        pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX,    0);
        pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1,        D3DTA_TEXTURE);        
        pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP,            D3DTOP_SELECTARG1);

        pd3dDevice->SetTexture(1, g_detail_texture);
        pd3dDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX,    0);
        pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG1,        D3DTA_TEXTURE);
        pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG2,        D3DTA_CURRENT);

        hr = pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_ADDSIGNED);

        if(FAILED(hr))
            pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE2X);

        wcscpy(g_blend_info, BLEND_INFO_DETAIL);
    }
}

//--------------------------------------------------------------------------------------
// Render the helper information
//--------------------------------------------------------------------------------------
void RenderText()
{
    CDXUTTextHelper text_helper(g_font, g_text_sprite, 20);
    
    text_helper.Begin();

    // show frame and device states
    text_helper.SetInsertionPos(5, 5);
    text_helper.SetForegroundColor(FONT_COLOR);
    text_helper.DrawTextLine( DXUTGetFrameStats(true) );
    text_helper.DrawTextLine( DXUTGetDeviceStats() );

    // show other simple information
    text_helper.SetForegroundColor( D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f) );
    text_helper.DrawTextLine(g_blend_info);

    // show helper information
    
    const D3DSURFACE_DESC* surface_desc = DXUTGetBackBufferSurfaceDesc();

    if(g_show_help)
    {
        text_helper.SetInsertionPos(10, surface_desc->Height - 18 * 10);
        text_helper.SetForegroundColor(FONT_COLOR);
        text_helper.DrawTextLine(L"Controls (F1 to hide):");
        
        text_helper.SetInsertionPos(40, surface_desc->Height - 18 * 9);
        text_helper.DrawTextLine(L"Quit: ESC");

        text_helper.DrawTextLine(L"");
        text_helper.DrawTextLine(L"1: Dark Blend");
        text_helper.DrawTextLine(L"2: Dark Blend Animation");
        text_helper.DrawTextLine(L"3: Blend Texture and Vertex Diffuse Color");
        text_helper.DrawTextLine(L"4: Blend Texture and Vertex Diffuse Color and Dark");
        text_helper.DrawTextLine(L"5: Glow Mapping");
        text_helper.DrawTextLine(L"6: Detail Mapping");        
    }
    else
    {
        text_helper.SetInsertionPos(10, surface_desc->Height - 15 * 4);
        text_helper.SetForegroundColor( D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f) );
        text_helper.DrawTextLine(L"Press F1 for help");
    }

    text_helper.End();
}

//--------------------------------------------------------------------------------------
// Render the scene
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
{
    HRESULT hr;

    if(g_settings_dlg.IsActive())
    {
        g_settings_dlg.OnRender(fElapsedTime);
        return;
    }

    // Clear the render target and the zbuffer
    V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 32, 64, 80), 1.0f, 0) );

    // Render the scene
    if( SUCCEEDED( pd3dDevice->BeginScene() ) )
    {
        pd3dDevice->SetStreamSource(0, g_vertex_buffer, 0, sizeof(sCustomVertex));
        pd3dDevice->SetFVF(D3DFVF_CUSTOM_VERTEX);
        pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);

        RenderText();

        V(g_button_dlg.OnRender(fElapsedTime));

        V( pd3dDevice->EndScene() );
    }
}


//--------------------------------------------------------------------------------------
// Handle messages to the application
//--------------------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
                          bool* pbNoFurtherProcessing, void* pUserContext )
{
    *pbNoFurtherProcessing = g_dlg_resource_manager.MsgProc(hWnd, uMsg, wParam, lParam);
    if(*pbNoFurtherProcessing)
        return 0;

    if(g_settings_dlg.IsActive())
    {
        g_settings_dlg.MsgProc(hWnd, uMsg, wParam, lParam);
        return 0;
    }

    *pbNoFurtherProcessing = g_button_dlg.MsgProc(hWnd, uMsg, wParam, lParam);
    if(*pbNoFurtherProcessing)
        return 0;

    return 0;
}


//--------------------------------------------------------------------------------------
// Handle keybaord event
//--------------------------------------------------------------------------------------
void CALLBACK OnKeyboardProc(UINT charater, bool is_key_down, bool is_alt_down, void* user_context)
{
    if(is_key_down)
    {
        switch(charater)
        {
        case VK_F1:
            g_show_help = !g_show_help;
            break;
        case 49:    // press key "1"
            g_blend_flag = BLEND_DARK;
            break;
        case 50:    // press key "2"
            g_blend_flag = BLEND_DARK_ANIM;
            break;
        case 51:    // press key "3"
            g_blend_flag = BLEND_TEXTURE_DIFFUSE;
            break;
        case 52:    // press key "4"
            g_blend_flag = BLEND_DARK_DIFFUSE;
            break;
        case 53:    // press key "5"
            g_blend_flag = BLEND_GLOW;
            break;
        case 54:    // press key "6"
            g_blend_flag = BLEND_DETAIL;
            break;
        }
    }
}

//--------------------------------------------------------------------------------------
// Handle events for controls
//--------------------------------------------------------------------------------------
void CALLBACK OnGUIEvent(UINT event, int control_id, CDXUTControl* control, void* user_context)
{
    switch(control_id)
    {
    case IDC_TOGGLE_FULLSCREEN:
        DXUTToggleFullScreen();
        break;

    case IDC_TOGGLE_REF:
        DXUTToggleREF();
        break;

    case IDC_CHANGE_DEVICE:
        g_settings_dlg.SetActive(true);
        break;
    }
}

//--------------------------------------------------------------------------------------
// Initialize dialogs
//--------------------------------------------------------------------------------------
void InitDialogs()
{
    g_settings_dlg.Init(&g_dlg_resource_manager);
    g_button_dlg.Init(&g_dlg_resource_manager);

    g_button_dlg.SetCallback(OnGUIEvent);

    int x = 35, y = 10, width = 125, height = 22;

    g_button_dlg.AddButton(IDC_TOGGLE_FULLSCREEN, L"Toggle full screen", x, y,         width, height);
    g_button_dlg.AddButton(IDC_TOGGLE_REF,          L"Toggle REF (F3)",     x, y += 24, width, height);
    g_button_dlg.AddButton(IDC_CHANGE_DEVICE,      L"Change device (F2)", x, y += 24, width, height, VK_F2);    
}

//--------------------------------------------------------------------------------------
// Initialize everything and go into a render loop
//--------------------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{
    // Enable run-time memory check for debug builds.
#if defined(DEBUG) | defined(_DEBUG)
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif

    // Set the callback functions
    DXUTSetCallbackDeviceCreated( OnCreateDevice );
    DXUTSetCallbackDeviceReset( OnResetDevice );
    DXUTSetCallbackDeviceLost( OnLostDevice );
    DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
    DXUTSetCallbackMsgProc( MsgProc );
    DXUTSetCallbackFrameRender( OnFrameRender );
    DXUTSetCallbackFrameMove( OnFrameMove );
    DXUTSetCallbackKeyboard(OnKeyboardProc);
   
    // TODO: Perform any application-level initialization here
    InitDialogs();

    // Initialize DXUT and create the desired Win32 window and Direct3D device for the application
    DXUTInit( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
    DXUTSetCursorSettings( true, true ); // Show the cursor and clip it when in full screen
    DXUTCreateWindow( L"Texture Color Blend" );
    DXUTCreateDevice( D3DADAPTER_DEFAULT, true, 640, 480, IsDeviceAcceptable, ModifyDeviceSettings );

    // Start the render loop
    DXUTMainLoop();

    // TODO: Perform any application-level cleanup here

    return DXUTGetExitCode();
}

[B][URL=http://www.cppblog.com/Files/changingnow/TextureColorBlend.rar]下载示例工程[/URL][/B]


--  作者:卷积内核
--  发布时间:12/3/2008 8:30:00 AM

--  
高级纹理映射技术(5)
Alpha混合操作

设置alpha操作的语句大致如下:

// i为纹理层序号
pd3dDevice->SetTextureStageState(i, D3DTSS_ALPHAARG1, arg1);
pd3dDevice->SetTextureStageState(i, D3DTSS_ALPHAARG2, arg2);
pd3dDevice->SetTextureStageState(i, D3DTSS_ALPHAOP, op);

参数op是属于枚举类型D3DTEXTUREOP的常量。和纹理颜色混合操作相同,纹理Alpha操作最多可接受三个颜色参数:D3DTSS_ALPHAARG0、D3DTSS_ALPHAARG1、D3DTSS_ALPHAARG2。

Direct3D在渲染一个场景时,它可以结合几种来源的颜色信息:顶点、当前材质、纹理贴图、先前写入渲染目标的颜色信息,然后将其中的一些颜色混合起来。同时也可以使用Alpha来指定Direct3D该以怎样的权重混合这些颜色,Alpha信息可以存储在顶点中、材质中、纹理贴图中。Alpha值为0表示完全透明,Alpha值为1表示不透明,其余0~1之间的值表示不同程度的透明。

如果要从一张纹理中获取Alpha值,应将D3DTA_TEXTURE作为Alpha参数。

如果要使用来自顶点中的Alpha值,应将D3DTA_DIFFUSE作为Alpha参数,并确保渲染状态D3DRS_DIFFUSEMATERIALSOURCE被设置为D3DMCS_COLOR1(这也是默认状态)。

如果要使用来自材质中的Alpha值,应将D3DTA_DIFFUSE作为Alpha参数,并确保渲染状态D3DRS_DIFFUSEMATERIALSOURCE被设置为D3DMCS_MATERIAL。

如果未用SetRenderState()设置D3DRS_DIFFUSEMATERIALSOURCE参数,则从默认来源(即顶点)获取漫反射颜色。

示例程序中将纹理颜色和Alpha混合的代码如下所示:

// set texture color and alpha blend method

pd3dDevice->SetTexture(0, g_texture);
pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);

pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);

pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

Alpha操作从纹理中获取Alpha值,因为用到了Alpha混合,所以在上面的代码中还需要启用Alpha混合并设置Alpha混合系数。

运行效果:

按此在新窗口浏览图片


--  作者:卷积内核
--  发布时间:12/3/2008 8:30:00 AM

--  
主程序:


#include "dxstdafx.h"
#include "resource.h"

#pragma warning(disable : 4127 4995 4996)

#define release_com(p)    do { if(p) { (p)->Release(); (p) = NULL; } } while(0)

#define IDC_TOGGLE_FULLSCREEN        1
#define IDC_TOGGLE_REF                2
#define IDC_CHANGE_DEVICE            3

struct sCustomVertex
{
    float x, y, z;
    float u, v;
};

#define D3DFVF_CUSTOM_VERTEX    (D3DFVF_XYZ | D3DFVF_TEX1)

const D3DXCOLOR FONT_COLOR(0.85f, 0.85f, 0.85f, 1.0f);

CDXUTDialogResourceManager    g_dlg_resource_manager;
CD3DSettingsDlg                g_settings_dlg;
CDXUTDialog                    g_button_dlg;

IDirect3DVertexBuffer9*        g_vertex_buffer;
IDirect3DTexture9*            g_texture;

ID3DXFont*        g_font;
ID3DXSprite*    g_text_sprite;
bool            g_show_help = true;

//--------------------------------------------------------------------------------------
// Rejects any devices that aren't acceptable by returning false
//--------------------------------------------------------------------------------------
bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat,
                                  D3DFORMAT BackBufferFormat, bool bWindowed, void* pUserContext )
{
    // Typically want to skip backbuffer formats that don't support alpha blending

    IDirect3D9* pD3D = DXUTGetD3DObject();

    if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType, AdapterFormat,
                    D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
        return false;

    return true;
}


//--------------------------------------------------------------------------------------
// Before a device is created, modify the device settings as needed.
//--------------------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps, void* pUserContext )
{
    // If video card does not support hardware vertex processing, then uses sofaware vertex processing.
    if((pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0)
        pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;

    static bool is_first_time = true;

    if(is_first_time)
    {
        is_first_time = false;

        // if using reference device, then pop a warning message box.
        if(pDeviceSettings->DeviceType == D3DDEVTYPE_REF)
            DXUTDisplaySwitchingToREFWarning();
    }

    return true;
}


//--------------------------------------------------------------------------------------
// Create any D3DPOOL_MANAGED resources here
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice,
                                 const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
                                 void* pUserContext )
{
    HRESULT    hr;

    V_RETURN(g_dlg_resource_manager.OnCreateDevice(pd3dDevice));
    V_RETURN(g_settings_dlg.OnCreateDevice(pd3dDevice));

    D3DXCreateFont(pd3dDevice, 18, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
                   DEFAULT_PITCH | FF_DONTCARE, L"Arial", &g_font);

    V_RETURN(D3DXCreateTextureFromFile(pd3dDevice, L"tree.tga",    &g_texture));
    
    // create vertex buffer and fill data

    sCustomVertex vertices[] =     
    {
        { -3.0f, -3.0f,  0.0f,  0.0f, 1.0f},
        { -3.0f,  3.0f,  0.0f,  0.0f, 0.0f},
        {  3.0f, -3.0f,  0.0f,  1.0f, 1.0f},
        {  3.0f,  3.0f,  0.0f,  1.0f, 0.0f}
    };

    pd3dDevice->CreateVertexBuffer(sizeof(vertices), 0, D3DFVF_CUSTOM_VERTEX, D3DPOOL_MANAGED, &g_vertex_buffer, NULL);

    void* ptr;
    g_vertex_buffer->Lock(0, sizeof(vertices), (void**)&ptr, 0);
    memcpy(ptr, vertices, sizeof(vertices));
    g_vertex_buffer->Unlock();

    return S_OK;
}


//--------------------------------------------------------------------------------------
// Create any D3DPOOL_DEFAULT resources here
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice,
                                const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
                                void* pUserContext )
{
    HRESULT hr;

    V_RETURN(g_dlg_resource_manager.OnResetDevice());
    V_RETURN(g_settings_dlg.OnResetDevice());
    V_RETURN(g_font->OnResetDevice());
    V_RETURN(D3DXCreateSprite(pd3dDevice, &g_text_sprite));

    // set dialog position and size

    g_button_dlg.SetLocation(pBackBufferSurfaceDesc->Width - 170, 0);
    g_button_dlg.SetSize(170, 170);

    // setup world matrix
    D3DXMATRIX mat_world;
    D3DXMatrixIdentity(&mat_world);
    pd3dDevice->SetTransform(D3DTS_WORLD, &mat_world);

    // setup view matrix

    D3DXMATRIX mat_view;
    D3DXVECTOR3 eye(0.0f, 0.0f, -10.0f);
    D3DXVECTOR3  at(0.0f, 0.0f,  0.0f);
    D3DXVECTOR3  up(0.0f, 1.0f,  0.0f);

    D3DXMatrixLookAtLH(&mat_view, &eye, &at, &up);
    pd3dDevice->SetTransform(D3DTS_VIEW, &mat_view);

    // set projection matrix
    D3DXMATRIX mat_proj;
    float aspect = (float)pBackBufferSurfaceDesc->Width / pBackBufferSurfaceDesc->Height;
    D3DXMatrixPerspectiveFovLH(&mat_proj, D3DX_PI/4, aspect, 1.0f, 100.0f);
    pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_proj);

    // setup material

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

    material.Ambient.r = 1.0f;
    material.Ambient.g = 1.0f;
    material.Ambient.b = 1.0f;
    material.Ambient.a = 1.0f;

    pd3dDevice->SetMaterial(&material);

    pd3dDevice->SetRenderState(D3DRS_AMBIENT, 0xFF00FF00);

    // set texture color and alpha blend method

    pd3dDevice->SetTexture(0, g_texture);
    pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX,    0);
    pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1,        D3DTA_TEXTURE);
    pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2,        D3DTA_DIFFUSE);
    pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP,            D3DTOP_MODULATE);

    pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1,        D3DTA_TEXTURE);
    pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP,            D3DTOP_SELECTARG1);

    pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,    TRUE);
    pd3dDevice->SetRenderState(D3DRS_SRCBLEND,            D3DBLEND_SRCALPHA);
    pd3dDevice->SetRenderState(D3DRS_DESTBLEND,            D3DBLEND_INVSRCALPHA);

    return S_OK;
}

//--------------------------------------------------------------------------------------
// Release resources created in the OnResetDevice callback here
//--------------------------------------------------------------------------------------
void CALLBACK OnLostDevice( void* pUserContext )
{
    g_dlg_resource_manager.OnLostDevice();
    g_settings_dlg.OnLostDevice();
    g_font->OnLostDevice();

    release_com(g_text_sprite);
}


//--------------------------------------------------------------------------------------
// Release resources created in the OnCreateDevice callback here
//--------------------------------------------------------------------------------------
void CALLBACK OnDestroyDevice( void* pUserContext )
{
    g_dlg_resource_manager.OnDestroyDevice();
    g_settings_dlg.OnDestroyDevice();    

    release_com(g_font);
    release_com(g_vertex_buffer);
    release_com(g_texture);
}

//--------------------------------------------------------------------------------------
// Handle updates to the scene
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
{
}

//--------------------------------------------------------------------------------------
// Render the helper information
//--------------------------------------------------------------------------------------
void RenderText()
{
    CDXUTTextHelper text_helper(g_font, g_text_sprite, 20);
    
    text_helper.Begin();

    // show frame and device states
    text_helper.SetInsertionPos(5, 5);
    text_helper.SetForegroundColor(FONT_COLOR);
    text_helper.DrawTextLine( DXUTGetFrameStats(true) );
    text_helper.DrawTextLine( DXUTGetDeviceStats() );

    // show other simple information
    text_helper.SetForegroundColor( D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f) );
    text_helper.DrawTextLine(L"Texture Alpha Blend");

    // show helper information
    
    const D3DSURFACE_DESC* surface_desc = DXUTGetBackBufferSurfaceDesc();

    if(g_show_help)
    {
        text_helper.SetInsertionPos(10, surface_desc->Height - 18 * 5);
        text_helper.SetForegroundColor(FONT_COLOR);
        text_helper.DrawTextLine(L"Controls (F1 to hide):");
        
        text_helper.SetInsertionPos(40, surface_desc->Height - 18 * 4);
        text_helper.DrawTextLine(L"Quit: ESC");
    }
    else
    {
        text_helper.SetInsertionPos(10, surface_desc->Height - 15 * 4);
        text_helper.SetForegroundColor( D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f) );
        text_helper.DrawTextLine(L"Press F1 for help");
    }

    text_helper.End();
}

//--------------------------------------------------------------------------------------
// Render the scene
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
{
    HRESULT hr;

    if(g_settings_dlg.IsActive())
    {
        g_settings_dlg.OnRender(fElapsedTime);
        return;
    }

    // Clear the render target and the zbuffer
    V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 32, 64, 80), 1.0f, 0) );

    // Render the scene
    if( SUCCEEDED( pd3dDevice->BeginScene() ) )
    {
        pd3dDevice->SetStreamSource(0, g_vertex_buffer, 0, sizeof(sCustomVertex));
        pd3dDevice->SetFVF(D3DFVF_CUSTOM_VERTEX);
        pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);

        RenderText();

        V(g_button_dlg.OnRender(fElapsedTime));

        V( pd3dDevice->EndScene() );
    }
}


//--------------------------------------------------------------------------------------
// Handle messages to the application
//--------------------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
                          bool* pbNoFurtherProcessing, void* pUserContext )
{
    *pbNoFurtherProcessing = g_dlg_resource_manager.MsgProc(hWnd, uMsg, wParam, lParam);
    if(*pbNoFurtherProcessing)
        return 0;

    if(g_settings_dlg.IsActive())
    {
        g_settings_dlg.MsgProc(hWnd, uMsg, wParam, lParam);
        return 0;
    }

    *pbNoFurtherProcessing = g_button_dlg.MsgProc(hWnd, uMsg, wParam, lParam);
    if(*pbNoFurtherProcessing)
        return 0;

    return 0;
}


//--------------------------------------------------------------------------------------
// Handle keybaord event
//--------------------------------------------------------------------------------------
void CALLBACK OnKeyboardProc(UINT charater, bool is_key_down, bool is_alt_down, void* user_context)
{
    if(is_key_down)
    {
        switch(charater)
        {
        case VK_F1:
            g_show_help = !g_show_help;
            break;
        }
    }
}

//--------------------------------------------------------------------------------------
// Handle events for controls
//--------------------------------------------------------------------------------------
void CALLBACK OnGUIEvent(UINT event, int control_id, CDXUTControl* control, void* user_context)
{
    switch(control_id)
    {
    case IDC_TOGGLE_FULLSCREEN:
        DXUTToggleFullScreen();
        break;

    case IDC_TOGGLE_REF:
        DXUTToggleREF();
        break;

    case IDC_CHANGE_DEVICE:
        g_settings_dlg.SetActive(true);
        break;
    }
}

//--------------------------------------------------------------------------------------
// Initialize dialogs
//--------------------------------------------------------------------------------------
void InitDialogs()
{
    g_settings_dlg.Init(&g_dlg_resource_manager);
    g_button_dlg.Init(&g_dlg_resource_manager);

    g_button_dlg.SetCallback(OnGUIEvent);

    int x = 35, y = 10, width = 125, height = 22;

    g_button_dlg.AddButton(IDC_TOGGLE_FULLSCREEN, L"Toggle full screen", x, y,         width, height);
    g_button_dlg.AddButton(IDC_TOGGLE_REF,          L"Toggle REF (F3)",     x, y += 24, width, height);
    g_button_dlg.AddButton(IDC_CHANGE_DEVICE,      L"Change device (F2)", x, y += 24, width, height, VK_F2);    
}

//--------------------------------------------------------------------------------------
// Initialize everything and go into a render loop
//--------------------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{
    // Enable run-time memory check for debug builds.
#if defined(DEBUG) | defined(_DEBUG)
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif

    // Set the callback functions
    DXUTSetCallbackDeviceCreated( OnCreateDevice );
    DXUTSetCallbackDeviceReset( OnResetDevice );
    DXUTSetCallbackDeviceLost( OnLostDevice );
    DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
    DXUTSetCallbackMsgProc( MsgProc );
    DXUTSetCallbackFrameRender( OnFrameRender );
    DXUTSetCallbackFrameMove( OnFrameMove );
    DXUTSetCallbackKeyboard(OnKeyboardProc);
   
    // TODO: Perform any application-level initialization here
    InitDialogs();

    // Initialize DXUT and create the desired Win32 window and Direct3D device for the application
    DXUTInit( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
    DXUTSetCursorSettings( true, true ); // Show the cursor and clip it when in full screen
    DXUTCreateWindow( L"Texture Color And Alpha Blend" );
    DXUTCreateDevice( D3DADAPTER_DEFAULT, true, 640, 480, IsDeviceAcceptable, ModifyDeviceSettings );

    // Start the render loop
    DXUTMainLoop();

    // TODO: Perform any application-level cleanup here

    return DXUTGetExitCode();
}


[B][URL=http://www.cppblog.com/Files/changingnow/TextureAlphaBlend.rar]下载示例工程[/URL][/B]


W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
171.875ms