I have set of points. I created strip triangles using these points.
I am using HelixToolkit to draw these rectangles. Function requires list of pointes (triangles will be made using triangle strip) and set of normal vectors. Now I need to calculate normal. What I thought that for each triangle there should be a normal. But function says that for every point there will be a normal. I used three points to calculate normal of a triangle, but how can I calculate normal of a point.
So if am using the example shown in the figure what will be normal of All points (A, B, C, D, E, F).
Here is the method which I am calling.
/// <summary>
/// Adds a triangle strip to the mesh.
/// </summary>
/// <param name="stripPositions">
/// The points of the triangle strip.
/// </param>
/// <param name="stripNormals">
/// The normal vectors of the triangle strip.
/// </param>
/// <param name="stripTextureCoordinates">
/// The texture coordinates of the triangle strip.
/// </param>
/// <remarks>
/// See http://en.wikipedia.org/wiki/Triangle_strip.
/// </remarks>
public void AddTriangleStrip(
IList<Point3D> stripPositions,
IList<Vector3D> stripNormals = null,
IList<Point> stripTextureCoordinates = null)
Here is what I have.
var points = new List<Point3D>();
// populate points.
// TODO: populate Normal for each point.
AddTriangleStrip(points, normal);
I used this method to calculate normal of a surface.
private static Vector3D CalculateNormal(Point3D firstPoint, Point3D secondPoint, Point3D thirdPoint)
{
var u = new Point3D(firstPoint.X - secondPoint.X,
firstPoint.Y - secondPoint.Y,
firstPoint.Z - secondPoint.Z);
var v = new Point3D(secondPoint.X - thirdPoint.X,
secondPoint.Y - thirdPoint.Y,
secondPoint.Z - thirdPoint.Z);
return new Vector3D(u.Y * v.Z - u.Z * v.Y, u.Z * v.X - u.X * v.Z, u.X * v.Y - u.Y * v.X);
}
There is no such concept like a normal of Point. Normal refers to a surface and not to a point, so I presume that we are talking here about average normal of all neighbour faces of a given point .
For this, you should know somehow from given point all connected to it faces.
For every face calculate its normal and make an average of them
Hope this helps.
Related
It seems straight forward to define a function like this
/// <summary>
/// Build 3D transform matrix with image of unit vectors of axes, and the image of the origin
/// </summary>
/// <param name="xUnit">The image of x axis unit vector</param>
/// <param name="yUnit">The image of y axis unit vector</param>
/// <param name="zUnit">The image of z axis unit vector</param>
/// <param name="offset">The image of the origin</param>
/// <returns>The matrix</returns>
public static Matrix3D MatrixFromVectors(Vector3D xUnit, Vector3D yUnit, Vector3D zUnit, Vector3D offset)
{
var m = new Matrix3D(
xUnit.X, xUnit.Y, xUnit.Z, 0.0,
yUnit.X, yUnit.Y, yUnit.Z, 0.0,
zUnit.X, zUnit.Y, zUnit.Z, 0.0,
0, 0, 0, 1);
m.Translate(offset);
return m;
}
However the test code
...
var m = Geo.MatrixFromVectors(vx,vy,vz,new Vector3D(1,2,3));
var result = m.transform(new Vector3D(1,0,0)) //result: equal to vx
...
shows it does not use the offset at all. How to make it work?
The structures in the Media3D Namespace make a distinction between Vectors and Points. Vector3D is used to specify a position independent value in space (such as an Axis, Surface normal, Acceleration etc.), while Point3D is used to specify position.
Because Vectors are not suppsed to carry position Information Matrix3D.Transform(Vector3D) does not apply the offset. It only transforms the direction of the Vector.
If you pass a Point3D instead of a Vector3D to Matrix3D.Transform(Point3D) it works as expected:
...
var m = Geo.MatrixFromVectors(vx,vy,vz,new Vector3D(1,2,3));
var result = m.transform(new Point3D(0,0,0)) // result is 1,2,3
...
I am attempting to convert euler angle rotations between Unity and Threejs. There are two main issues with this.
Problem 1:
Unity and Threejs have different coordinate systems
Unity:
Threejs
Problem 2:
Unity does euler math in the order ZXY whereas Threejs defaults to XYZ. I have found some formulas on the Threejs side for creating Euler angles using a different order of multiplication, but I would like to know the math behind this so I can go back and forth between the two systems. I am also not sure how the different coordinate systems plays into this conversion math.
EDIT 1
I found this stack overflow post about converting a Unity Quaternion to Threejs:
Convert Unity transforms to THREE.js rotations
However, I was not able to get this code to work for going the opposite direction of Threejs to Unity which is what I need.
I finally found a solution to this using the links below. There may be an easier solution, but nothing else I tried gave me the intended effect. It is worth noting that this was tested with a Threejs camera that is -z facing where +y is up. My unity camera is -z facing with +y facing up. If you have a +z facing camera, which is common in Unity, simply child the GameObject to an empty GameObject and apply a 180 degree Euler rotation to the empty GameObject. This also assumes that the Threejs Euler rotation is the default XYZ ordering.
http://answers.unity3d.com/storage/temp/12048-lefthandedtorighthanded.pdf
http://en.wikipedia.org/wiki/Euler_angles
http://forum.unity3d.com/threads/how-to-assign-matrix4x4-to-transform.121966/
/// <summary>
/// Converts the given XYZ euler rotation taken from Threejs to a Unity Euler rotation
/// </summary>
public static Vector3 ConvertThreejsEulerToUnity(Vector3 eulerThreejs)
{
eulerThreejs.x *= -1;
eulerThreejs.z *= -1;
Matrix4x4 threejsMatrix = CreateRotationalMatrixThreejs(ref eulerThreejs);
Matrix4x4 unityMatrix = threejsMatrix;
unityMatrix.m02 *= -1;
unityMatrix.m12 *= -1;
unityMatrix.m20 *= -1;
unityMatrix.m21 *= -1;
Quaternion rotation = ExtractRotationFromMatrix(ref unityMatrix);
Vector3 eulerRotation = rotation.eulerAngles;
return eulerRotation;
}
/// <summary>
/// Creates a rotation matrix for the given threejs euler rotation
/// </summary>
private static Matrix4x4 CreateRotationalMatrixThreejs(ref Vector3 eulerThreejs)
{
float c1 = Mathf.Cos(eulerThreejs.x);
float c2 = Mathf.Cos(eulerThreejs.y);
float c3 = Mathf.Cos(eulerThreejs.z);
float s1 = Mathf.Sin(eulerThreejs.x);
float s2 = Mathf.Sin(eulerThreejs.y);
float s3 = Mathf.Sin(eulerThreejs.z);
Matrix4x4 threejsMatrix = new Matrix4x4();
threejsMatrix.m00 = c2 * c3;
threejsMatrix.m01 = -c2 * s3;
threejsMatrix.m02 = s2;
threejsMatrix.m10 = c1 * s3 + c3 * s1 * s2;
threejsMatrix.m11 = c1 * c3 - s1 * s2 * s3;
threejsMatrix.m12 = -c2 * s1;
threejsMatrix.m20 = s1 * s3 - c1 * c3 * s2;
threejsMatrix.m21 = c3 * s1 + c1 * s2 * s3;
threejsMatrix.m22 = c1 * c2;
threejsMatrix.m33 = 1;
return threejsMatrix;
}
/// <summary>
/// Extract rotation quaternion from transform matrix.
/// </summary>
/// <param name="matrix">Transform matrix. This parameter is passed by reference
/// to improve performance; no changes will be made to it.</param>
/// <returns>
/// Quaternion representation of rotation transform.
/// </returns>
public static Quaternion ExtractRotationFromMatrix(ref Matrix4x4 matrix)
{
Vector3 forward;
forward.x = matrix.m02;
forward.y = matrix.m12;
forward.z = matrix.m22;
Vector3 upwards;
upwards.x = matrix.m01;
upwards.y = matrix.m11;
upwards.z = matrix.m21;
return Quaternion.LookRotation(forward, upwards);
}
Problem 1:
Granted I only minored in math but I believe you should simply be able to do a straight mapping as follows for points:
(X, Y, Z) => (X, Y, -Z)
And that should work both ways.
As far as I remember once you convert between coordinates the math should be the same, just make sure you work all in one system or the other to make your life easier. Then you can export results back as needed.
I am trying to look for a way to indent example code in Doxygen but could not find anything about C# and Xml comments.
Since every attempt is a little long on setting it up and all and I have not found any proper documentation on that issue, I though of asking here.
The idea is to create indentation for C# xml comment. So far I have:
/// <code>public void Method()<br>
/// {<br>
/// <blockquote>float x = 10, y = 10 , z = 0;<br>
/// Vector3 vector = new Vector3 (x, y, z);<br>
/// if(something)<br>
/// <blockquote>Other Code</blockquote></br></blockquote>
/// }</code>
But it draws a blue line on the left side:
Does anyone have a simple and good looking way?
Thanks
How about this?
/// \code
/// public void Method()
/// {
/// float x = 10, y = 10 , z = 0;
/// Vector3 vector = new Vector3 (x, y, z);
/// if(something)
/// Other Code
/// }
/// \endcode
Much easier to read the source comments too :)
I've got two rectangles on WindowsForm and I would like to check if they collide. For simple non-rotated collision it looks like this:
Point newLocation; // upper-left corner of the object to check its collision
Size objectSize; // the object size
bool collision = false;
foreach (Object otherObject in otherObjects)
{
if (newLocation.X >= otherObject.location.X && newLocation.X <= otherObject.location.X + otherObject.size.width)
if (newLocation.Y >= otherObject.location.Y && newLocation.Y <= otherObject.location.Y + otherObject.size.height)
{
collision = true;
break;
}
}
But now I rotated both objects with:
Matrix matrix = new Matrix();
matrix.RotateAt(angle, newLocation);
graphics.Transform = matrix;
How can I check for the collisions at the rotated matrix? Can I somehow get the translated X, Y coordinates?
I have some code to transfer points from the standard coordinate system to a specific coordinate system (but in you case, Y increases downards in screen, so some adjusts were made and commented).
Here, the double[] represents a point, where index 0 is X coordinate and index 1 is Y.
Notice the angle of the new coordinate system is measurede counterclockwise and in radians. (Multiply by Pi/180 to transform degrees to radians).
/// <summary>
/// Implemented - Returns the point coordinates related to a new coordinate system
/// Does not change original point
/// </summary>
/// <param name="Point">Point to be returned in new coordinate system</param>
/// <param name="NewSystemCouterClockRotation">CounterClokWise Angle of rotation of the new coordinate system compared to the current, measured in radians</param>
/// <param name="NewSystemOrigin">Location of the new origin point in the current coordinate system</param>
/// <returns></returns>
public double[] ChangeCoordinateSystem(double[] Point, double NewSystemCouterClockRotation, double[] NewSystemOrigin)
{
//first adjust: fix that winform downwards increasing Y before applying the method
Point[1] = -Point[1];
NewSystemOrigin[1] = -NewSystemOrigin[1]
//end of first adjust
//original method
double[] Displacement = new double[2] { Point[0] - NewSystemOrigin[0], Point[1] - NewSystemOrigin[1] };
double[] Result = new double[2]
{
+ Displacement[0] * Math.Cos(NewSystemCouterClockRotation) + Displacement[1] * Math.Sin(NewSystemCouterClockRotation),
- Displacement[0] * Math.Sin(NewSystemCouterClockRotation) + Displacement[1] * Math.Cos(NewSystemCouterClockRotation)
};
//second adjust: reset Y of the result
Result[1] = - Result[1];
return Result;
}
But, if your two objects have different angles, you should be careful, the best way to do that is to check if all four corners of the first of the first rectangle are not inside the other object AND if the other object four corners are not inside the first as well.
Some algorythm to find out if a point is inside a polygon can be found here:
Point in polygon
Based on information in Chapter 7 of 3D Programming For Windows (Charles Petzold), I've attempted to write as helper function that projects a Point3D to a standard 2D Point that contains the corresponding screen coordinates (x,y):
public Point Point3DToScreen2D(Point3D point3D,Viewport3D viewPort )
{
double screenX = 0d, screenY = 0d;
// Camera is defined in XAML as:
// <Viewport3D.Camera>
// <PerspectiveCamera Position="0,0,800" LookDirection="0,0,-1" />
// </Viewport3D.Camera>
PerspectiveCamera cam = viewPort.Camera as PerspectiveCamera;
// Translate input point using camera position
double inputX = point3D.X - cam.Position.X;
double inputY = point3D.Y - cam.Position.Y;
double inputZ = point3D.Z - cam.Position.Z;
double aspectRatio = viewPort.ActualWidth / viewPort.ActualHeight;
// Apply projection to X and Y
screenX = inputX / (-inputZ * Math.Tan(cam.FieldOfView / 2));
screenY = (inputY * aspectRatio) / (-inputZ * Math.Tan(cam.FieldOfView / 2));
// Convert to screen coordinates
screenX = screenX * viewPort.ActualWidth;
screenY = screenY * viewPort.ActualHeight;
// Additional, currently unused, projection scaling factors
/*
double xScale = 1 / Math.Tan(Math.PI * cam.FieldOfView / 360);
double yScale = aspectRatio * xScale;
double zFar = cam.FarPlaneDistance;
double zNear = cam.NearPlaneDistance;
double zScale = zFar == Double.PositiveInfinity ? -1 : zFar / (zNear - zFar);
double zOffset = zNear * zScale;
*/
return new Point(screenX, screenY);
}
On testing however this function returns incorrect screen coordinates (checked by comparing 2D mouse coordinates against a simple 3D shape). Due to my lack of 3D programming experience I am confused as to why.
The block commented section contains scaling calculations that may be essential, however I am not sure how, and the book continues with the MatrixCamera using XAML. Initially I just want to get a basic calculation working regardless of how inefficient it may be compared to Matrices.
Can anyone advise what needs to be added or changed?
I've created and succesfully tested a working method by using the 3DUtils Codeplex source library.
The real work is performed in the TryWorldToViewportTransform() method from 3DUtils. This method will not work without it (see the above link).
Very useful information was also found in the article by Eric Sink: Auto-Zoom.
NB. There may be more reliable/efficient approaches, if so please add them as an answer. In the meantime this is good enough for my needs.
/// <summary>
/// Takes a 3D point and returns the corresponding 2D point (X,Y) within the viewport.
/// Requires the 3DUtils project available at http://www.codeplex.com/Wiki/View.aspx?ProjectName=3DTools
/// </summary>
/// <param name="point3D">A point in 3D space</param>
/// <param name="viewPort">An instance of Viewport3D</param>
/// <returns>The corresponding 2D point or null if it could not be calculated</returns>
public Point? Point3DToScreen2D(Point3D point3D, Viewport3D viewPort)
{
bool bOK = false;
// We need a Viewport3DVisual but we only have a Viewport3D.
Viewport3DVisual vpv =VisualTreeHelper.GetParent(viewPort.Children[0]) as Viewport3DVisual;
// Get the world to viewport transform matrix
Matrix3D m = MathUtils.TryWorldToViewportTransform(vpv, out bOK);
if (bOK)
{
// Transform the 3D point to 2D
Point3D transformedPoint = m.Transform(point3D);
Point screen2DPoint = new Point(transformedPoint.X, transformedPoint.Y);
return new Nullable<Point>(screen2DPoint);
}
else
{
return null;
}
}
Since Windows coordinates are z into the screen (x cross y), I would use something like
screenY = viewPort.ActualHeight * (1 - screenY);
instead of
screenY = screenY * viewPort.ActualHeight;
to correct screenY to accomodate Windows.
Alternately, you could use OpenGL. When you set the viewport x/y/z range, you could leave it in "native" units, and let OpenGL convert to screen coordinates.
Edit:
Since your origin is the center. I would try
screenX = viewPort.ActualWidth * (screenX + 1.0) / 2.0
screenY = viewPort.ActualHeight * (1.0 - ((screenY + 1.0) / 2.0))
The screen + 1.0 converts from [-1.0, 1.0] to [0.0, 2.0]. At which point, you divide by 2.0 to get [0.0, 1.0] for the multiply. To account for Windows y being flipped from Cartesian y, you convert from [1.0, 0.0] (upper left to lower left), to [0.0, 1.0] (upper to lower) by subtracting the previous screen from 1.0. Then, you can scale to the ActualHeight.
This doesn't address the algoritm in question but it may be useful for peple coming across this question (as I did).
In .NET 3.5 you can use Visual3D.TransformToAncestor(Visual ancestor). I use this to draw a wireframe on a canvas over my 3D viewport:
void CompositionTarget_Rendering(object sender, EventArgs e)
{
UpdateWireframe();
}
void UpdateWireframe()
{
GeometryModel3D model = cube.Content as GeometryModel3D;
canvas.Children.Clear();
if (model != null)
{
GeneralTransform3DTo2D transform = cube.TransformToAncestor(viewport);
MeshGeometry3D geometry = model.Geometry as MeshGeometry3D;
for (int i = 0; i < geometry.TriangleIndices.Count;)
{
Polygon p = new Polygon();
p.Stroke = Brushes.Blue;
p.StrokeThickness = 0.25;
p.Points.Add(transform.Transform(geometry.Positions[geometry.TriangleIndices[i++]]));
p.Points.Add(transform.Transform(geometry.Positions[geometry.TriangleIndices[i++]]));
p.Points.Add(transform.Transform(geometry.Positions[geometry.TriangleIndices[i++]]));
canvas.Children.Add(p);
}
}
}
This also takes into account any transforms on the model etc.
See also: http://blogs.msdn.com/wpf3d/archive/2009/05/13/transforming-bounds.aspx
It's not clear what you are trying to achieve with aspectRatio coeff. If the point is on the edge of field of view, then it should be on the edge of screen, but if aspectRatio!=1 it isn't. Try setting aspectRatio=1 and make window square. Are the coordinates still incorrect?
ActualWidth and ActualHeight seem to be half of the window size really, so screenX will be [-ActualWidth; ActualWidth], but not [0; ActualWidth]. Is that what you want?
screenX and screenY should be getting computed relative to screen center ...
I don't see a correction for the fact that when drawing using the Windows API, the origin is in the upper left corner of the screen. I am assuming that your coordinate system is
y
|
|
+------x
Also, is your coordinate system assuming origin in the center, per Scott's question, or is it in the lower left corner?
But, the Windows screen API is
+-------x
|
|
|
y
You would need the coordinate transform to go from classic Cartesian to Windows.