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.
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 would like to draw those black dots around the whole circle with regular spacing in between each other (rough image below). Those black dots should sit directly on the circle. Is there an easy way to do it somehow with painter.drawArc() function or something like that?
No, there isn't. I am afraid you will have to use... math!
Actually, you could get away without that. For sweeping around a circle in particular there is an easy way to do it by transforming the painter. You initially transform the painter to the center of the circle, and draw the first dot at the circle's 12 o'clock position. That means drawing it into negative y space. Then you simply rotate the painter by 360 / numOfObjects degree and draw the same circle again.
They key thing here is to transform the painter to the center and draw the object offset, because otherwise it will be more complicated to calculate the position and angle yourself. The angle doesn't play a role here, since you are drawing dots, but it will make a huge difference if you draw something other than dots. This way you can easily sweep the circle by rotating the painter around its origin.
To put it in pseudo code:
draw big circle
move painter to big circle center
degree = 360 / numOfObjects
while numOfObjects--
draw dot at 12 o'clock
rotate painter by degree
I'm recently trying to build a program by myself, and for this reason I need to make a Sprite bigger when the MouseCursor is over it. Is solved it by checking for Mouse movement and then checking if ths mouse is over the Sprite. I increase the size of the sprite by using the setScale(); function. The problem then was, that the Sprite has been enlarged, but the center of the Sprite has been moved. I tried to set the Origin to the center of the Sprite, but now, the texture is at an other place than the Sprite.
The Texture is 500x500px large, so I set the origin to 250, 250. The Texture of the sprite moved to the right spot, since the origin is at an other place. The Position is "50, 250", so the texture is slightly off the screen. When I set a new position, the texture moves, but the sprite also. So texture and sprite don't match anymore.
Does anyone know how to fix the problem?
I plan on making a game, and I want to create some background animations for said game. One of these animations is a rotating rectangle. I've looked all over, and I cannot find any form of math or logic that allows me to rotate a rectangle (SDL_Rect to be specific, but you might have already known that).
I can't figure out the math for myself, I really don't have any working code for this, so I can't show anything.
Essentially I'm looking for some type of logic that I can apply the rectangle's coordinates so that whenever the main game loop loops, it will rotate the rectangle some amount of degrees.
You can't rotate an SDL_Rect. If you look at its definition, it's made of coordinates for the top-left corner, the width and the height. There's no way to represent a rectangle with sides that aren't parallel to the coordinate system's axes.
SDL_RenderCopyEx supports drawing rotated textures, though.
just wondering how someone would go about dragging 4 different
objects in openGL. I have very simple code to draw these objects:
glPushMatrix();
glTranslatef(mouse_x, mouse_y, 0);
glutSolidIcosahedron();
glPopMatrix();
glPushMatrix();
glTranslatef(mouse_x2, mouse_y2, 0);
glutSolidIcosahedron();
glPopMatrix();
glPushMatrix();
glTranslatef(mouse_x3, mouse_y3, 0);
glutSolidIcosahedron();
glPopMatrix();
glPushMatrix();
glTranslatef(mouse_x4, mouse_y4, 0);
glutSolidIcosahedron();
glPopMatrix();
I understand how to move an object, but I want to learn how to drag and drop any one of these objects.
I've been researching about the Name Stack and Selection Mode, but it just confused the hell out of me.
And I also know about having to have some sort of glutMouseFunc.
It's just the selection of each shape I'm puzzled on.
First thing that you need to do is capturing the position of mouse on the screen when the button is clicked. There are plenty of ways to do it but I believe it's outside of the scope of this question. When you have screen X,Y coords you must detect if any object is selected and which one it is. There are two possible approaches. You can either keep track of a bounding rectangle positions of each object (in screen space) and the test if the cursor is inside any of those rectangles will be quite simple. Or you can cast a ray from eye through cursor position in world space and check intersection of this ray with each object.
The second approach is more versatile for 3D graphics but you seem to be using only X and Y coords so you don't need to worry about Z order of objects.
In case of the first solution the main problem is: how to know how big is your object on the screen. glutSolidIcosahedron() renders an object of radius 1. To calculate it's screen radius you can either use some matrix math or in that case a simple trigonometry. You will need to know the distance from camera to the drawing plane (I believe you're using some glTranslatef(0,0,X) before you render. X is your distance) You also need to know the view angle of the camera. You set it in projection matrix. Now take a piece of paper, draw a cone of angle alpha, intersecting a plane at distance X and knowing that an object has radius 1 you can easily calculate how large area of the screen it occupies. (I'll leave this calculation for you)
Now if you know the radius on screen, simply test the distance from your click position to each object. if the distance is below radius it's selected. If more than one object passes this test just select first one of them.