I am making little game in C++ with Directx 9. I read some tutorial and i can draw my sprite object and move it etc.But i want to rotate it.I try :
void D3DGraphics::DrawSprite(LPDIRECT3DTEXTURE9 &texture,ID3DXSprite* pSprite, D3DXVECTOR3* pos, D3DXVECTOR3* dim ){
pDevice->Clear( 0,NULL,D3DCLEAR_STENCIL,D3DCOLOR_XRGB(0,0,0),0.0f,0 );
D3DXMATRIX matrix;
D3DXMatrixRotationX(&matrix, 0.05f);
pSprite->Begin(D3DXSPRITE_ALPHABLEND);
hresult= pSprite->SetTransform(&matrix);
hresult= pSprite->Draw(texture, NULL, dim, pos, 0xFFFFFFFF);
pSprite->End();
}
When i remove settransform part, it works perfectly.I checked hresult s they returned S_OK.Any idea?
I think the main problem is, that you try to use 3D-Transformations for a 2D usecase. Try to work with D3DXMatrixTransformation2D (doc) for the matrix. But there are additional problems. I presume the name dim stands for dimension, but this parameter of Draw()(doc) sets the center of the sprite, not the size. Finally, a fullscreen-clear of your stencilbuffer without any use of it is unnecessary expensive, but I don't know your other code.
Hope that helps :)
I think it does not make sense to rotate the sprite, since a sprite is normally come with a 2d texture and used for bill-boarding, if you rotate it around X-axis, it's just like a picture flips around the X-axis, you can not get the effect you want, I have try to rotate it around the Z-axis, this works well since the texture was usually on the XOY plane.
if you want to make a spinning ball, why not use a 3D mesh? sprite is not a good choice for this request.
Related
My goal is to create an intuitive 3D manipulator to handle rotations of meshes displayed in my 3D editor, made with Qt / QML.
To do that, when the user clicks on an entity, 3 tori are spawned around the mesh, representing the euler angles the user can act on. If the user then clicks on one torus, I want him to be able to rotate the mesh by dragging the mouse. The natural way users seem to do that is by dragging the mouse around the torus in the direction they want the mesh to rotate.
I therefore need a way to know how the user is rotating his mouse. I thought of a way: when the user clicks on the torus, I retrieve the position of the center of the torus. Then, I translate this world position to its screen position. Then, I monitor the angle between the cursor of the mouse and the center of the torus. The evolution of this angle should tell me everything I need: if the angle increases clockwise, the mesh should rotate clockwise and vice versa. This solution should yield a result good enough for my application, since it won't depend on the angle of the camera, or only very minimally.
However, I can't find a way to translate a world position to its screen position with Qt. I found the function QVector3D::project(const QMatrix4x4 &modelView, const QMatrix4x4 &projection, const QRect &viewport), but its documentation is very scarce and I couldn't find anyone using it... I might have found what to feed in for the projection argument (the projectionMatrix property from QCamera, here https://doc.qt.io/qt-5/qml-qt3d-render-camera.html), but that's it. What is the modelView ? And viewport ? Is it simply QRect(0, 0, 1920, 1080) ?
If anyone have any kind of lead, it would be amazing, I can't find anything anywhere and I'm kind of losing hope now. Or maybe another, simpler, solution to my problem ? Please note that the user can also freely move the camera around the mesh, which adds in complexity.
Thanks a lot for your time, and have a nice day !
Yes, you should be able to translate from world position to screen position using the mentioned function. You are correct about the projection argument. As for the modelView argument, you should use viewMatrix property from QCamera, which is missing from the official documentation, but it works for me. The viewport parameter represents the dimensions of the part of the screen, you are projecting on. You could use QRect(0, 0, 1920, 1080) if you use full screen Full HD projection, otherwise use something like QRect(QPoint(0, 0), view->size()), where view is the wigdet or window with your 3D image. Be careful, that the resulting screen position will have y = 0 being down and positive values being above, which the opposite to usual screen coordinates.
I have a simple game that I'm trying to do for learning purposes, but Matrices are a bit hard, especially in DirectX.
I currently have a tilesystem that renders tiles at the screen and a character position at the center (on startup)
When the player move to the left, the ground should move to the right so he's always at the center of the screen. I use a Sprite to transform the Tiles and the player, but having trouble because the ground is moving and the player stands still on the ground still positioned at the center.
This is a topdown 2D game so I only need to transform Position (and perhaps rotation)
My Camera class has this method:
D3DXMatrixTransformation2D(&View, NULL, 0, &Scale, &Center, D3DXToRadian(Rotation), &Position);
I've also tried (for the Camera):
D3DXMatrixTranslation(&View, Position.x, Position.y, 0);
then when I render the ground sprite I set it to transform to the camera, but the Player has it's own Matrix that I use when he's moving.
Exactly like the one above but with his position, rotation and such...
What am I missing and what do I need?
I only have a tilesystem that fits the width/height of the screen so I should see when he's moving but he's standing still at the center and the ground and the player is moving.
Do I need to invert the matrix so that the ground moves in the opposite direction?
Only the player moves here and the world transforms around him.
I must say that being the number #1 language in game programming there's very little guides that explains simple things as "TopDown Camera in 2D"...
For your problem you should read something about the different spaces: object space, world space and camera space. (Mostly referred in relation to a 3D-space, but I'll try to explain it for 2D)
Object space
Each object should be modelled or in your case drawn to be in objectspace. This means that for each object their is a matrix, which determine the center, e.g. of your player.
World space
This is your game world. It describes the position and orientation of each object in your scene.
Camera space
This describes the current view at your game world. The camera is assumed to be fix at the middle of your screen and you move the whole world to fit to the current viewpoint (e.g. translating with the negative position).
For your case it means, that you need a matrix for each object, which describes the offset that the image is correctly centered at the position (objectspace). Then you need to transform the object into the world space. Therefore you need a matrix with the position and orientation of the object and multiply it with the objectmatrix. Finally you have to take the viewpoint into account and multiply the cameramatrix, so that the object are transformed from worldspace to viewspace. The resulting matrix is the one you use for rendering.
Hope that helps :)
With the help of people at the chat I realized what the problem was with my system, altough I tried similiar things but probably in the wrong way / order.
For a simple 2D TopDown camera with just positioning:
Camera2D Translation:
D3DXMatrixTranslation(&CameraView, Position.x, Position.y, 0);
For each object in the camera's view:
D3DXMATRIX ObjectWorld;
D3DXMatrixTransformation2D(&ObjectWorld, NULL, 0, NULL, NULL, 0, &Position);
D3DXMATRIX Translation;
D3DXMatrixMultiply(&Translation, ObjectWorld, CameraView);
and then to render the sprite:
sprite->SetTransform(&Translation);
sprite->Draw(Texture, NULL, NULL, NULL, Color);
altough this method requires me to move the camera in the opposite direction that the player is moving, so if player is moving +100, the camera should move -100 to still be positioned at the same location relative to the player.
I have a sprite, a square, just for orthogonal projection. Now I want to project it in a very basic, simple isometric way. (I know this might not be pretty, but I just want to figure this out)
Given my square, I rotate it 45 degrees. Now if I understand correctly, I should still divide my height by 2. This has been impossible for me in SFML. There is a scale function but if I scale with a factor 0.5 in the y-axis direction, my cube just gets stretched, instead of a diamond shape. It looks as though SFML transforms the sprite according to it's own relative axes (that were rotated before..).
Since you cannot access the height of a sprite, I was wondering if this was even possible?
Can I convert a square sprite to a diamond shape in SFML?
Using a sf::RenderTexture is an option (see other answer). Another option is to fiddle with the sf::View. Double the view's height, and adjust coordinates. It would go something like this:
my_sprite.setRotation(45.f);
//adjust the position for new screen coordinates (once)
my_sprite.setPosition(my_sprite.getPosition().x, my_sprite.getPosition().y * 2);
//...
//when drawing:
sf::View v = my_render_window.getDefaultView();
v.setSize(v.getSize().x, v.getSize().y * 2);
v.setCenter(v.getSize() *.5f);
my_render_window.setView(v);
my_render_window.draw(my_sprite);
my_render_window.setView(my_render_window.getDefaultView());
Rotate your sprite as you are doing now. Render it to an sf::RenderTexture. Use the member function getTexture, and make a new sprite from it, or reuse the old sprite. Scale the sprite along the y-axis. Draw it to the render window.
Some math on your part may be required in order to set the RenderTexture to the right size and to draw the original sprite in the correct location on it.
original_sprite.setRotation(45);
sf::RenderTexture rt;
rt.create(FigureOutWidth(),FigureOutHeight());
original_sprite.setPosition(MoreMathHere());
rt.draw(original_sprite);
sf::Sprite new_sprite(rt.getTexture());
new_sprite.setScale(1.0,0.5);
It should go without saying, but do this once in initialization, not every frame.
I am trying to make a 2D platform game using OpenGl and glut with C++. You can move your player around with the left and right arrow keys and jump with space. I have all the platforms loaded into the game through a text file and printed to the screen. This all works really good. The problem I am having is with the camera. When the right arrow key is pressed I have the players x position to increase. The problem is that when this happens I can not get the actual camera to move as well. This makes me think that instead of moving the player, I should use glTranslatef to translate all the platforms to the left. This seems a bit odd to me and I am just wondering if this is how it should be done. So I guess the final question is, should I translate the entire scene or move the player?
Move the camera to follow the player by glTranslateing in the opposite direction as the player.
You should think of the camera like an in game object similar to the player and other movable items and the level as a static object with a fixed position. This makes placing in-game items and other things much easier.
actually when you "move the camera" in OpenGL, since there is actually no camera, what is done internally, is exactly that, moving everything on the scene in the oposite direction.
As for the solution, if you're using glut, you can use
gluLookAt(x, y, z,
ex, ey, ez,
0, 1, 0)
where (x, y, z) is the coordinate where you want the camera to be, (ex, ey, ez) is the direction vector that you want the camera to look into (in reference to (x, y, z) coordinates) and (0, 1, 0) is the up vector. This function does all the matrix transformations necessary. More info here
If you're not using glut, but only raw OpenGL, the same link also explains the equivalent opengl calls you have to use to achieve exactly the same effect as gluLookAt
So when you want to move the camera (only right and left probably, since it's a platform game) you only have to change the x value
I got this working using the following..
gl.PushMatrix()
gl.Translatef((1280/2)-float32((player.Body.Position().X)), 0, 0.0)
//Rest of drawing Code Code
gl.PopMatrix()
This is using OpenGL + Chipmunk Physics (in GoLang but should apply as these are just c-bindings). 1280 in this case is screen Width.
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?
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.