From ca5c51f47eb458a7fc1140f97d9faade90563c07 Mon Sep 17 00:00:00 2001 From: Raul Santos Date: Wed, 23 Nov 2022 17:44:30 +0100 Subject: C#: Add Projection documentation - Add documentation to Projection type - Reorder Projection members to be consistent with other C# types --- .../glue/GodotSharp/GodotSharp/Core/Projection.cs | 530 ++++++++++++++------- 1 file changed, 368 insertions(+), 162 deletions(-) (limited to 'modules') diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs index 371729ebec..8b1b73fcc3 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs @@ -3,6 +3,14 @@ using System.Runtime.InteropServices; namespace Godot { + /// + /// A 4x4 matrix used for 3D projective transformations. It can represent transformations such as + /// translation, rotation, scaling, shearing, and perspective division. It consists of four + /// columns. + /// For purely linear transformations (translation, rotation, and scale), it is recommended to use + /// , as it is more performant and has a lower memory footprint. + /// Used internally as 's projection matrix. + /// [Serializable] [StructLayout(LayoutKind.Sequential)] public struct Projection : IEquatable @@ -59,48 +67,107 @@ namespace Godot public Vector4 w; /// - /// Constructs a projection from 4 vectors (matrix columns). + /// Access whole columns in the form of . /// - /// The X column, or column index 0. - /// The Y column, or column index 1. - /// The Z column, or column index 2. - /// The W column, or column index 3. - public Projection(Vector4 x, Vector4 y, Vector4 z, Vector4 w) + /// Which column vector. + /// + /// is not 0, 1, 2 or 3. + /// + public Vector4 this[int column] { - this.x = x; - this.y = y; - this.z = z; - this.w = w; + readonly get + { + switch (column) + { + case 0: + return x; + case 1: + return y; + case 2: + return z; + case 3: + return w; + default: + throw new ArgumentOutOfRangeException(nameof(column)); + } + } + set + { + switch (column) + { + case 0: + x = value; + return; + case 1: + y = value; + return; + case 2: + z = value; + return; + case 3: + w = value; + return; + default: + throw new ArgumentOutOfRangeException(nameof(column)); + } + } } /// - /// Constructs a new from a . + /// Access single values. /// - /// The . - public Projection(Transform3D transform) + /// Which column vector. + /// Which row of the column. + /// + /// or are not 0, 1, 2 or 3. + /// + public real_t this[int column, int row] { - x = new Vector4(transform.basis.Row0.x, transform.basis.Row1.x, transform.basis.Row2.x, 0); - y = new Vector4(transform.basis.Row0.y, transform.basis.Row1.y, transform.basis.Row2.y, 0); - z = new Vector4(transform.basis.Row0.z, transform.basis.Row1.z, transform.basis.Row2.z, 0); - w = new Vector4(transform.origin.x, transform.origin.y, transform.origin.z, 1); + readonly get + { + switch (column) + { + case 0: + return x[row]; + case 1: + return y[row]; + case 2: + return z[row]; + case 3: + return w[row]; + default: + throw new ArgumentOutOfRangeException(nameof(column)); + } + } + set + { + switch (column) + { + case 0: + x[row] = value; + return; + case 1: + y[row] = value; + return; + case 2: + z[row] = value; + return; + case 3: + w[row] = value; + return; + default: + throw new ArgumentOutOfRangeException(nameof(column)); + } + } } /// - /// Constructs a new from the . + /// Creates a new that projects positions from a depth range of + /// -1 to 1 to one that ranges from 0 to 1, and flips the projected + /// positions vertically, according to . /// - /// The . - public static explicit operator Transform3D(Projection proj) - { - return new Transform3D( - new Basis( - new Vector3(proj.x.x, proj.x.y, proj.x.z), - new Vector3(proj.y.x, proj.y.y, proj.y.z), - new Vector3(proj.z.x, proj.z.y, proj.z.z) - ), - new Vector3(proj.w.x, proj.w.y, proj.w.z) - ); - } - + /// If the projection should be flipped vertically. + /// The created projection. public static Projection CreateDepthCorrection(bool flipY) { return new Projection( @@ -111,6 +178,12 @@ namespace Godot ); } + /// + /// Creates a new that scales a given projection to fit around + /// a given in projection space. + /// + /// The AABB to fit the projection around. + /// The created projection. public static Projection CreateFitAabb(AABB aabb) { Vector3 min = aabb.Position; @@ -124,6 +197,25 @@ namespace Godot ); } + /// + /// Creates a new for projecting positions onto a head-mounted display with + /// the given X:Y aspect ratio, distance between eyes, display width, distance to lens, oversampling factor, + /// and depth clipping planes. + /// creates the projection for the left eye when set to 1, + /// or the right eye when set to 2. + /// + /// + /// The eye to create the projection for. + /// The left eye when set to 1, the right eye when set to 2. + /// + /// The aspect ratio. + /// The distance between the eyes. + /// The display width. + /// The distance to the lens. + /// The oversampling factor. + /// The near clipping distance. + /// The far clipping distance. + /// The created projection. public static Projection CreateForHmd(int eye, real_t aspect, real_t intraocularDist, real_t displayWidth, real_t displayToLens, real_t oversample, real_t zNear, real_t zFar) { real_t f1 = (intraocularDist * (real_t)0.5) / displayToLens; @@ -148,6 +240,17 @@ namespace Godot } } + /// + /// Creates a new that projects positions in a frustum with + /// the given clipping planes. + /// + /// The left clipping distance. + /// The right clipping distance. + /// The bottom clipping distance. + /// The top clipping distance. + /// The near clipping distance. + /// The far clipping distance. + /// The created projection. public static Projection CreateFrustum(real_t left, real_t right, real_t bottom, real_t top, real_t near, real_t far) { if (right <= left) @@ -179,6 +282,18 @@ namespace Godot ); } + /// + /// Creates a new that projects positions in a frustum with + /// the given size, X:Y aspect ratio, offset, and clipping planes. + /// determines whether the projection's field of view is flipped over its diagonal. + /// + /// The frustum size. + /// The aspect ratio. + /// The offset to apply. + /// The near clipping distance. + /// The far clipping distance. + /// If the field of view is flipped over the projection's diagonal. + /// The created projection. public static Projection CreateFrustumAspect(real_t size, real_t aspect, Vector2 offset, real_t near, real_t far, bool flipFov) { if (!flipFov) @@ -188,6 +303,11 @@ namespace Godot return CreateFrustum(-size / 2 + offset.x, +size / 2 + offset.x, -size / aspect / 2 + offset.y, +size / aspect / 2 + offset.y, near, far); } + /// + /// Creates a new that projects positions into the given . + /// + /// The Rect2 to project positions into. + /// The created projection. public static Projection CreateLightAtlasRect(Rect2 rect) { return new Projection( @@ -198,6 +318,17 @@ namespace Godot ); } + /// + /// Creates a new that projects positions using an orthogonal projection with + /// the given clipping planes. + /// + /// The left clipping distance. + /// The right clipping distance. + /// The bottom clipping distance. + /// The top clipping distance. + /// The near clipping distance. + /// The far clipping distance. + /// The created projection. public static Projection CreateOrthogonal(real_t left, real_t right, real_t bottom, real_t top, real_t zNear, real_t zFar) { Projection proj = Projection.Identity; @@ -211,6 +342,17 @@ namespace Godot return proj; } + /// + /// Creates a new that projects positions using an orthogonal projection with + /// the given size, X:Y aspect ratio, and clipping planes. + /// determines whether the projection's field of view is flipped over its diagonal. + /// + /// The frustum size. + /// The aspect ratio. + /// The near clipping distance. + /// The far clipping distance. + /// If the field of view is flipped over the projection's diagonal. + /// The created projection. public static Projection CreateOrthogonalAspect(real_t size, real_t aspect, real_t zNear, real_t zFar, bool flipFov) { if (!flipFov) @@ -220,6 +362,17 @@ namespace Godot return CreateOrthogonal(-size / 2, +size / 2, -size / aspect / 2, +size / aspect / 2, zNear, zFar); } + /// + /// Creates a new that projects positions using a perspective projection with + /// the given Y-axis field of view (in degrees), X:Y aspect ratio, and clipping planes. + /// determines whether the projection's field of view is flipped over its diagonal. + /// + /// The vertical field of view (in degrees). + /// The aspect ratio. + /// The near clipping distance. + /// The far clipping distance. + /// If the field of view is flipped over the projection's diagonal. + /// The created projection. public static Projection CreatePerspective(real_t fovyDegrees, real_t aspect, real_t zNear, real_t zFar, bool flipFov) { if (flipFov) @@ -249,6 +402,27 @@ namespace Godot return proj; } + /// + /// Creates a new that projects positions using a perspective projection with + /// the given Y-axis field of view (in degrees), X:Y aspect ratio, and clipping distances. + /// The projection is adjusted for a head-mounted display with the given distance between eyes and distance + /// to a point that can be focused on. + /// creates the projection for the left eye when set to 1, + /// or the right eye when set to 2. + /// determines whether the projection's field of view is flipped over its diagonal. + /// + /// The vertical field of view (in degrees). + /// The aspect ratio. + /// The near clipping distance. + /// The far clipping distance. + /// If the field of view is flipped over the projection's diagonal. + /// + /// The eye to create the projection for. + /// The left eye when set to 1, the right eye when set to 2. + /// + /// The distance between the eyes. + /// The distance to a point of convergence that can be focused on. + /// The created projection. public static Projection CreatePerspectiveHmd(real_t fovyDegrees, real_t aspect, real_t zNear, real_t zFar, bool flipFov, int eye, real_t intraocularDist, real_t convergenceDist) { if (flipFov) @@ -286,6 +460,13 @@ namespace Godot return proj * cm; } + /// + /// Returns a scalar value that is the signed factor by which areas are scaled by this matrix. + /// If the sign is negative, the matrix flips the orientation of the area. + /// The determinant can be used to calculate the invertibility of a matrix or solve linear systems + /// of equations involving the matrix, among other applications. + /// + /// The determinant calculated from this projection. public readonly real_t Determinant() { return x.w * y.z * z.y * w.x - x.z * y.w * z.y * w.x - @@ -302,12 +483,20 @@ namespace Godot x.y * y.x * z.z * w.w + x.x * y.y * z.z * w.w; } + /// + /// Returns the X:Y aspect ratio of this 's viewport. + /// + /// The aspect ratio from this projection's viewport. public readonly real_t GetAspect() { Vector2 vpHe = GetViewportHalfExtents(); return vpHe.x / vpHe.y; } + /// + /// Returns the horizontal field of view of the projection (in degrees). + /// + /// The horizontal field of view of this projection. public readonly real_t GetFov() { Plane rightPlane = new Plane(x.w - x.x, y.w - y.x, z.w - z.x, -w.w + w.x).Normalized(); @@ -322,11 +511,22 @@ namespace Godot } } + /// + /// Returns the vertical field of view of the projection (in degrees) associated with + /// the given horizontal field of view (in degrees) and aspect ratio. + /// + /// The horizontal field of view (in degrees). + /// The aspect ratio. + /// The vertical field of view of this projection. public static real_t GetFovy(real_t fovx, real_t aspect) { return Mathf.RadToDeg(Mathf.Atan(aspect * Mathf.Tan(Mathf.DegToRad(fovx) * (real_t)0.5)) * (real_t)2.0); } + /// + /// Returns the factor by which the visible level of detail is scaled by this . + /// + /// The level of detail factor for this projection. public readonly real_t GetLodMultiplier() { if (IsOrthogonal()) @@ -341,6 +541,12 @@ namespace Godot } } + /// + /// Returns the number of pixels with the given pixel width displayed per meter, after + /// this is applied. + /// + /// The width for each pixel (in meters). + /// The number of pixels per meter. public readonly int GetPixelsPerMeter(int forPixelWidth) { Vector3 result = this * new Vector3(1, 0, -1); @@ -348,6 +554,15 @@ namespace Godot return (int)((result.x * (real_t)0.5 + (real_t)0.5) * forPixelWidth); } + /// + /// Returns the clipping plane of this whose index is given + /// by . + /// should be equal to one of , + /// , , , + /// , or . + /// + /// The kind of clipping plane to get from the projection. + /// The clipping plane of this projection. public readonly Plane GetProjectionPlane(Planes plane) { Plane newPlane = plane switch @@ -364,28 +579,49 @@ namespace Godot return newPlane.Normalized(); } + /// + /// Returns the dimensions of the far clipping plane of the projection, divided by two. + /// + /// The half extents for this projection's far plane. public readonly Vector2 GetFarPlaneHalfExtents() { var res = GetProjectionPlane(Planes.Far).Intersect3(GetProjectionPlane(Planes.Right), GetProjectionPlane(Planes.Top)); return new Vector2(res.Value.x, res.Value.y); } + /// + /// Returns the dimensions of the viewport plane that this + /// projects positions onto, divided by two. + /// + /// The half extents for this projection's viewport plane. public readonly Vector2 GetViewportHalfExtents() { var res = GetProjectionPlane(Planes.Near).Intersect3(GetProjectionPlane(Planes.Right), GetProjectionPlane(Planes.Top)); return new Vector2(res.Value.x, res.Value.y); } + /// + /// Returns the distance for this beyond which positions are clipped. + /// + /// The distance beyond which positions are clipped. public readonly real_t GetZFar() { return GetProjectionPlane(Planes.Far).D; } + /// + /// Returns the distance for this before which positions are clipped. + /// + /// The distance before which positions are clipped. public readonly real_t GetZNear() { return -GetProjectionPlane(Planes.Near).D; } + /// + /// Returns a copy of this with the signs of the values of the Y column flipped. + /// + /// The flipped projection. public readonly Projection FlippedY() { Projection proj = this; @@ -393,6 +629,13 @@ namespace Godot return proj; } + /// + /// Returns a with the near clipping distance adjusted to be + /// . + /// Note: The original must be a perspective projection. + /// + /// The near clipping distance to adjust the projection to. + /// The adjusted projection. public readonly Projection PerspectiveZNearAdjusted(real_t newZNear) { Projection proj = this; @@ -404,6 +647,12 @@ namespace Godot return proj; } + /// + /// Returns a with the X and Y values from the given + /// added to the first and second values of the final column respectively. + /// + /// The offset to apply to the projection. + /// The offseted projection. public readonly Projection JitterOffseted(Vector2 offset) { Projection proj = this; @@ -412,6 +661,11 @@ namespace Godot return proj; } + /// + /// Returns a that performs the inverse of this 's + /// projective transformation. + /// + /// The inverted projection. public readonly Projection Inverse() { Projection proj = this; @@ -535,11 +789,70 @@ namespace Godot return proj; } + /// + /// Returns if this performs an orthogonal projection. + /// + /// If the projection performs an orthogonal projection. public readonly bool IsOrthogonal() { return w.w == (real_t)1.0; } + // Constants + private static readonly Projection _zero = new Projection( + new Vector4(0, 0, 0, 0), + new Vector4(0, 0, 0, 0), + new Vector4(0, 0, 0, 0), + new Vector4(0, 0, 0, 0) + ); + private static readonly Projection _identity = new Projection( + new Vector4(1, 0, 0, 0), + new Vector4(0, 1, 0, 0), + new Vector4(0, 0, 1, 0), + new Vector4(0, 0, 0, 1) + ); + + /// + /// Zero projection, a projection with all components set to 0. + /// + /// Equivalent to new Projection(Vector4.Zero, Vector4.Zero, Vector4.Zero, Vector4.Zero). + public static Projection Zero { get { return _zero; } } + + /// + /// The identity projection, with no distortion applied. + /// This is used as a replacement for Projection() in GDScript. + /// Do not use new Projection() with no arguments in C#, because it sets all values to zero. + /// + /// Equivalent to new Projection(new Vector4(1, 0, 0, 0), new Vector4(0, 1, 0, 0), new Vector4(0, 0, 1, 0), new Vector4(0, 0, 0, 1)). + public static Projection Identity { get { return _identity; } } + + /// + /// Constructs a projection from 4 vectors (matrix columns). + /// + /// The X column, or column index 0. + /// The Y column, or column index 1. + /// The Z column, or column index 2. + /// The W column, or column index 3. + public Projection(Vector4 x, Vector4 y, Vector4 z, Vector4 w) + { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + /// + /// Constructs a new from a . + /// + /// The . + public Projection(Transform3D transform) + { + x = new Vector4(transform.basis.Row0.x, transform.basis.Row1.x, transform.basis.Row2.x, 0); + y = new Vector4(transform.basis.Row0.y, transform.basis.Row1.y, transform.basis.Row2.y, 0); + z = new Vector4(transform.basis.Row0.z, transform.basis.Row1.z, transform.basis.Row2.z, 0); + w = new Vector4(transform.origin.x, transform.origin.y, transform.origin.z, 1); + } + /// /// Composes these two projections by multiplying them /// together. This has the effect of applying the right @@ -646,127 +959,41 @@ namespace Godot } /// - /// Access whole columns in the form of . + /// Constructs a new from the . /// - /// Which column vector. - /// - /// is not 0, 1, 2 or 3. - /// - public Vector4 this[int column] + /// The . + public static explicit operator Transform3D(Projection proj) { - readonly get - { - switch (column) - { - case 0: - return x; - case 1: - return y; - case 2: - return z; - case 3: - return w; - default: - throw new ArgumentOutOfRangeException(nameof(column)); - } - } - set - { - switch (column) - { - case 0: - x = value; - return; - case 1: - y = value; - return; - case 2: - z = value; - return; - case 3: - w = value; - return; - default: - throw new ArgumentOutOfRangeException(nameof(column)); - } - } + return new Transform3D( + new Basis( + new Vector3(proj.x.x, proj.x.y, proj.x.z), + new Vector3(proj.y.x, proj.y.y, proj.y.z), + new Vector3(proj.z.x, proj.z.y, proj.z.z) + ), + new Vector3(proj.w.x, proj.w.y, proj.w.z) + ); } /// - /// Access single values. + /// Returns if the projection is exactly equal + /// to the given object (). /// - /// Which column vector. - /// Which row of the column. - /// - /// or are not 0, 1, 2 or 3. - /// - public real_t this[int column, int row] + /// The object to compare with. + /// Whether or not the vector and the object are equal. + public override readonly bool Equals(object obj) { - readonly get - { - switch (column) - { - case 0: - return x[row]; - case 1: - return y[row]; - case 2: - return z[row]; - case 3: - return w[row]; - default: - throw new ArgumentOutOfRangeException(nameof(column)); - } - } - set - { - switch (column) - { - case 0: - x[row] = value; - return; - case 1: - y[row] = value; - return; - case 2: - z[row] = value; - return; - case 3: - w[row] = value; - return; - default: - throw new ArgumentOutOfRangeException(nameof(column)); - } - } + return obj is Projection other && Equals(other); } - // Constants - private static readonly Projection _zero = new Projection( - new Vector4(0, 0, 0, 0), - new Vector4(0, 0, 0, 0), - new Vector4(0, 0, 0, 0), - new Vector4(0, 0, 0, 0) - ); - private static readonly Projection _identity = new Projection( - new Vector4(1, 0, 0, 0), - new Vector4(0, 1, 0, 0), - new Vector4(0, 0, 1, 0), - new Vector4(0, 0, 0, 1) - ); - - /// - /// Zero projection, a projection with all components set to 0. - /// - /// Equivalent to new Projection(Vector4.Zero, Vector4.Zero, Vector4.Zero, Vector4.Zero). - public static Projection Zero { get { return _zero; } } - /// - /// The identity projection, with no distortion applied. - /// This is used as a replacement for Projection() in GDScript. - /// Do not use new Projection() with no arguments in C#, because it sets all values to zero. + /// Returns if the projections are exactly equal. /// - /// Equivalent to new Projection(new Vector4(1, 0, 0, 0), new Vector4(0, 1, 0, 0), new Vector4(0, 0, 1, 0), new Vector4(0, 0, 0, 1)). - public static Projection Identity { get { return _identity; } } + /// The other projection. + /// Whether or not the projections are exactly equal. + public readonly bool Equals(Projection other) + { + return x == other.x && y == other.y && z == other.z && w == other.w; + } /// /// Serves as the hash function for . @@ -797,26 +1024,5 @@ namespace Godot $"{z.x.ToString(format)}, {z.y.ToString(format)}, {z.z.ToString(format)}, {z.w.ToString(format)}\n" + $"{w.x.ToString(format)}, {w.y.ToString(format)}, {w.z.ToString(format)}, {w.w.ToString(format)}\n"; } - - /// - /// Returns if the projection is exactly equal - /// to the given object (). - /// - /// The object to compare with. - /// Whether or not the vector and the object are equal. - public override readonly bool Equals(object obj) - { - return obj is Projection other && Equals(other); - } - - /// - /// Returns if the projections are exactly equal. - /// - /// The other projection. - /// Whether or not the projections are exactly equal. - public readonly bool Equals(Projection other) - { - return x == other.x && y == other.y && z == other.z && w == other.w; - } } } -- cgit v1.2.3