tags:

views:

418

answers:

3

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 than 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?

A: 

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.

MarkR
so is what will happen basically, i will create a box around what my sphere would be, and move that box along my screen somehow? i just don't understand this.
4501
IF this is the case, how does this work with a background? There is another texture that is behind the sun object.
4501
Getting objects in front of/ behind each other is a separate discussion - normally done using either drawing order (painter's algorithm) or z buffers. You'd draw the box around the centre of the object, using world coordinates the same way you would any other 3d object in your world. As a sun would probably be behind everything else, you might use a different drawing order.
MarkR
+2  A: 

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

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.

shoosh
Correct me if I'm misunderstanding, which I most likely am, but you keep referencing quads. Quads are not spheres. How can I generate a spherical object if I'm rendering quads?
4501
You place a texture of a circle on the quad. If you've ever played Super Mario 64, for example, the trees were just quads, they always faced you [1]. With decent enough art, it can look as though it's not just a picture on a quad. (Which is why it is mostly used for distant objects. SM64 of course had no other choice, considering the hardware at the time.) [1] (at about 0:43) http://www.youtube.com/watch?v=grg91mBJZSE
GMan
Interesting, and as a texture would just be a .jpg image or something of the sorts, how would you deal with the outside of the circle? (+1 for solid example!)
4501
With respect to your comments on jpg and png, is there any way to give a jpg alpha qualities? I obviously can't just rename it as a .png, but I don't have any tools such as photoshop
4501
I have gotten this (kind of) working, but not at all. What I have right now is a sun that sits at the forefront of my screen and covers 80% of the screen no matter how the camera is pointing. It is not sitting in a specific place in my "world". Why is this? I will update with the code I used to create it.
4501
+1  A: 

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 :)!

UberJumper