Lines represented as long thin triangles are not visble in 3D? - c#

I am trying to draw a 3D line in wpf and I have this xaml code:
<Grid>
<Viewport3D x:Name="ViewerViewport"
RenderOptions.BitmapScalingMode="HighQuality"
Focusable="True" Grid.RowSpan="2">
<ModelVisual3D x:Name="Model">
</ModelVisual3D>
<!-- Camera -->
<Viewport3D.Camera>
<PerspectiveCamera x:Name="Camera"
Position="0,0,0"
LookDirection="0,1,0"
UpDirection="0,0,1"
FieldOfView="100"
FarPlaneDistance="10"
NearPlaneDistance="0.1"/>
</Viewport3D.Camera>
</Viewport3D>
</Grid>
and this c# code:
public MainWindow()
{
InitializeComponent();
var ModelsGroup = new Model3DGroup();
ModelsGroup.Children.Add(this.AddLine(new Point3D(0, 0, 100), new Point3D(0, 100, 100),"line 1)"));
ModelsGroup.Children.Add(new AmbientLight(Colors.White));
Model.Content = ModelsGroup;
}
and line creation code:
private Model3D AddLine(Point3D startPoint, Point3D EndPoint, string name)
{
SolidColorBrush brush = new SolidColorBrush(Colors.Black);
var material = new DiffuseMaterial(brush);
var mesh = new MeshGeometry3D();
mesh.Positions.Add(startPoint);
mesh.Positions.Add(EndPoint);
mesh.TriangleIndices.Add(0);
mesh.TriangleIndices.Add(1);
mesh.TriangleIndices.Add(0);
return new GeometryModel3D(mesh, material);
}
but it doesn't show any line in output?
What is wrong with this?
I know that there are some 3d libraries that can do this easily, but I like to learn how to do it in WPF and then investigate how to do this using libraries (such as helix3d)

You are creating a triangle where two corners are at the same point, that is a triangle with zero area so it can never be seen from any angle. WPF uses only triangles with area
To create a line you must make a rectangle the length and width of the line, and split it with a diagonal to create two narrow triangles. So you need four positions and two triangles, like "0 1 2 0 1 3". Then of course you must make sure that the orientation of this rectangle is so that it is facing the camera.
You can google or bing for helix toolbox which is an excellent library of utilities for 3D in WPF. There you might find a useful helper function.

Why do you want to draw just line. In 3D you usually need triangles. If you have triangle you can determine normals. They are used to define facing of triangle which is used in lighting and texturing.
Camera settings
Typical camera Position is somewhere in positive z coordinates (something like 0, 0, 2 or 5, 0, 20), LookDirection vector is 0, 0, -1 and UpDirection vector is 0, 1, 0. In this case axes should be positioned as they usually are (positive y axis goes up and positive x axis goes to the right).
If you change UpDirection to 1, 0, 0 then positive x axis goes up not y axis.
If you change Position to negative z coordinates (0, 0, -5) and LookDirection to 0, 0, 1 then you look at your sceen from "behind" so positive x axis goes to the left (not to the right) but y axis still goes up.
In your settings your camera is pointing to the positive y numbers from origin and z axis goes up. X axis still goes to the right. If I add third point to your code. Point 100, 0, 100, than you can see small black triangle.
mesh.Positions.Add(startPoint);
mesh.Positions.Add(endPoint);
mesh.Positions.Add(new Point3D(100, 0, 100));
mesh.TriangleIndices.Add(0);
mesh.TriangleIndices.Add(1);
mesh.TriangleIndices.Add(2);
This triangle is small because of distance from camera - 100. So as #Samuels says in comment another error in settings is FarPlaneDistance="10".

you're building lines with no thickness....actually this and pixel coloring are the 2 most important problems of WPF....
If you want to draw lines you'll have to build it as a quadrangle (2 connex triangles), if you want to get smarter and have a lower number of triangles you can use other tricks (I'll let you think about it ^^, but for a given mesh you can have a wireframe that has exactly the same number of triangles as your mesh, which would not be the case if you create quadrangles)

Related

c# draw an arc in a rectangle

Spiral:
I have coded squares in C# based on the Fibonacci series exactly as shown in the included image. The problem I am having is trying to draw the arcs. I am not sure if I should be using arcs, curves or bezier curves. I assume an arc is what I want, but I have been unable to get the results I am trying for.
If someone could show me an example of how to draw an arc from corner to corner within a square it would be very much appreciated. I just hard coded the squares for fun. I want to try to write an algorithm to generate them, but right now I am stumped by the behavior of the arcs.
Bitmap bmp = new Bitmap(50, 50);
using (Graphics g = Graphics.FromImage(bmp))
{
g.DrawArc(Pens.Black, new Rectangle(0, 0, 100, 100), 0, 90);
}
Parameters
Stroke color
Bounding box for the circle the arc would be part of
Starting angle (in degrees)
Ending angle (in degrees)
The arc is drawn clockwise from the starting arc. To do a counterclockwise arc, supply a negative value for the ending angle.
Bitmap bmp = new Bitmap(50, 50);
using (Graphics g = Graphics.FromImage(bmp))
{
g.DrawArc(Pens.Black, new Rectangle(0, 0, 100, 100), 0, 90);
}
It seems the bounding box must be twice the size of the square in order for the arc to go from corner to corner.
Curve
The "rectangle" is a square. The center of the arc is a corner, the radius is a side, the starting angle is a multiple of 90° and the sweep angle is 90°. No rocket science.

Image rotation moving resulting image unpredictably

I've been looking all over SO today and I can't get anything to work for my needs.
I have a web application that let's users drag and drop text/images and then it sends the details to the server to draw those to a pdf. I'm trying to enable rotation, but I can't get a hold of the translatetransform stuff. My image in testing prints out great, rotated well, but it is not in the correct location. I'm missing how the intitial translatetransform changes things and my mind is shot at the end of the day. Do I have to draw this as a bitmap first using a different graphics instance, and then draw that bitmap to my background? Any help on this would be great! Thanks!
CODE:
i is the image object from the browser
coord is the x & y of the upper corner of the image on the canvas (990wx1100h) on the browser
size is the h & w of the element on the browser
Bitmap b = new Bitmap(wc.OpenRead(i.img));
if (i.rotation != 0)
{
g.TranslateTransform(this.CanvasDetails.size.width/2, this.CanvasDetails.size.height/2);
g.RotateTransform(i.rotation);
g.DrawImage(b, new Rectangle(- i.coord.x/2, -i.coord.y/2, i.size.width, i.size.height), 0, 0, b.Width, b.Height, GraphicsUnit.Pixel, ia);
}
else
{
g.DrawImage(b, new Rectangle(i.coord.x, i.coord.y, i.size.width, i.size.height), 0, 0, b.Width, b.Height, GraphicsUnit.Pixel, ia);
}
EDIT
I added the translatransform reversal as suggested by Adam, but the image is still drawn in a different location.
g.TranslateTransform(this.CanvasDetails.size.width / 2, this.CanvasDetails.size.height / 2);
g.RotateTransform(i.rotation);
g.TranslateTransform(-this.CanvasDetails.size.width / 2, -this.CanvasDetails.size.height / 2);
g.DrawImage(b, new Rectangle(-i.coord.x / 2, -i.coord.y / 2, i.size.width, i.size.height), 0, 0, b.Width, b.Height, GraphicsUnit.Pixel, ia);
Examples:
Browser View
.NET drawn version
Ok, completely reworking this answer to try to explain it clearer. A couple of things to know are that transformations 'accumulate' and rotation transforms happen around the origin. So to just explain the affect of accumulating (multiplying) transforms, look at this example:
//draw an ellipse centered at 200,200
g.DrawEllipse(Pens.Red, 195, 195, 10, 10);
//apply translate transform - shifts origin to 200,200
g.TranslateTransform(200, 200);
//draw another ellipse, should draw around first ellipse
//because translate tranforms essentially moves our coordinates 200,200
g.DrawEllipse(Pens.Blue, -7, -7, 14, 14);
//now do rotate transform
g.RotateTransform(90f); //degree to rotate object
//now, anything we draw with coordinates 0,0 is actually going to be draw at 200,200 AND be rotated by 45*
//this line will be vertical, through 200,200, instead of horizontal through 0,0
g.DrawLine(Pens.Green, -20,0,20,0);
//If we add another translate, this time 50x, it would normally translate by 50 in the X direction
//BUT - because we already have transforms applied, including the 90 rotate, it affects this translation
//so this in effect because a 50px translation in Y, because it's rotated 90*
g.TranslateTransform(50, 0);
//so even though we translated 50x, this line will draw 50px below the last line
g.DrawLine(Pens.Green, -20, 0, 20, 0);
So for your case, you want to draw an object Centered at CenterPoint and rotated by Angle. So you would do:
g.TranslateTransform(-CenterPoint.X, -CenterPoint.Y);
g.RotateTransform(Angle);
g.DrawImage(b, -ImageSize/2, -ImageSize/2, ImageSize, ImageSize);
You'd then need to reset the transforms for additional drawing, which you can do with:
g.ResetTransform();
If that doesn't leave the image where you want it, then you'll need to check the values you're using to position it. Are you storing it's center? Or top left? Etc.

Dynamically moving pause button rectangle correct but drawing incorrectly

I have a button class which is basic, it glows when mouse is over the button and works for my main menu. However with a pause function that I have the x values are going to be different all the time. I have a camera class which changes the viewport and will scroll depending on where the player's position is. This is all working fine. However when I introduced the pause option either the Drawn "button" is placed correctly, however the rectangle used for mouse detection is some distance away from that.
replay.SetPosition(new Vector2(camera.viewport.Width / 4 + 50,camera.centre.Y));
//replay.SetPosition(new Vector2((int)camera.centre.X , (int)camera.centre.Y);
replay.Update(mouse);
The commented out one draws the image correctly but the rectangle is way off.
The uncommented version has the correct rectangle placement but the image stays at currently 200(x),250(y)
if (isPaused)
{
spriteBatch.Draw(pauseTexture,pauseRectangle, Color.White);
//replay.Draw(spriteBatch);
exit.Draw(spriteBatch);
mainmenu.Draw(spriteBatch);
}
The camera class update elements:
public void Update(Vector2 position, int xOffset, int yOffset)
{
if (position.X < viewport.Width / 4)
centre.X = viewport.Width / 4;
else if (position.X > xOffset - (viewport.Width / 4))
centre.X = xOffset - (viewport.Width / 4);
else centre.X = position.X;
}
I will be around most of the day to add information if needed. Thanks for all the help!
Unfortunately I don't have enough rep to comment just yet, so based on the information given I will do my best to answer.
It sounds like your rectangle and position of your menu item are not being updated together. Let's say you have a position of (0,0) and rectangle of (0, 0, 100, 100) - (x, y, width, height), so the rectangle extends from (0, 0) to (100, 100). If you update the position to (100, 100), for example, you also have to update the rectangle's x and y coords to (100, 100), thus the rectangle now extends from (100, 100) to (200, 200).
I don't have enough information from your code samples to tell you what's going wrong where, but from what I can tell that's what is happening.
On another note.. if you are passing in the camera's transformation matrix to SpriteBatch.Begin(...) and you are also making draw calls to your HUD elements within that SpriteBatch.Begin...End section, you should consider making another SpriteBatch.Begin...End section without the camera's transformation matrix being passed in. This way your HUD elements' positions will be in screen coordinates compared to world coordinates, and you won't run into issues like this. The HUD elements typically never change positions, unless of course you allow them to, but you will still be working in screen coordinates compared to world coordinates.
Example: (Keep in mind that I don't recall what the parameters are exactly for SpriteBatch.Begin(...) but this should help)
//Main Draw function
public void Draw() {
//World Coordinates
spriteBatch.Begin(cameraTransformationMatrix);
//Draw all world coordinate objects
//Player, Enemies, Walls, etc.
spriteBatch.End();
//Screen Coordinates
spriteBatch.Begin();
//Draw all screen coordinate objects
//Menus, In-Game HUD elements, etc.
spriteBatch.End();
}

Difference between AnisotropicClamp and AnisotropicWrap in XNA 4.0?

I understand that both are methods of texture filtering but what is the difference between clamp and wrap? Which one is better?
EDIT: I tried both with integrated graphics card and found that AnisotropicWrap showed a lower FPS than AnisotropicClamp. Is it true that AnisotropicWrap renders a better texture than AnisotropicClamp?
The sampler states are responsible for telling the graphics device how to translate texture coordinates into texels. Say you have a quadrilateral polygon with the UV coordinates arranged like this:
(0, 0) (1, 0)
o----------o
| |
o----------o
(0, 1) (1, 1)
Texture coordinates have the range [0, 1]. When this is rendered, the top-left corner of the texture will appear at the top-left corner of the polygon, the bottom-right corner of the texture will appear at the bottom-right corner of the polygon, and so on.
Now say you arrange your UV coordinates like this:
(-1, -1) (2, -1)
o----------o
| |
o----------o
(-1, 2) (2, 2)
What happens? There's no correct way to map these coordinates to the texture, because they're outside of our [0, 1] range!
The answer is that you have to tell the device what the correct way is, by specifying either WRAP or CLAMP sampler states.
A CLAMP state clamps the texture coordinates to the [0, 1] range; pixels with coordinates outside of this range will display the closest valid texel.
A WRAP state, on the other hand, assumes that the texture coordinates are cyclical. A coordinate of 1.5 will be treated as 0.5, a coordinate of -0.25 will be treated as 0.75, and so on. This causes the texture to wrap, giving it a tiled appearance.
I'm not an XNA developer but they looks different for me.
SamplerState.AnisotropicClamp
Contains default state for anisotropic filtering and texture
coordinate clamping.
SamplerState.AnisotropicWrap
Contains default state for anisotropic filtering and texture
coordinate wrapping.
Check these links also;
http://iloveshaders.blogspot.com/2011/04/using-state-objects-in-xna.html
https://code.google.com/p/slimdx/

Fitting a rectangle into screen with XNA

I am drawing a rectangle with primitives in XNA. The width is:
width = GraphicsDevice.Viewport.Width
and the height is
height = GraphicsDevice.Viewport.Height
I am trying to fit this rectangle in the screen (using different screens and devices) but I am not sure where to put the camera on the Z-axis. Sometimes the camera is too close and sometimes to far.
This is what I am using to get the camera distance:
//Height of piramid
float alpha = 0;
float beta = 0;
float gamma = 0;
alpha = (float)Math.Sqrt((width / 2 * width/2) + (height / 2 * height / 2));
beta = height / ((float)Math.Cos(MathHelper.ToRadians(67.5f)) * 2);
gamma = (float)Math.Sqrt(beta*beta - alpha*alpha);
position = new Vector3(0, 0, gamma);
Any idea where to put the camera on the Z-axis?
The trick to doing this is to draw the rectangle directly in raster space. This is the space that the GPU works in when actually rendering stuff.
Normally your model starts in its own model space, you apply a world transform to get it into world space. You then apply a view transform to move the points in the world around the camera (to get the effect of the camera moving around the world). Then you apply a projection matrix to get all those points into the space that the GPU uses for drawing.
It just so happens that this space is always - no matter the screen size - from (-1,-1) in the bottom left corner of the viewport, to (1,1) in the top right (and from 0 to 1 on the Z axis for depth).
So the trick is to set all your matrices (world, view, project) to Matrix.Identity, and then draw a rectangle from (-1,-1,0) to (1,1,0). You probably also want to set DepthStencilState.None so that it doesn't affect the depth buffer.
An alternative method is to just use SpriteBatch and draw to a rectangle that is the same size as the Viewport.

Categories