zoukankan      html  css  js  c++  java
  • DirectX 龙书 混合 理解

    关于SetTextureStageState()这个函数,此文的理解有误,怕误导了别人,特别在这里声明一下,大家可以看最下面的那个连接,那个写的很好,我也是看了那个blog才知道我理解错了。
    下面的代码可以不看了。
     
    再次说说我的理解吧,一个物体是否透明,取决于它的材质,可以理解,在现实中,玻璃这种材质是透明的,而木头这种材质是不透明的,而材质中的diffuse,diffuse中的alpha就是用来调整这个材质的透明度。
    SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);这句话是说,现在要画的这个物体,它的alpha来自于颜色,比如这个地方的茶壶,并没有指定它使用什么纹理,而只是指定了它的材质是红色的,且材质的diffsue的alpha值是可调用的,所以它是透明的,而如果使用
    SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);的话,茶壶就不会有透明的效果,因为这句话是说,茶壶的透明度将来自纹理的alpha通道,因为之前设置的纹理是木板墙图片,这个图片没有alpha通道,默认值是0xffffffff,而在这个地方调整的alpha值是茶壶材质的alpha,与纹理的alpha不相干,所以,不管怎么调整这个alpha值,茶壶它都不会变的透明!
    View Code
    bool DXSetup()
    {
    /*******************************************************************************************
    * 背景墙
    ******************************************************************************************
    */

    // 创建顶点
    g_pd3dDevice->CreateVertexBuffer(
    6 * sizeof(DX7Vertex),
    D3DUSAGE_WRITEONLY,
    DX7Vertex::FVF,
    D3DPOOL_MANAGED,
    &BkGndQuad,
    0);

    DX7Vertex* v;
    BkGndQuad->Lock(0, 0, (void**)&v, 0);

    // quad built from two triangles, note texture coordinates:
    v[0] = DX7Vertex(-6.0f, -6.0f, 5.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
    v[1] = DX7Vertex(-6.0f, 6.0f, 5.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
    v[2] = DX7Vertex( 6.0f, 6.0f, 5.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);

    v[3] = DX7Vertex(-6.0f, -6.0f, 5.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
    v[4] = DX7Vertex( 6.0f, 6.0f, 5.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
    v[5] = DX7Vertex( 6.0f, -6.0f, 5.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f);
    BkGndQuad->Unlock();

    // 设置过滤器
    g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
    g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
    g_pd3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT); // 设置Mipmaps过滤器

    // 创建并使用纹理
    D3DXCreateTextureFromFile(g_pd3dDevice, "..\\Texture\\256.bmp", &BkGndTex);
    BkGndMtrl = WHITE_MTRL;

    /*******************************************************************************************
    * 物体
    ******************************************************************************************
    */

    // 茶壶材质
    ::ZeroMemory(&TeapotMtrl, sizeof(TeapotMtrl));
    TeapotMtrl.Ambient = RED;
    TeapotMtrl.Diffuse = RED;
    TeapotMtrl.Specular = RED;
    TeapotMtrl.Emissive = BLACK;
    TeapotMtrl.Power = 10.0f;

    // 茶壶物体
    D3DXCreateTeapot(g_pd3dDevice, &Teapot, NULL); // 画一个茶壶

    // 灯光默认为True
    //g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, false);

    // 设置摄影机
    D3DXVECTOR3 position(0.0f, 0.0f, -3.0f);
    D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
    D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
    D3DXMATRIX camera;
    D3DXMatrixLookAtLH(&camera,&position, &target, &up);
    g_pd3dDevice->SetTransform(D3DTS_VIEW, &camera);

    /*******************************************************************************************
    * 场景、灯光、摄影机&可视体设置
    ******************************************************************************************
    */

    // 设置灯光
    D3DLIGHT9 dir;
    ::ZeroMemory(&dir, sizeof(dir));
    dir.Type = D3DLIGHT_POINT;
    dir.Diffuse = WHITE;
    dir.Specular = WHITE * 0.3f;
    dir.Ambient = WHITE * 0.6f;
    dir.Position = D3DXVECTOR3(10.0f, 10.0f, -10.0f);
    dir.Range = 100;
    g_pd3dDevice->SetLight(0, &dir);
    g_pd3dDevice->LightEnable(0, true);

    g_pd3dDevice->SetRenderState(D3DRS_NORMALIZENORMALS, true);
    g_pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, true);

    // use alpha in material's diffuse component for alpha
    g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
    g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);

    // set blending factors so that alpha
    // component determines transparency
    g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
    g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);


    // 设置投影矩阵
    D3DXMATRIX proj;
    D3DXMatrixPerspectiveFovLH(
    &proj,
    D3DX_PI * 0.5f, // 90 - degree
    (float)Width / (float)Height,
    1.0f,
    1000.0f);
    g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &proj);

    return true;
    }

    void Render()
    {
    // keyboard message process -->>

    // increase/decrease alpha via keyboard input
    if (::GetAsyncKeyState('A') & 0x8000f)
    TeapotMtrl.Diffuse.a += 0.01f;
    if (::GetAsyncKeyState('S') & 0x8000f)
    TeapotMtrl.Diffuse.a -= 0.01f;

    // force alpha to[0,1] interval
    if (TeapotMtrl.Diffuse.a > 1.0f)
    TeapotMtrl.Diffuse.a = 1.0f;
    if (TeapotMtrl.Diffuse.a < 0.0f)
    TeapotMtrl.Diffuse.a = 0.0f;
    // keyboard message process <<--

    static float angle = 0.0f;
    angle += 0.02f;
    if (angle > 6.48)
    {
    angle = 0;
    }

    g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0x00,200,200,200), 1.0f, 0);
    g_pd3dDevice->BeginScene();
    // rendering of scene objects happens here

    // 画纹理背景墙
    D3DXMATRIX priCode;
    D3DXMatrixIdentity(&priCode);
    g_pd3dDevice->SetTransform(D3DTS_WORLD, &priCode);
    g_pd3dDevice->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1);
    g_pd3dDevice->SetStreamSource(0, BkGndQuad, 0, sizeof(DX7Vertex));
    g_pd3dDevice->SetMaterial(&BkGndMtrl); // 设置材质
    g_pd3dDevice->SetTexture(0, BkGndTex); // 设置纹理
    g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);

    // 画Mesh
    g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
    g_pd3dDevice->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL);
    g_pd3dDevice->SetMaterial(&TeapotMtrl); // 设置材质(并没有设置纹理,但是效果却是与纹理混合的效果,因为前面设置了纹理)
    Teapot->DrawSubset(0);
    g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);

    g_pd3dDevice->EndScene();
    g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
    }


    说说我对SetTextureStageState这个函数的理解,在这个例子中只出现了下面这两种用法
    g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
    g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);

    首先关于混合,用下面的函数
    g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
    g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
    指定了源混合因子与目标混合因子,画茶壶的时候调用
    g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
    将混合应用打开
    画茶壶的时候,用公式:OutputPixel=SourcePixel 叉乘 SourceBlendFactor + DestPixel 叉乘 DestBlendFactor来计算目标像素的值

    现在,在场景中只画出一个灰色的背景墙和一个茶壶(先不画木板纹理墙),灰色的背景墙的颜色值为D3DCOLOR_ARGB(0x00,200,200,200)
    使用SetRenderState()指定源与目标混合因子,但是,此时不使用SetTextureStageState()这个函数,OK,来画一个茶壶吧,像上面贴的代码中那样,使用A和S键可以控制这个茶壶的透明度。

    现在,在刚才的场景中增加画一个木板纹理墙,使用SetRenderState()指定源与目标混合因子,还是不使用SetTextureStageState()这个函数,这个时候你会发现,A与S键无法控制茶壶的透明度了!
    现在把SetTextureStageState()调用打开(Setup中调用,或者画茶壶之前调用都行)
    g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
    g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
    这个时候再运行,发现A与S键又可以控制茶壶的透明度了!

    OK,小结一下,SetTextureStageState(),这个函数的设置就是与那个纹理背景墙相关的!我和理解如下:
    先说说不使用SetTextureStageState()这个函数的情况吧。
    我的纹理背景墙的图片是没有alpha通道的,它只有24位颜色值,先画纹理背景墙,再画茶壶的时候,要用上面的那个公式来计算输出像素,可是DestPixel是24位的,没有alpha值,而公式中计算的要求是32位的,所以,计算失败!而最终使用的像素颜色值还是茶壶自身的像素颜色值。

    调用SetTextureStageState()这个函数,它的用意就是:
    指定DestPixel的alpha从哪里来的!
    g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
    这句话是说,在混合的时候,如果目标像素颜色值没有alpha值话,那么,目标像素的alpha值将从它的颜色值中计算出来!这样,画茶壶的时候,用公式来计算混合出的目标颜色时,目标像素就有了alpha值,而公式计算有效!就出现了茶壶在纹理背景墙上可以调整透明度!
    而g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);这句话,就是说,使用D3DTSS_ALPHAARG1指定的值,即,D3DTA_DIFFUSE.

    OK,那什么,不画背景纹理墙,只画一个灰色背景的时候,在不使用SetTextureStageState()的情况下就可以调用茶壶的透明度呢,因为灰度的背景墙是有alpha值的,这个地方我设置为0x00,其实,你设置成任何数值,茶壶都是在可以在灰色背景墙上调整透明度的!

    我觉得自己很罗嗦,OK,索性罗嗦到底吧。
    g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
    g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);

    这个函数就是用来指定,那个纹理背景墙中的alpha到底从哪里来的!

    关于这部分内容,这个文章写的很好!

    http://www.cppblog.com/kesalin/archive/2008/03/23/45183.html

  • 相关阅读:
    mysql中InnoDB存储引擎的行锁和表锁
    阿里云出海 埃森哲护航
    阿里云出海 埃森哲护航
    阿里云出海 埃森哲护航
    阿里云出海 埃森哲护航
    Python开发简单爬虫
    Python开发简单爬虫
    Python开发简单爬虫
    Python开发简单爬虫
    问大家一个问题,如何用1万元创业,每天利润达到500元?
  • 原文地址:https://www.cnblogs.com/emyueguang/p/2290266.html
Copyright © 2011-2022 走看看