Hey Community,
ich brauche etwas Hilfe bei der 3D-Programmierung.
Ich möchte einen einfachen Würfel (später mehrere) darstellen, aber richtig. Das heißt: Ich habe eine AnimationLoop die mit 30fps rendert und updatet. Bevor ich aber zum Würfel komme, wollte ich einfach die drei Koordinatenachsen darstellen (siehe Axes3D.cs).
Diese Klasse wird einmalig instantiiert (mit nem Scaling von (20, 20, 20)) und der AnimationLoop hinzugefügt, sodass halt die Render- und Update-Methode aufgerufen wird.
Interessant ist jetzt in Axes3D.cs die erste Zeile in der Render-Methode, da wird von alle Ecken (Vertices, Typ ist Point3D) eine Methode ToProjectionSpace aufgerufen, die soll halt 3D in 2D umwandeln, unter Berücksichtigung der Zielposition, Skalierung und Rotation der Achsen und des Weiteren der definierten Kamera und Dingen wie FOV und sowas.
Mein Problem ist, dass das ganze vllt richtig aussieht, aber bei Variation der Werte für Rotation und Position falsche Dinge rauskommen. Ich habs mal versucht darzustellen, da sollte sich eig alles um die X-Achse drehen, siehe Anhang.
Gerichtet hab ich mich dabei nach dem MVP Konzept (Model-View-Projection), seit bitte nachsichtig, ich habe wahrscheinlich irgendwas vergessen anzuhängen, fragt dann einfach.
Axes3D.cs
ProjectionSettings.cs
ToProjectionSpace
ich brauche etwas Hilfe bei der 3D-Programmierung.
Ich möchte einen einfachen Würfel (später mehrere) darstellen, aber richtig. Das heißt: Ich habe eine AnimationLoop die mit 30fps rendert und updatet. Bevor ich aber zum Würfel komme, wollte ich einfach die drei Koordinatenachsen darstellen (siehe Axes3D.cs).
Diese Klasse wird einmalig instantiiert (mit nem Scaling von (20, 20, 20)) und der AnimationLoop hinzugefügt, sodass halt die Render- und Update-Methode aufgerufen wird.
Interessant ist jetzt in Axes3D.cs die erste Zeile in der Render-Methode, da wird von alle Ecken (Vertices, Typ ist Point3D) eine Methode ToProjectionSpace aufgerufen, die soll halt 3D in 2D umwandeln, unter Berücksichtigung der Zielposition, Skalierung und Rotation der Achsen und des Weiteren der definierten Kamera und Dingen wie FOV und sowas.
Mein Problem ist, dass das ganze vllt richtig aussieht, aber bei Variation der Werte für Rotation und Position falsche Dinge rauskommen. Ich habs mal versucht darzustellen, da sollte sich eig alles um die X-Achse drehen, siehe Anhang.
Gerichtet hab ich mich dabei nach dem MVP Konzept (Model-View-Projection), seit bitte nachsichtig, ich habe wahrscheinlich irgendwas vergessen anzuhängen, fragt dann einfach.
C#-Quellcode
- public class Axes3D : RenderEntity
- {
- public Axes3D()
- {
- Vertices = new[] {new Point3D(0, 0, 0), new Point3D(1, 0, 0), new Point3D(0, 1, 0), new Point3D(0, 0, 1)};
- Axes = new[] {new[] {0, 1}, new[] {0, 2}, new[] {0, 3}};
- }
- public Point3D[] Vertices { get; set; }
- public int[][] Axes { get; }
- public Point3D TargetPosition
- { get; set; } = Point3D.Origin;
- public Vector3D Scaling
- { get; set; } = Vector3D.One;
- public Vector3D Rotation
- { get; set; } = Vector3D.Zero;
- public override void Update()
- {
- }
- public override void Render(Graphics g)
- {
- //Convert 3D Vertices to ProjectedPoints
- var ver = Vertices.Select(v => v.ToProjectionSpace(TargetPosition, Scaling, Rotation));
- //Converts ProjectedPoints to (positioned) 2DPoints
- var pt2D = ver.Select(v => new Point2D(v.X + ProjectionSettings.CanvasSize.Width / 2f, v.Y + ProjectionSettings.CanvasSize.Height / 2f)).ToArray();
- //EDGES
- var edges = Axes.Select(e => e.Select(i => pt2D[i])).ToArray();
- var pens = new [] {new Pen(Color.Red, 2f), new Pen(Color.Blue, 2f), new Pen(Color.Green, 2f)};
- for(var i = 0; i < edges.Count(); i++)
- g.DrawLine(pens[i], (PointF)edges[i].ToArray()[0], (PointF)edges[i].ToArray()[1]);
- g.FillEllipse(Brushes.Black, pt2D[0].X - 3, pt2D[0].Y - 3, 6, 6);
- }
- }
C#-Quellcode
- public static class ProjectionSettings
- {
- public static Size CanvasSize
- { get; set; } = new Size(100, 100); //wird zu pictureBox1.Size geändert (iwie 600 * 400)
- public static float FieldOfView
- { get; set; } = MathHelper.Deg2Rad(90);
- public static float AspectRatio
- { get; set; } = 1f;
- public static float NearPlane
- { get; set; } = 1f;
- public static float FarPlane
- { get; set; } = 100f;
- public static float Depth => FarPlane - NearPlane;
- }
C#-Quellcode
- /// <summary>
- /// Turns a 3DPoint into a 2DPoint based on all projection factors
- /// </summary>
- /// <param name="p">The 3DPoint in model space</param>
- /// <param name="dest">The destination point in world space</param>
- /// <param name="scale">The scaling</param>
- /// <param name="rot">The rotation</param>
- /// <returns></returns>
- public static ProjectedPoint ToProjectionSpace(this Point3D p, Point3D dest, Vector3D scale, Vector3D rot)
- {
- var model = GetModelMatrix(dest, scale, rot);
- var view = GetViewMatrix();
- var proj = GetProjectionMatrix();
- var mvp = proj * view * model;
- var res = mvp * p;
- return new ProjectedPoint(res.X, res.Y, res.Z);
- }
- /// <summary>
- /// Creates a model matrix based on the model vertices the entity and all transformations to be done
- /// </summary>
- /// <returns>The model matrix.</returns>
- private static Matrix4X4 GetModelMatrix(Point3D destPoint, Vector3D scaling, Vector3D rot)
- {
- //Model matrix
- var translation = Matrix4X4.CreateTranslation(destPoint.X, destPoint.Y, destPoint.Z);
- var scale = Matrix4X4.CreateScale(scaling.X, scaling.Y, scaling.Z);
- var rotation = Matrix4X4.CreateRotationX(rot.X) * Matrix4X4.CreateRotationY(rot.Y) * Matrix4X4.CreateRotationZ(rot.Z);
- var matrix = translation * scale * rotation;
- return matrix;
- }
- /// <summary>
- /// Creates a view (camera) matrix based on the camera position and target and the definition of "up".
- /// </summary>
- /// <returns>The view matrix.</returns>
- private static Matrix4X4 GetViewMatrix()
- {
- var zaxis = Point3D.Connect(Camera.Target, Camera.Position).Normalize();
- var xaxis = (Vector3D.Cross(Camera.UpVector, zaxis)).Normalize();
- var yaxis = Vector3D.Cross(zaxis, xaxis);
- var result = Matrix4X4.Identity;
- result.M11 = xaxis.X;
- result.M12 = yaxis.X;
- result.M13 = zaxis.X;
- result.M14 = 0.0f;
- result.M21 = xaxis.Y;
- result.M22 = yaxis.Y;
- result.M23 = zaxis.Y;
- result.M24 = 0.0f;
- result.M31 = xaxis.Z;
- result.M32 = yaxis.Z;
- result.M33 = zaxis.Z;
- result.M34 = 0.0f;
- result.M41 = -Vector3D.Dot(xaxis, (Vector3D)Camera.Position);
- result.M42 = -Vector3D.Dot(yaxis, (Vector3D)Camera.Position);
- result.M43 = -Vector3D.Dot(zaxis, (Vector3D)Camera.Position);
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Creates a perspective projection matrix based on a field of view, aspect ratio, and near and far view plane distances.
- /// </summary>
- /// <returns>The perspective projection matrix.</returns>
- private static Matrix4X4 GetProjectionMatrix()
- {
- var yScale = 1.0f / (float)Math.Tan(ProjectionSettings.FieldOfView * 0.5f);
- var xScale = yScale / ProjectionSettings.AspectRatio;
- var result = Matrix4X4.Identity;
- result.M11 = xScale;
- result.M12 = result.M13 = result.M14 = 0.0f;
- result.M22 = yScale;
- result.M21 = result.M23 = result.M24 = 0.0f;
- result.M31 = result.M32 = 0.0f;
- result.M33 = ProjectionSettings.FarPlane / -ProjectionSettings.Depth;
- result.M34 = -1.0f;
- result.M41 = result.M42 = result.M44 = 0.0f;
- result.M43 = ProjectionSettings.NearPlane * ProjectionSettings.FarPlane / -ProjectionSettings.Depth;
- return result;
- }
»There's no need to "teach" atheism. It's the natural result of education without indoctrination.« — Ricky Gervais