Scrolling a 3D Object and it's Texture Upwards - c#

So I'm building a windows game, and I've got some text as a texture on a primitive. I'm trying to scroll the primitive upwards, but cannot accomplish this. I've tried simply adding a value to the Y position of the Vector3, but there's issues here.
I initialize the vertexes with:
verts = new VertexPositionTexture[4];
verts[0] = new VertexPositionTexture(new Vector3(-xPosition, yPosition, 0), new Vector2(0,0));
verts[1] = new VertexPositionTexture(new Vector3(xPosition, yPosition, 0), new Vector2(1, 0));
verts[2] = new VertexPositionTexture(new Vector3(-xPosition, negY, 0), new Vector2(0, 1));
verts[3] = new VertexPositionTexture(new Vector3(xPosition, negY, 0), new Vector2(1, 1));
Then When I try to get this to scroll upwards by adding to the Y coordinates, several things can happen.
If I add to both the variables for the y coordinates like this :
yPosition += .01f;
negY += .01f;
verts[0].Position.Y = yPosition;
verts[1].Position.Y = yPosition;
verts[2].Position.Y = negY;
verts[3].Position.Y = negY;
The texture, or the primitive all together doesn't even show up anymore. If I comment out the negY += .01f, the top of the primitive scrolls upwards, but this begins to distort the texture obviously. Why doesn't this work?! Why does adding to the negY bork the whole deal?

Related

MonoGame VertexPositionColor draws in incorrect place

I'm trying to make a rendering library for monogame and I'm currently working on drawing 2D polygons. However, The positions don't make any sense. Somehow, drawing them at (0, 0, 0), (100. 0, 0), (0, 100, 0), and (100, 100, 0) doesn't reach the top-left coordinate (0, 0). How do I fix this?
My Code:
BasicEffect basicEffect = new BasicEffect(GraphicsDevice);
VertexPositionColor[] vert = new VertexPositionColor[4];
vert[0].Position = new Vector3(0, 0, 0);
vert[1].Position = new Vector3(100, 0, 0);
vert[2].Position = new Vector3(0, 100, 0);
vert[3].Position = new Vector3(100, 100, 0);
short[] ind = new short[6];
ind[0] = 0;
ind[1] = 2;
ind[2] = 1;
ind[3] = 1;
ind[4] = 2;
ind[5] = 3;
foreach (EffectPass effectPass in basicEffect.CurrentTechnique.Passes)
{
effectPass.Apply();
GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionColor>(
PrimitiveType.TriangleList, vert, 0, vert.Length, ind, 0, ind.Length / 3);
}
RESULT: https://imgur.com/GkyqmlY
MonoGame uses a different origin for 2D and 3D coordinate systems. In 2D, (0, 0) is top-left corner, and Y increases toward the bottom of the screen. In 3D, (0,0,0) is the center of the screen, and the coordinate grid works very much like it does in mathematics - think 4 quadrants in math, if you "flatten" the z-axis.
You're drawing in Quadrant I. If you want the drawing to be based on top-left corner, you need to translate your vertices by -1/2 your viewport width and +1/2 your viewport height.

Smoothen line on linerender

I've created a square using linerenderer but my problem now is that the line is not smooth. see below picture. I've tried enabling anti-aliasing and setting lr.numCapVertices to no avail.
private void DrawLine()
{
GameObject myLine = new GameObject();
myLine.transform.position = start;
myLine.AddComponent<LineRenderer>();
lr = myLine.GetComponent<LineRenderer>();
lr.material = new Material(Shader.Find("Sprites/Default"));
lr.positionCount = 4;
lr.startWidth = .1f;
lr.endWidth = .1f;
lr.SetPosition(0, new Vector3(1, 0, 0));
lr.SetPosition(1, new Vector3(2, 0, 0));
lr.SetPosition(2, new Vector3(2, -1, 0));
lr.SetPosition(3, new Vector3(1, -1, 0));
lr.loop = true;
Gradient gradient = new Gradient();
gradient.SetKeys(
new GradientColorKey[]
{
new GradientColorKey(Color.red, 0.25f),
new GradientColorKey(Color.green, 0.50f),
new GradientColorKey(Color.blue, 0.75f),
new GradientColorKey(Color.yellow, 1f),
},
new GradientAlphaKey[] { new GradientAlphaKey(1f, 0.0f)
}
);
lr.colorGradient = gradient;
}
Have a look at line renderer documentation. Specifically the following properties:
Corner vertices
End cap vertices
Alignment
The corner and cap vertices will determine the 'roundness' of corners and line endings.
Different alignment settings may give you a more orthogonal view of the line which should prevent the illusion of varying thickness as can be seen at the green corner in your image.

How to move the axis on a 3d model

A few days into 3d models and I can't figure out how to move an axis so I can start my rotations. for example.... I want to tilt X at 30 degrees and then I will be lined up to do each axis rotations. If I rotate X to 30 degrees it throws off Y and Z rotations. Any examples of how to do this in code behind? The closest example I found was in the Manipulator demo but it doesn't show the code on how the manipulator works.
private Transform3DGroup GetTransforms(Model3D model)
{
var transforms = new Transform3DGroup();
// Rotation around X
transforms.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), 0)));
// Rotation around Y
transforms.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), 0)));
// Rotation around Z
transforms.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 0, 1), 0)));
// Translate transform (if required)
transforms.Children.Add(new TranslateTransform3D());
model.Transform = transforms;
return transforms;
}
private void SetRotation(double amountX, double amountY, double amountZ, Model3D model, Point3D center)
{
// Suppose we have a function that gives us all the transforms
// applied to this object
var transforms = GetTransforms(model);
var translation = transforms.Children[3];
// Suppose GetCenter() obtains the center point of an object
// in Point3D format
var translatedCenter = translation.Transform(center);
if (!(transforms.Children[0] is RotateTransform3D rotX)) throw new ArgumentNullException(nameof(rotX));
if (!(transforms.Children[1] is RotateTransform3D rotY)) throw new ArgumentNullException(nameof(rotY));
if (!(transforms.Children[2] is RotateTransform3D rotZ)) throw new ArgumentNullException(nameof(rotZ));
// Set the center point of transformation to the translated center of the object
rotX.CenterX = rotY.CenterX = rotZ.CenterX = translatedCenter.X;
rotX.CenterY = rotY.CenterY = rotZ.CenterY = translatedCenter.Y;
rotX.CenterZ = rotY.CenterZ = rotZ.CenterZ = translatedCenter.Z;
// Apply the angle amounts
((AxisAngleRotation3D) rotX.Rotation).Angle = amountX;
((AxisAngleRotation3D) rotY.Rotation).Angle = amountY;
((AxisAngleRotation3D) rotZ.Rotation).Angle = amountZ;
}

How to rotate a camera around its own axis in WPF viewport3D?

I am working on a 3D application in WPF and having trouble with the camera. It should be possible to rotate the camera around its own axis (with other words, look around) using the mouse but I can not get it to work properly. I create the camera with the following code:
PerspectiveCamera perspectiveCamera = new PerspectiveCamera(new Point3D(0, 30, 0), new Vector3D(0, -1, 0), new Vector3D(0, 0, 1), 90);
perspectiveCamera.NearPlaneDistance = 0.001;
perspectiveCamera.FarPlaneDistance = 1000;
center = new TranslateTransform3D(0, 30, 0);
rot_x = new AxisAngleRotation3D(new Vector3D(1, 0, 0), 0);
rot_y = new AxisAngleRotation3D(new Vector3D(0, 1, 0), 0);
rot_z = new AxisAngleRotation3D(new Vector3D(0, 0, 1), 0);
zoom = new ScaleTransform3D(1, 1, 1);
Transform3DGroup t = new Transform3DGroup();
t.Children.Add(zoom);
t.Children.Add(new RotateTransform3D(rot_x));
t.Children.Add(new RotateTransform3D(rot_y));
t.Children.Add(new RotateTransform3D(rot_z));
t.Children.Add(center);
perspectiveCamera.Transform = t;
myViewport3D.Camera = perspectiveCamera;
And then I try to rotate it using the following code:
private void OnViewportMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (mouseLeftIsDown)
{
Point position = e.GetPosition(this);
double rotZAngle = (rot_z.Angle % 360) + oldLeftPosition.X - position.X;
double rotXAngle = (rot_x.Angle % 360) + position.Y - oldLeftPosition.Y;
if (rotZAngle < 0) //rotZAngle is negative, make it positive
{
rotZAngle = 360 + rotZAngle;
}
if (rotXAngle < 0) //rotXAngle is negative, make it positive
{
rotXAngle = 360 + rotXAngle;
}
rot_z.Angle = rotZAngle;
rot_x.Angle = rotXAngle;
oldLeftPosition = position;
}
}
However, it seams that the rotation is not happening around the camera and instead somehere else. The model that I load at position (0,0,0) is becoming visible after I rotate 180 degrees around the z axis which should not be the case.
What am I missing?

How to shoot a triangle out of an asteroid which floats all of the way up to the screen?

I currently have an asteroid texture loaded as my "test player" for the game I'm writing. What I'm trying to figure out how to do is get a triangle to shoot from the center of the asteroid, and keep going until it hits the top of the screen. What happens in my case (as you'll see from the code I've posted), is that the triangle will show, however it will either be a long line, or it will just be a single triangle which stays in the same location as the asteroid moving around (that disappears when I stop pressing the space bar), or it simply won't appear at all. I've tried many different methods, but I could use a formula here.
All I'm trying to do is write a space invaders clone for my final in C#. I know how to code fairly well, my formulas just need work is all.
So far, this is what I have:
Main Logic Code
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(ClearOptions.Target, Color.Black, 1, 1);
mAsteroid.Draw(mSpriteBatch);
if (mIsFired)
{
mPositions.Add(mAsteroid.LastPosition);
mRay.Fire(mPositions);
mIsFired = false;
mRay.Bullets.Clear();
mPositions.Clear();
}
base.Draw(gameTime);
}
Draw Code
public void Draw()
{
VertexPositionColor[] vertices = new VertexPositionColor[3];
int stopDrawing = mGraphicsDevice.Viewport.Width / mGraphicsDevice.Viewport.Height;
for (int i = 0; i < mRayPos.Length(); ++i)
{
vertices[0].Position = new Vector3(mRayPos.X, mRayPos.Y + 5f, 10);
vertices[0].Color = Color.Blue;
vertices[1].Position = new Vector3(mRayPos.X - 5f, mRayPos.Y - 5f, 10);
vertices[1].Color = Color.White;
vertices[2].Position = new Vector3(mRayPos.X + 5f, mRayPos.Y - 5f, 10);
vertices[2].Color = Color.Red;
mShader.CurrentTechnique.Passes[0].Apply();
mGraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleStrip, vertices, 0, 1);
mRayPos += new Vector2(0, 1f);
mGraphicsDevice.ReferenceStencil = 1;
}
}
This isn't quite how you're supposed to be manipulating the location of a model in world space and since you're creating a new vertex array every single draw frame you'll find that it performs pretty badly when you come to draw more than a few triangles.
declare the vertices and index list for your triangle just once in the LoadContent method.
VertexBuffer triangleVertexBuffer;
IndexBuffer triangleIndexBuffer;
protected override void LoadContent()
{
// Setup a basic effect to draw the triangles with.
mEffect = new BasicEffect(GraphicsDevice);
// setup the triangle vertext buffer and load up it's content.
triangleVertexBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionColor), 3, BufferUsage.WriteOnly);
triangleVertexBuffer.SetData<VertexPositionColor>(new VertexPositionColor[]
{
new VertexPositionColor (new Vector3 (0f, -1f, 0.0f), Color.Blue), // Top Point
new VertexPositionColor (new Vector3 (-1f, 1f, 0.0f), Color.White), // Bottom Left
new VertexPositionColor (new Vector3 (1f, 1f, 0.0f), Color.Red), // Bottom Right
});
// setup an index buffer to join the dots!
triangleIndexBuffer = new IndexBuffer(GraphicsDevice, IndexElementSize.SixteenBits, 3, BufferUsage.WriteOnly);
triangleIndexBuffer.SetData<short>(new short[]
{
0,
1,
2,
});
}
After this assuming your effect takes in to account a world transformation (basic effect does) you can use that parameter to move the triangle.
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
for (int i = 0; i < mRayPos.Length ; i++)
{
// This is the line that moves the triangle along your ray.
mEffect.World = Matrix.CreateTranslation(new Vector3(mRayPos[i].X, mRayPos[i].Y, mRayPos[i].Z));
mEffect.Techniques[0].Passes[0].Apply();
// These lines tell the graphics card that you want to draw your triangle.
GraphicsDevice.SetVertexBuffer(triangleVertexBuffer);
GraphicsDevice.Indices = triangleIndexBuffer;
GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 3, 0, 1);
}
base.Draw(gameTime);
}
If you use this method it becomes a very simple operation to rotate or scale your trangle using Matrix.CreateRotation and Matrix.CreateScale.

Categories