开发者

How to use "billboards" to create a spherical object on the screen

I am tasked with making a sun/moon object flow across the screen throughout a time-span (as it would in a regular day). One of the options available to me is to use a "billboard", which is a quad that is always facing the camera.

I have yet to use many direct x libraries or techniques. This is my first graphics project. How does this make sense? And how can you use this to move a sun object across a screen?

Thanks :) This will be run on windows machines only and I only have the option for direct x (9).

I have gotten this half working. I have a sun image displaying, but it sits at the front of my screen overtop of 80% of my screen, no matter which way my camera is pointing. I'm looking down towards the ground? Still a huge sun there. Why is this? Here is the code I used to create it...

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();
}

Obviously, my position vector is hardcoded. Is this what I need to be changing? I have noticed in the documentation the possibility of D3DXSPRITE_BILLBOARD rather tha开发者_如何转开发n D3DXSPRITE_ALPHABLEND, will this work? Is it possible to use both?

As per the tutorial mentioned in an earlier post, D3DXSPRITE is a 2d object, and probably will not work for displaying within the 3d world? What is a smarter alternative?


The easiest way to do a screen aligned quad is by using Point Sprites with texture rewrite.
I never did that with DirectX but in OpenGL, enabling point sprites is a matter of 2 API calls that look like this.

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

With this mode enabled, You draw a single vertex and instead of a point, a screen aligned quad is renderd. The coordinate replace thing means that the rendered quad is processed with texture coordinates. This means that you can place any texture on the quad. Usually you'll want something with an alpha channel to blend into the background seamlessly.

There should be an equivalently easy way to do it in D3D. In addition, if you write a shader, it may allow you do do some additional stuff like discard some of the pixels of the texture.

This tutorial might help
Also, google.

--Edit
To transform a quad to any other shape, use the alpha channel of the texture. If the alpha is 0, the pixel is not visible. You can't add an alpha channel to a JPEG but you can do it to a PNG. Here's an example:

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

If you'll open this image in photoshop you'll see that the background is invisible.
Using alpha blending might cause some problems if you have other things going on in the scene so if that happens, you can write a simple fragment shader which discards the pixels with alpha==0.


Okay im not a direct x expert so i am going to assume a few things.

First i am assuming you have some sort of DrawQuad() function that takes the 4 corners and a texture inside your rendering class.

First we want to get the current viewport matrix

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

Lets just set some sort of arbitrary size

float size = 20.0f;

Now we need to calculate two vectors the up unit vector and the right unit vector.

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;

Now we need to define a Location for our object, i am just going with the origin.

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

Lets load the sun texture:

m_SunTexture = <insert magic texture load>

Now lets figure out the 4 corners.

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

Lets draw our quad. I am assuming this function exists otherwise you'll need to do some vertex drawing.

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);

Enjoy :)!


Yes, a billboard would typically be used for this. It's pretty straightforward to calculate the coordinates of the corners of the billboard and the texture parameters. The texture itself could be rendered using some other technique (in the application in system ram for instance).

It it simple enough to take the right and up vectors of the camera and add/sub those (scaled appropriately) from the centre point of the world-coordinates you want to render the object in.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜