代码之家  ›  专栏  ›  技术社区  ›  user189327

如何使用“公告牌”在屏幕上创建球形对象

  •  1
  • user189327  · 技术社区  · 15 年前

    我的任务是让一个日月物体在一段时间内(就像平常一样)在屏幕上流动。我可用的选项之一是使用 广告牌 “,这是一个始终面向相机的四边形。

    我还没有使用许多直接的X库或技术。这是我的第一个图形项目。这有什么意义?你怎么能用这个在屏幕上移动太阳物体呢?

    谢谢:)这只能在Windows计算机上运行,我只能选择Direct X。( )

    我已经完成了一半的工作。我有一个太阳图像显示,但它位于我80%的屏幕上方,不管我的相机指向哪个方向。我朝地面看?那里还有一个巨大的太阳。为什么会这样?这是我用来创建它的代码…

    void Sun::DrawSun()
    {
        std::wstring hardcoded = L"..\\Data\\sun.png";
        m_SunTexture = MyTextureManager::GetInstance()->GetTextureData(hardcoded.c_str()).m_Texture;
    
    
    LPD3DXSPRITE sprite = NULL;
    
    if (SUCCEEDED(D3DXCreateSprite(MyRenderer::GetInstance()->GetDevice(), &sprite)))
    {
        //created!
    }
    
    sprite->Begin(D3DXSPRITE_ALPHABLEND);
    
    D3DXVECTOR3 pos;
    
    pos.x = 40.0f;
    pos.y = 20.0f;
    pos.z = 20.0f;
    
    HRESULT someHr;
    someHr = sprite->Draw(m_SunTexture, NULL, NULL, &pos, 0xFFFFFFFF);
    sprite->End();
    }
    

    显然,我的位置向量是硬编码的。这就是我需要改变的吗?我在文档中注意到了d3dxsprite_广告牌而不是d3dxsprite_alphablend的可能性,这会起作用吗?两者都可以用吗?

    根据前面一篇文章中提到的教程,d3dxsprite是一个二维对象,可能不适用于在三维世界中显示?什么是更明智的选择?

    3 回复  |  直到 15 年前
        1
  •  0
  •   UberJumper    15 年前

    好吧,我不是一个直接的X专家,所以我要假设一些事情。

    首先,我假设您有一个drawQuad()函数,它在您的渲染类中获取4个角和一个纹理。

    首先我们要得到当前的视区矩阵

    D3DMATRIX mat;
    hr = m_Renderer->GetRenderDevice()->GetTransform(D3DTS_VIEW,&mat);
    

    让我们设置一些任意大小的

    float size = 20.0f;
    

    现在我们需要计算两个向量,上单位向量和右单位向量。

    D3DXVECTOR3 rightVect;
    D3DXVECTOR3 viewMatrixA(mat._11,mat._21,mat._31);
    D3DXVECTOR3 viewMatrixB(mat._12,mat._22,mat._32);
    D3DXVec3Normalize(&rightVect, &viewMatrixA);
    rightVect = rightVect * size * 0.5f;
    D3DXVECTOR3 upVect;
    D3DXVec3Normalize(&upVect, &viewMatrixB);
    upVect = upVect * size * 0.5f;
    

    现在我们需要为我们的对象定义一个位置,我只想使用原点。

    D3DXVECTOR3 loc(0.0f, 0.0f, 0.0f);
    

    让我们加载太阳纹理:

    m_SunTexture = <insert magic texture load>
    

    现在让我们找出4个角。

    D3DXVECTOR3 upperLeft = loc - rightVect;
    D3DXVECTOR3 upperRight = loc + upVect;
    D3DXVECTOR3 lowerRight = loc-upVect;
    D3DXVECTOR3 lowerLeft= loc + rightVect;
    

    让我们画四方形。我假设这个函数存在,否则您需要这样做 一些顶点绘制。

    m_Renderer->DrawQuad(
        upperLeft.x, upperLeft.y, upperLeft.z,
        upperRight.x, upperRight.y, upperRight.z,
        lowerRight.x, lowerRight.y, lowerRight.z,
        lowerLeft.x, lowerLeft.y, lowerLeft.z, m_SunTexture);
    

    享受:)!

        2
  •  1
  •   shoosh    15 年前

    最简单的方法做屏幕对齐四元是使用点精灵与纹理重写。
    我从来没有用过DirectX,但是在OpenGL中,启用点sprites是两个类似这样的API调用的问题。

    glEnable(GL_POINT_SPRITE);
    glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, true);
    

    启用此模式后,绘制一个顶点,而不是一个点,屏幕对齐的四元体是renderd。坐标替换意味着渲染的四元体将使用纹理坐标进行处理。这意味着您可以在四边形上放置任何纹理。通常情况下,你会希望有阿尔法通道的东西无缝地融入到背景中。

    在d3d中应该有一个同样简单的方法来完成它。另外,如果你编写一个明暗器,它可能允许你做一些额外的事情,比如丢弃一些纹理的像素。

    This tutorial might help
    还有,谷歌。

    —— 编辑
    要将四边形转换为任何其他形状,请使用纹理的alpha通道。如果alpha为0,则像素不可见。不能将alpha通道添加到jpeg,但可以将其添加到png。下面是一个例子:

    sun with alpha channel http://www.shiny.co.il/shooshx/sun.png

    如果你在photoshop中打开这张图片,你会看到背景是不可见的。
    如果场景中发生了其他事情,使用alpha混合可能会导致一些问题,因此如果发生这种情况,可以编写一个简单的片段着色程序,它将丢弃alpha==0的像素。

        3
  •  0
  •   MarkR    15 年前

    是的,广告牌通常是用来做这个的。计算广告牌角落的坐标和纹理参数非常简单。纹理本身可以使用其他技术(例如,在系统RAM中的应用程序中)进行渲染。

    它非常简单,可以从要渲染对象的世界坐标的中心点获取相机的右上方向向量,并添加/细分这些向量(适当缩放)。