I'm developing a 3D application in OpenGL and I want to rotate the objects with the mouse like in AutoCad, SolidEdge or another CAD program. By the way, I'm totally new in 3D programing and OpenGl.
I've tried with GL.Rotate but as far as I know its complicated and not very attratctive for the user because one rotation around one axis affect the others. So I've been searching and I found the quaternions. I thought I understood how they work but when I run the app the GLControl that Im using is totally white. Also In the debugging mode I've seen that the Matrix "Mat" is full with NaN and I think that that's the problem. The AngX and AngY are the angles of rotation that I change in the mousemove
This is what I've done:
The main loop:
Mat = Matrix4d.Identity; //Global
Vector3d vect1 = new Vector3d(0, -1, 0);
Vector3d vect2 = new Vector3d(-1, 0, 0);
QuatRot1 = new Quaterniond(vect1, AngX);//Global
QuatRot2 = new Quaterniond(vect2, AngY);//Global
QuatRot1.Normalize();
QuatRot2.Normalize();
Quaterniond.Multiply(QuatAcc, QuatRot1);
Quaterniond.Multiply(QuatAcc, QuatRot2);
Matrix4d.CreateFromQuaternion(ref QuatAcc, out Mat);// I think the problem is here
AngX = 0;
AngY = 0;
GL.MultMatrix(ref Mat);
The mousemove:
if (WheelPress)
{ //mouse1 previous mouse position
//mouse0 current mouse position
AngY = 0.1f * (mouse1.X - mouse0.X);
AngX = 0.1f * (mouse1.Y - mouse0.Y);
Cursor.Current = Cursors.Hand;
glControl1.Refresh();
}
PS.I don't know if it's important but im working with OpenTK
Related
Lately I have started a project on an RTS game and honestly I didn't know I would run into so many difficulties.
The main problem I have right now is that I cannot find a way to project a 2D rectangle into the world, to get the units that are inside my screen rectangle and select them. I have an idea of how I could go about it using Physics.BoxCast but I just can't get my head around calculating it from the camera's rotation, and distance to the ground.
Here is the code I use to create a standard RTS unit rectagle selection tool.
if (Input.GetMouseButtonDown(0))
{
mouseStartPos = Input.mousePosition;
}
else if (Input.GetMouseButton(0))
{
Vector2 curMousePos = Input.mousePosition;
if (!selectionBoxObj.activeSelf)
{
selectionBoxObj.SetActive(true);
}
float width = curMousePos.x - mouseStartPos.x;
float height = curMousePos.y - mouseStartPos.y;
Vector2 selectionCenter = new Vector2(width / 2, height / 2);
selectionBoxTransform.sizeDelta = new Vector2(Mathf.Abs(width), Mathf.Abs(height));
selectionBoxTransform.anchoredPosition = mouseStartPos + selectionCenter;
}
else if (Input.GetMouseButtonUp(0))
{
if (selectionBoxObj.activeSelf)
{
selectionBoxObj.SetActive(false);
}
}
Now, can someone much smarter than me, help me with converting these coordinates into a BoxCast or similar function?
I know there is an easier way, which is storing every possible unit in a list and then checking their world to screen position, but I do not like that approach as I feel like it is extremely taxing when there are a lot of units which I intend having.
Thank you everyone.
I am trying to set up an extremely simple XNA game with a 3d terrain and some 2d GUI objects on top. I chose Nuclex since that seems to be one of the few 2d GUIs that's currently active.
My problem: adding a Nuclex "screen" class to my game results in the 3d terrain and lines drawn on top of it to screw up -- I have three layers of 3d objects: terrain, a wireframe outline of the terrain and some "routes" that hug the terrain. With the screen added, the routes that are partially-submerged into the terrain appear entirely on top of the terrain, and the wireframe grid appears thicker.
This is the tail-end of my Game.Initialize method, as made by following the sample on the Nuclex GuiManager page:
InputManager im = new InputManager();
IGraphicsDeviceService igds = Nuclex.Graphics.GraphicsDeviceServiceHelper.MakeDummyGraphicsDeviceService(GraphicsDevice);
gui = new GuiManager(igds, im);
gui.Initialize();
Viewport vp = GraphicsDevice.Viewport;
Screen main_screen = new Screen(vp.Width, vp.Height);
//main_screen.
this.gui.Screen = main_screen;
main_screen.Desktop.Bounds = new UniRectangle(
new UniScalar(0.1f, 0.0f), new UniScalar(0.1f, 0.0f), // x and y
new UniScalar(0.8f, 0.0f), new UniScalar(0.8f, 0.0f) // width and height
);
LabelControl text = new LabelControl("hello");
text.Bounds = new UniRectangle(10, 10, 200, 30);
main_screen.Desktop.Children.Add(text);
Components.Add(gui);
base.Initialize();
So, any ideas as to what I'm doing wrong?
Thanks!
Right, so thanks to catflier who pointed me in the direction of render states, I fixed the problem:
* First, "RenderState" is an XNA3 term; XNA4 simply allows a few state flags directly on the GraphicsDevice object.
* The problem is that Nuclex is secretly setting the GraphicsDevice.DepthStencilState and leaving it instead of restoring it to its previous value after use (naughty!!).
* So the solution is, at the top of your Draw method, to add a line like so:
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
I'm having a problem with moving a 3D object after I apply a rotation. Both the move and rotation functions work perfectly on their own. But the problem is when I move an object after a rotation, the object doesn't follow the mouse and goes in weird directions. If anyone can see my flaw, I'd appreciate it. Thanks! Here's my code:
private void Rotate()
{
double angle;
bool willangle = Double.TryParse(AngleRot.Text.ToString(), out angle);
RectangleVisual3D rect = (RectangleVisual3D)LastSelectedObject;
AxisAngleRotation3D r = new AxisAngleRotation3D(new Vector3D(0, 0, 1), angle);
RotateTransform3D rot = new RotateTransform3D(r, rect.Origin);
rect.Transform = Transform3DHelper.CombineTransform(rect.Transform, rot);
LastSelectedObject = rect as ModelVisual3D;
}
private void MoveObject(MouseEventArgs e)
{
if (LastSelectedObject is RectangleVisual3D)
{
RectangleVisual3D rect = (RectangleVisual3D)LastSelectedObject;
Point3D? origin = GetPoints(e);
if (origin == null)
return;
rect.Origin = (Point3D)origin;
LastSelectedObject = rect as ModelVisual3D;
}
}
I hope this help: The order of rotation and move is very important. If you move, then rotate, then it move according to the x,y,z co-ordinates. If you rotate, then move, then it will move according to the rotations co-ordinates.
Moving your object by setting its origin is generally a bad move. If your helper library ( I don't think Transform3DHelper is .Net? ) is doing matrix math in the basic way, then you're messing it up by setting rect.Origin.
Instead, try finding the distance vector moved and apply that translation matrix.
I'm assuming
Vector2D dist=new Vector2D((oldPosition - newPosition).x, (oldPosition - newPosition).y);
TranslateTransform3D trans = new TranslateTransform3D(dist.x,dist.y,0);
rect.Transform = Transform3DHelper.CombineTransform(rect.Transform, trans);
The other possible error is that CombineTransform should reverse rect.Transform and rot, but I'm not sure if the API is handling that for you. See if an overloaded version of the method allows you to reverse those two.
Hello I'm trying to make a terrain engine similar to that of Minecraft.
I was able to get a chunk loaded. It is very laggy and when there is more than one chunk loaded at once it becomes unplayable.
This is my render code:
public static void renderNormalBlock(GraphicsDevice g, Chunk chunk,Texture2D texture, int x, int y, int z)
{
float tileSize = 0.5F;
Vector3 blockPosition = new Vector3(x / tileSize, y / tileSize, z / tileSize);
Model blockModel = Main.defaultBlockModel;
ModelMesh mesh = blockModel.Meshes[0];
g.SamplerStates[0] = SamplerState.PointWrap;
BasicEffect effect = (BasicEffect)mesh.Effects[0];
effect.TextureEnabled = true;
effect.Texture = texture;
effect.View = Main.camera;
effect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), g.DisplayMode.AspectRatio, 1, 128);
effect.World = Matrix.CreateWorld(blockPosition, Vector3.Forward, Vector3.Up);
mesh.Draw();
}
As You can see I am not using for-each or for loops because as it's only a cube; It is not required.
I did some research and the best answer I found was that I need to hide the cube's faces that are not visible. So say if there's 2 cubes next to each other, I don't want to render the in between faces.
This is where I get stuck, Most people are using cubes that were drawn in XNA, and I'm using a model.
I'm new to XNA and I don't understand too much of the Math involved in manually drawing a cube since I'm currently in grade 9, so I used a model.
So how would I go about rendering only the faces that are visible?
your starting to develop a game before learning the basics. you wont get too far this way. First grab a book about XNA development and go through it. This is a basic subject that will be covered there. In addition, go visit techCraft http://techcraft.codeplex.com/ and download their implementation which comes with all the code. you will learn alot from that alone.
Good day everyone.
I hope you can help me with my question.
Is there a way to transform or directly render sprite like so?
Without using 3d. I know it can be easily done in 3d, but the project I'm working on doesn't use 3d at all, so I don't really want to also include 3d just because of that small thing...
(example image is from some random game)
So basically what I need:
Take a sprite as a rectangle, and then transform it in a free way, meaning that I can set points of that sprite to any coorditates, not just as rectangle.
Thanks in advance.
The technique used in that image is raycasting 2d. that was used first time with wolfenstein 3d, and implements a fake 3d over 2D.
here you can find a tutotial http://lodev.org/cgtutor/
though this is not what you want.
the best way to achieve what you want is define two triangles and use GraphicsDevice.DrawUserPrimitives with a basiceffect to draw it.
// Init Triangles with four points A,B,C and D
VertexPOsitionTexture[] Vertex = new VertexPositionTexture[6];
Vertex[0].Position = (A.X,A.Y,0);
Vertex[1].Position = (B.X,B.Y,0);
Vertex[2].Position = (C.X,C.Y,0);
Vertex[3].Position = (C.X,C.Y,0);
Vertex[4].Position = (B.X,B.Y,0);
Vertex[5].Position = (D.X,D.Y,0);
Vertex[0].Texture= (0,0);
Vertex[1].Texture= (1,0);
Vertex[2].Texture= (0,1);
Vertex[3].Texture= (0,1);
Vertex[4].Texture= (1,0);
Vertex[5].Texture= (1,1);
// Init Effect from http://blogs.msdn.com/b/shawnhar/archive/2010/04/05/spritebatch-and-custom-shaders-in-xna-game-studio-4-0.aspx
Matrix projection = Matrix.CreateOrthographicOffCenter(0, viewport.Width, viewport.Height, 0, 0, 1);
Matrix halfPixelOffset = Matrix.CreateTranslation(-0.5f, -0.5f, 0);
BasicEffect effect = new BasicEffect();
effect.Texture = your texture;
effect.TextureEnabled = true;
effect.World = Matrix.Identity;
effect.View = Matrix.Identity;
effect.Projection = halfPixelOffset * projection;
// Draw Triangles
effect.Apply():
GraphicsDevice.DrawUserPrimitives<VertexPositionTexture>(vertex, TriangleList, ...,...);
this code have to be understand as pseudocode, it's not tested but it shows the relevant actions to be done.