How do i reduce memory usage in my C# program? - c#
I'm working on a 3d engine, I recently added a list so that i can sort the triangles of my mesh and render them from furthest away to closest in order to avoid overlapping triangles that shouldn't be there. Ever since i've added this memory usage has shot way up, I'm not sure what to do to fix this however.
I've already tried converting the list to an array and converting it to a linked list but neither gave me the performance i needed.
//#define wireframe
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.IO;
using static System.Diagnostics.Process;
public class Ref<T> // Way around using pointers.
{
private readonly Action<T> setter;
private readonly Func<T> getter;
public Ref(Action<T> setter, Func<T> getter)
{
this.setter = setter;
this.getter = getter;
}
public T Value { get { return getter(); } set { setter(value); } }
}
public class Vector3
{
public float x, y, z;
public Vector3(float xp = 0, float yp = 0, float zp = 0)
{
x = xp;
y = yp;
z = zp;
}
public static Vector3 operator +(Vector3 vec1, Vector3 vec2) => new Vector3(vec1.x + vec2.x, vec1.y + vec2.y, vec1.z + vec2.z);
public static Vector3 operator -(Vector3 vec1, Vector3 vec2) => new Vector3(vec1.x - vec2.x, vec1.y - vec2.y, vec1.z - vec2.z);
public static Vector3 operator *(Vector3 vec1, Vector3 vec2) => new Vector3(vec1.x * vec2.x, vec1.y * vec2.y, vec1.z * vec2.z);
public static Vector3 operator /(Vector3 vec1, Vector3 vec2) => new Vector3(vec1.x / vec2.x, vec1.y / vec2.y, vec1.z / vec2.z);
public static Vector3 operator +(Vector3 vec1, float val) => new Vector3(vec1.x + val, vec1.y + val, vec1.z + val);
public static Vector3 operator -(Vector3 vec1, float val) => new Vector3(vec1.x - val, vec1.y - val, vec1.z - val);
public static Vector3 operator *(Vector3 vec1, float val) => new Vector3(vec1.x * val, vec1.y * val, vec1.z * val);
public static Vector3 operator /(Vector3 vec1, float val) => new Vector3(vec1.x / val, vec1.y / val, vec1.z / val);
};
public class Trig : IComparable<Trig>
{
public List<Vector3> points;
public Color col = Colors.Orange;
public Trig(Vector3 vec1, Vector3 vec2, Vector3 vec3, Color colr)
{
points = new List<Vector3> { vec1, vec2, vec3 };
col = colr;
}
public Trig(Vector3 vec1, Vector3 vec2, Vector3 vec3)
{
points = new List<Vector3> { vec1, vec2, vec3 };
}
public int CompareTo(Trig t2)
{
return (int)((this.points[0].z + this.points[1].z + this.points[2].z) / 3.0f) - (int)((t2.points[0].z + t2.points[1].z + t2.points[2].z) / 3.0f);
}
public Color GetColour(float lum, Color orig) => orig * lum;
};
public class Mesh
{
public List<Trig> tris;
public Mesh(List<Trig> trigs = null)
{
tris = trigs;
}
public void MakeCube(float width = 1, float height = 1, float length = 1)
{
tris = new List<Trig>{
// SOUTH
new Trig(new Vector3(0.0f * width, 0.0f * height, 0.0f * length), new Vector3(0.0f * width, 1.0f * height, 0.0f * length), new Vector3(1.0f * width, 1.0f * height, 0.0f * length)),
new Trig(new Vector3(0.0f * width, 0.0f * height, 0.0f * length), new Vector3(1.0f * width, 1.0f * height, 0.0f * length), new Vector3(1.0f * width, 0.0f * height, 0.0f * length)),
// EAST
new Trig(new Vector3(1.0f * width, 0.0f * height, 0.0f * length), new Vector3(1.0f * width, 1.0f * height, 0.0f * length), new Vector3(1.0f * width, 1.0f * height, 1.0f * length)),
new Trig(new Vector3(1.0f * width, 0.0f * height, 0.0f * length), new Vector3(1.0f * width, 1.0f * height, 1.0f * length), new Vector3(1.0f * width, 0.0f * height, 1.0f * length)),
// NORTH
new Trig(new Vector3(1.0f * width, 0.0f * height, 1.0f * length), new Vector3(1.0f * width, 1.0f * height, 1.0f * length), new Vector3(0.0f * width, 1.0f * height, 1.0f * length)),
new Trig(new Vector3(1.0f * width, 0.0f * height, 1.0f * length), new Vector3(0.0f * width, 1.0f * height, 1.0f * length), new Vector3(0.0f * width, 0.0f * height, 1.0f * length)),
// WEST
new Trig(new Vector3(0.0f * width, 0.0f * height, 1.0f * length), new Vector3(0.0f * width, 1.0f * height, 1.0f * length), new Vector3(0.0f * width, 1.0f * height, 0.0f * length)),
new Trig(new Vector3(0.0f * width, 0.0f * height, 1.0f * length), new Vector3(0.0f * width, 1.0f * height, 0.0f * length), new Vector3(0.0f * width, 0.0f * height, 0.0f * length)),
// TOP
new Trig(new Vector3(0.0f * width, 1.0f * height, 0.0f * length), new Vector3(0.0f * width, 1.0f * height, 1.0f * length), new Vector3(1.0f * width, 1.0f * height, 1.0f * length)),
new Trig(new Vector3(0.0f * width, 1.0f * height, 0.0f * length), new Vector3(1.0f * width, 1.0f * height, 1.0f * length), new Vector3(1.0f * width, 1.0f * height, 0.0f * length)),
// BOTTOM
new Trig(new Vector3(1.0f * width, 0.0f * height, 1.0f * length), new Vector3(0.0f * width, 0.0f * height, 1.0f * length), new Vector3(0.0f * width, 0.0f * height, 0.0f * length)),
new Trig(new Vector3(1.0f * width, 0.0f * height, 1.0f * length), new Vector3(0.0f * width, 0.0f * height, 0.0f * length), new Vector3(1.0f * width, 0.0f * height, 0.0f * length)),
};
}
public bool LoadObjectFromFile(string path)
{
if (!File.Exists(path))
{
return false;
}
else
{
tris = new List<Trig>();
StreamReader file = new StreamReader(path);
List<Vector3> vertCache = new List<Vector3>(); // Cache of verts
string line;
while ((line = file.ReadLine()) != null)
{
if (line != "")
{
if (line[0] == "v"[0])
{
Vector3 v = new Vector3(); // temporary vertex
string[] temp = line.Split(" "[0]); // Split string into array of strings seperated by space
v.x = float.Parse(temp[1]); v.y = float.Parse(temp[2]); v.z = float.Parse(temp[3]); // set temp vertex to the values specified in string.
vertCache.Add(v);
}
if (line[0] == "f"[0])
{
string[] temp = line.Split(" "[0]); // Split string into array of strings seperated by space
tris.Add(new Trig(vertCache[int.Parse(temp[1]) - 1], vertCache[int.Parse(temp[2]) - 1], vertCache[int.Parse(temp[3]) - 1])); // Add a triangle with values from the index specified in string.
}
}
}
Console.WriteLine(tris[0].points[0].x);
file.Close();
return true;
}
}
public void Resize(float x)
{
int counter = 0;
foreach(Trig tri in tris)
{
tris[counter] = new Trig(tri.points[0] * x, tri.points[1] * x, tri.points[2] * x);
counter++;
}
}
public void Resize(float x, float y, float z)
{
int counter = 0;
foreach (Trig tri in tris)
{
Vector3 tempVec = new Vector3(x,y,z);
tris[counter] = new Trig(tri.points[0] * tempVec, tri.points[1] * tempVec, tri.points[2] * tempVec);
counter++;
}
}
};
public class Mat4x
{
public float[,] matrix = new float[4, 4];
public Mat4x()
{
matrix.Initialize();
}
}
public class Camera
{
public Vector3 position = new Vector3();
public float fNear;
public float fFar;
public float fFov;
public float fAspectRatio; // = (float)width / (float)height
public float fFovRad;
public Camera(Vector3 pos, float near = 0.1f, float far = 1000.0f, float fov = 90.0f, float width = 640, float height = 640)
{
position = pos;
fNear = near;
fFar = far;
fFov = fov;
fAspectRatio = width / height;
fFovRad = 1.0f / (float)Math.Tan(fFov * 0.5f / 180.0f * 3.14159f);
}
public float x {get{ return position.x; } set{ position.x = value; }}
public float y { get { return position.y; } set { position.y = value; } }
public float z { get { return position.z; } set { position.z = value; } }
}
public class Light
{
public Vector3 position = new Vector3();
private Vector3 _direction = new Vector3();
public bool isInfinite = false;
public float radius = 1.0f;
public Color col;
public float Normaliser(Vector3 vec)
{
return (float)Math.Sqrt((vec.x * vec.x) + (vec.y * vec.y) + (vec.z * vec.z));
}
public Light(Vector3 dirc, Vector3 pos, Color colr, bool infin = false, float rad = 1.0f)
{
position = pos;
direction = dirc;
isInfinite = infin;
radius = rad;
col = colr;
_direction = new Vector3(dirc.x / Normaliser(dirc), dirc.y / Normaliser(dirc), dirc.z / Normaliser(dirc));
}
public Light(Vector3 dirc, Vector3 pos)
{
position = pos;
direction = dirc;
isInfinite = true;
radius = 0.0f;
col = Colors.WhiteSmoke;
_direction = new Vector3(dirc.x / Normaliser(dirc), dirc.y / Normaliser(dirc), dirc.z / Normaliser(dirc));
}
public Light(Vector3 dirc)
{
direction = dirc;
isInfinite = true;
radius = 0.0f;
col = Colors.WhiteSmoke;
_direction = new Vector3(dirc.x / Normaliser(dirc), dirc.y / Normaliser(dirc), dirc.z / Normaliser(dirc));
}
public float x { get { return position.x; } set { position.x = value; } }
public float y { get { return position.y; } set { position.y = value; } }
public float z { get { return position.z; } set { position.z = value; } }
public Vector3 direction { get => _direction; set => _direction = new Vector3 (value.x / Normaliser(value), value.y / Normaliser(value), value.z / Normaliser(value)); }
}
namespace _2dEngine
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
int height, width;
WriteableBitmap wrBmp;
Mesh cube;
Mat4x matproj, matRotZ, matRotX;
float fTheta, fElapsedTime;
Camera maincam;
Light mainlight;
List<Trig> trigsToDraw = new List<Trig>();
void MultiplyMatrixVector(Vector3 i, Ref<Vector3> o, Mat4x m)
{ // multiply a vector and a 4x matrix to get a vector which we store in o.
Vector3 newVec = new Vector3
{
x = (i.x * m.matrix[0, 0]) + (i.y * m.matrix[1, 0]) + (i.z * m.matrix[2, 0]) + m.matrix[3, 0],
y = (i.x * m.matrix[0, 1]) + (i.y * m.matrix[1, 1]) + (i.z * m.matrix[2, 1]) + m.matrix[3, 1],
z = (i.x * m.matrix[0, 2]) + (i.y * m.matrix[1, 2]) + (i.z * m.matrix[2, 2]) + m.matrix[3, 2]
};
float w = (i.x * m.matrix[0, 3]) + (i.y * m.matrix[1, 3]) + (i.z * m.matrix[2, 3]) + m.matrix[3, 3];
if (w != 0.0f)
{
newVec.x /= w; newVec.y /= w; newVec.z /= w;
}
o.Value = newVec;
//return newVec;
}
void DrawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, Color col)
{
wrBmp.DrawLine(x1, y1, x2, y2, col);
wrBmp.DrawLine(x2, y2, x3, y3, col);
wrBmp.DrawLine(x3, y3, x1, y1, col);
}
void FillTriangle(int x1, int y1, int x2, int y2, int x3, int y3, Color col) => wrBmp.FillTriangle(x1, y1, x2, y2, x3, y3, col);
private void ViewPort_Loaded(object sender, RoutedEventArgs e)
{
matproj = new Mat4x();
matRotZ = new Mat4x();
matRotX = new Mat4x();
width = (int)this.ViewPortContainer.ActualWidth;
height = (int)this.ViewPortContainer.ActualHeight;
wrBmp = BitmapFactory.New(width, height);
ViewPort.Source = wrBmp;
maincam = new Camera(BlankVector3(), width: width, height: height);
mainlight = new Light(new Vector3(0, 0, -1));
cube = new Mesh();
cube.LoadObjectFromFile(#"D:\Users\Electrode\Desktop\Cylinder.obj");
float fNear = 0.1f;
float fFar = 1000.0f;
float fFov = 90.0f;
float fAspectRatio = (float)width / (float)height;
float fFovRad = 1.0f / (float)Math.Tan((double)(fFov * 0.5f / 180.0f * 3.14159f));
fTheta = 1.0f;
matproj.matrix[0, 0] = fAspectRatio * fFovRad;
matproj.matrix[1, 1] = fFovRad;
matproj.matrix[2, 2] = fFar / (fFar - fNear);
matproj.matrix[3, 2] = (-fFar * fNear) / (fFar - fNear);
matproj.matrix[2, 3] = 1.0f;
matproj.matrix[3, 3] = 0.0f;
CompositionTarget.Rendering += CompostitionTarget_Rendering;
}
private void CompostitionTarget_Rendering(object sender, EventArgs e)
{
wrBmp.Clear(Colors.Black);
Trig triRotatedZ, triRotatedZX, triTranslated;
// Rotation Z
matRotZ.matrix[0, 0] = (float)Math.Cos(fTheta);
matRotZ.matrix[0, 1] = (float)Math.Sin(fTheta);
matRotZ.matrix[1, 0] = (float)-Math.Sin(fTheta);
matRotZ.matrix[1, 1] = (float)Math.Cos(fTheta);
matRotZ.matrix[2, 2] = 1;
matRotZ.matrix[3, 3] = 1;
// Rotation X
matRotX.matrix[0, 0] = 1;
matRotX.matrix[1, 1] = (float)Math.Cos(fTheta * 0.5f);
matRotX.matrix[1, 2] = (float)Math.Sin(fTheta * 0.5f);
matRotX.matrix[2, 1] = 0 - (float)Math.Sin(fTheta * 0.5f);
matRotX.matrix[2, 2] = (float)Math.Cos(fTheta * 0.5f);
matRotX.matrix[3, 3] = 1;
fElapsedTime = (float)TimeSpan.FromTicks(DateTime.UtcNow.Ticks - GetCurrentProcess().StartTime.ToUniversalTime().Ticks).TotalSeconds; // Time open in ticks.
// Alternate theta
// fTheta += 1.0f;
fTheta += (1.5f * fElapsedTime / 600) / 4; // Rotate our cube
/// Debug shit
/// Console.WriteLine(fTheta);
foreach (Trig tri in cube.tris) // Iterate through each triangle and render it correctly
{
// setup trigs
triRotatedZ = BlankTrig();
triRotatedZX = BlankTrig();
// Rotate in Z-Axis
MultiplyMatrixVector(tri.points[0], new Ref<Vector3>( // First point rotation
setter: yes => { triRotatedZ.points[0] = yes; }, // our setter for the variable
getter: () => triRotatedZ.points[0]), matRotZ); // our getter
MultiplyMatrixVector(tri.points[1], new Ref<Vector3>( // Second point
setter: yes => { triRotatedZ.points[1] = yes; },
getter: () => triRotatedZ.points[1]), matRotZ);
MultiplyMatrixVector(tri.points[2], new Ref<Vector3>( // Etc
setter: yes => { triRotatedZ.points[2] = yes; },
getter: () => triRotatedZ.points[2]), matRotZ);
// Rotate in X-Axis
MultiplyMatrixVector(triRotatedZ.points[0], new Ref<Vector3>( // See above
setter: yes => { triRotatedZX.points[0] = yes; },
getter: () => triRotatedZX.points[0]), matRotX);
MultiplyMatrixVector(triRotatedZ.points[1], new Ref<Vector3>(
setter: yes => { triRotatedZX.points[1] = yes; },
getter: () => triRotatedZX.points[1]), matRotX);
MultiplyMatrixVector(triRotatedZ.points[2], new Ref<Vector3>(
setter: yes => { triRotatedZX.points[2] = yes; },
getter: () => triRotatedZX.points[2]), matRotX);
// Offset into the screen
triTranslated = triRotatedZX;
triTranslated.points[0].z = triRotatedZX.points[0].z + 120.0f;
triTranslated.points[1].z = triRotatedZX.points[1].z + 120.0f;
triTranslated.points[2].z = triRotatedZX.points[2].z + 120.0f;
// Use Cross-Product to get surface normal
Vector3 normal, line1, line2;
normal = line1 = line2 = BlankVector3();
line1 = triTranslated.points[1] - triTranslated.points[0];
line2 = triTranslated.points[2] - triTranslated.points[0];
normal.x = (line1.y * line2.z) - (line1.z * line2.y);
normal.y = (line1.z * line2.x) - (line1.x * line2.z);
normal.z = (line1.x * line2.y) - (line1.y * line2.x);
// It's normally normal to normalise the normal
float l = (float)Math.Sqrt((normal.x * normal.x) + (normal.y * normal.y) + (normal.z * normal.z));
normal /= l;
if (normal.x * (triTranslated.points[0].x - maincam.x) +
normal.y * (triTranslated.points[0].y - maincam.y) +
normal.z * (triTranslated.points[0].z - maincam.z) < 0.0f)
{
float dp = normal.x * mainlight.direction.x + normal.y * mainlight.direction.y + normal.z * mainlight.direction.z;
triTranslated.col = triTranslated.GetColour(dp, triTranslated.col);
// Project triangle from 3d to 2d
Trig triProj = new Trig(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, 0.0f))
{
col = triTranslated.col
}; // make a blank triangle
MultiplyMatrixVector(triTranslated.points[0], new Ref<Vector3>( // First point projection
setter: yes => { triProj.points[0] = yes; },
getter: () => triProj.points[0]), matproj);
MultiplyMatrixVector(triTranslated.points[1], new Ref<Vector3>( // Second point
setter: yes => { triProj.points[1] = yes; },
getter: () => triProj.points[1]), matproj);
MultiplyMatrixVector(triTranslated.points[2], new Ref<Vector3>( // Etc
setter: yes => { triProj.points[2] = yes; },
getter: () => triProj.points[2]), matproj);
//Scale
triProj.points[0].x += 1.0f; triProj.points[0].y += 1.0f;
triProj.points[1].x += 1.0f; triProj.points[1].y += 1.0f;
triProj.points[2].x += 1.0f; triProj.points[2].y += 1.0f;
triProj.points[0].x *= 0.5f * width;
triProj.points[0].y *= 0.5f * height;
triProj.points[1].x *= 0.5f * width;
triProj.points[1].y *= 0.5f * height;
triProj.points[2].x *= 0.5f * width;
triProj.points[2].y *= 0.5f * height;
trigsToDraw.Add(triProj); // Either this,
}
}
Array.Sort(trigsToDraw.ToArray()); // This,
foreach(Trig triDraw in trigsToDraw) // Or This is causing a performance drop
{
// Draw triangles
FillTriangle(
(int)triDraw.points[0].x,
(int)triDraw.points[0].y,
(int)triDraw.points[1].x,
(int)triDraw.points[1].y,
(int)triDraw.points[2].x,
(int)triDraw.points[2].y,
triDraw.col);
#if (wireframe)
DrawTriangle( // Draw wireframe for debug reasons, if you want.
(int)triDraw.points[0].x,
(int)triDraw.points[0].y,
(int)triDraw.points[1].x,
(int)triDraw.points[1].y,
(int)triDraw.points[2].x,
(int)triDraw.points[2].y,
Color.FromRgb(0, 255, 0));
#endif
}
}
private static Vector3 BlankVector3()
{
return new Vector3();
}
private static Trig BlankTrig()
{
return new Trig(new Vector3(), new Vector3(), new Vector3());
}
}
}
I expect to render a 3D object to my screen without wasting too much memory.
I've worked out the source of the problem
trigsToDraw.Add(triProj); // part 1 of the problem
and
foreach(Trig triDraw in trigsToDraw)
{
// Draw triangles
FillTriangle(
(int)triDraw.points[0].x,
(int)triDraw.points[0].y,
(int)triDraw.points[1].x,
(int)triDraw.points[1].y,
(int)triDraw.points[2].x,
(int)triDraw.points[2].y,
triDraw.col);
#if (wireframe)
DrawTriangle( // Draw wireframe for debug reasons, if you want.
(int)triDraw.points[0].x,
(int)triDraw.points[0].y,
(int)triDraw.points[1].x,
(int)triDraw.points[1].y,
(int)triDraw.points[2].x,
(int)triDraw.points[2].y,
Color.FromRgb(0, 255, 0));
#endif
}// Part 2 of the problem
The reason it used so much memory was because i forgot to clear the list each time...
Sometimes i question my intelligence.
Related
Unable to draw spheres with arbitrary color
I am using SharpGL. I am trying to draw three overlapped spheres with three different colors like the following - However, I am getting output like the following - In other words, the gl.Color() is having no effect on the drawn object. How can I fix this? Source Code: public static class OpenGLhelper { public static void Init(OpenGL gl) { float[] mat_specular = { 1.0f, 1.0f, 1.0f, 1.0f }; float[] mat_shininess = { 50.0f }; float[] light_position = { 0.5f, 0.5f, 0.750f, 0.0f }; gl.ClearColor(0.0f, 0.0f, 0.0f, 0.0f); gl.ShadeModel(OpenGL.GL_SMOOTH); gl.Material(OpenGL.GL_FRONT, OpenGL.GL_SPECULAR, mat_specular); gl.Material(OpenGL.GL_FRONT, OpenGL.GL_SHININESS, mat_shininess); gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_POSITION, light_position); gl.Enable(OpenGL.GL_LIGHTING); gl.Enable(OpenGL.GL_LIGHT0); gl.Enable(OpenGL.GL_DEPTH_TEST); //// Cull back faces. gl.Enable(OpenGL.GL_CULL_FACE); gl.CullFace(OpenGL.GL_BACK); gl.FrontFace(OpenGL.GL_CW); } private static void drawSphere(OpenGL gl, Point3d c, Rgb color, double r, int n) { int i, j; double theta1, theta2, theta3; Point3d e = new Point3d(); Point3d p = new Point3d(); if (c == null) { c = new Point3d(0, 0, 0); } double twoPi = Math.PI * 2; double piD2 = Math.PI / 2; if (r < 0) r = -r; if (n < 0) n = -n; if (n < 4 || r <= 0) { gl.Begin(OpenGL.GL_POINTS); gl.Color(color.Red, color.Green, color.Blue); gl.Vertex(c.X, c.Y, c.Z); gl.End(); return; } for (j = 0; j < n / 2; j++) { theta1 = j * twoPi / n - piD2; theta2 = (j + 1) * twoPi / n - piD2; gl.Begin(OpenGL.GL_QUAD_STRIP); for (i = 0; i <= n; i++) { theta3 = i * twoPi / n; e.X = Math.Cos(theta2) * Math.Cos(theta3); e.Y = Math.Sin(theta2); e.Z = Math.Cos(theta2) * Math.Sin(theta3); p.X = c.X + r * e.X; p.Y = c.Y + r * e.Y; p.Z = c.Z + r * e.Z; gl.Normal(e.X, e.Y, e.Z); gl.TexCoord(i / (double)n, 2 * (j + 1) / (double)n); gl.Color(color.Red, color.Green, color.Blue); gl.Vertex(p.X, p.Y, p.Z); e.X = Math.Cos(theta1) * Math.Cos(theta3); e.Y = Math.Sin(theta1); e.Z = Math.Cos(theta1) * Math.Sin(theta3); p.X = c.X + r * e.X; p.Y = c.Y + r * e.Y; p.Z = c.Z + r * e.Z; gl.Normal(e.X, e.Y, e.Z); gl.TexCoord(i / (double)n, 2 * j / (double)n); gl.Color(color.Red, color.Green, color.Blue); gl.Vertex(p.X, p.Y, p.Z); } gl.End(); } } public static void Display(OpenGL gl) { gl.Clear(OpenGL . GL_COLOR_BUFFER_BIT | OpenGL . GL_DEPTH_BUFFER_BIT); drawSphere(gl, new Point3d(0, 0, 0), new Rgb(1, 0, 0), 0.5, 20); drawSphere(gl, new Point3d(0, 0.5, 0), new Rgb(0, 1, 0), 0.5, 20); drawSphere(gl, new Point3d(0, -0.5, 0), new Rgb(0, 0, 1), 0.5, 20); gl.Flush(); } public static void Reshape(OpenGL gl, int width, int height) { } } public partial class SharpGLForm : Form { private float rotation = 0.0f; public SharpGLForm() { InitializeComponent(); OpenGL gl = openGLControl1.OpenGL; OpenGLhelper.Init(gl); } private void openGLControl_OpenGLDraw(object sender, RenderEventArgs e) { OpenGL gl = openGLControl1.OpenGL; gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); gl.LoadIdentity(); gl.Translate(0.0f, 0.0f, -4.0f); // Move into the screen gl.Rotate(rotation, 0.0f, 1.0f, 0.0f); OpenGLhelper.Display(gl); rotation += 3.0f; } }
When lighting (GL_LIGHTING) is enabled, the render color is defined by the material parameters (glMaterial). If you want to define the color with glColor, you must enable GL_COLOR_MATERIAL and to set the color material parameters (glColorMaterial): gl.Enable(OpenGL.GL_LIGHTING); gl.Enable(OpenGL.GL_COLOR_MATERIAL); gl.ColorMaterial(OpenGL.GL_FRONT_AND_BACK, OpenGL.GL_AMBIENT_AND_DIFFUSE); Alternatively set the material color with GL.Material. e.g.: float[] ambient_diffuse_color = { 1.0f, 0.0f, 0.0f, 1.0f }; // RED GL.Material(OpenGL.GL_FRONT_AND_BACK, OpenGL.GL_AMBIENT_AND_DIFFUSE, ambient_diffuse_color);
Unity: detect click event on UIVertex
I am drawing lines on a canvas using the 'UIVertex' struct and I would like to be able to detect click events on the lines I have drawn. Here is how I draw lines (largely inspired from this tutorial => https://www.youtube.com/watch?v=--LB7URk60A): void DrawVerticesForPoint(Vector2 point, float angle, VertexHelper vh) { vertex = UIVertex.simpleVert; //vertex.color = Color.red; vertex.position = Quaternion.Euler(0, 0, angle) * new Vector3(-thickness / 2, 0); vertex.position += new Vector3(unitWidth * point.x, unitHeight * point.y); vh.AddVert(vertex); vertex.position = Quaternion.Euler(0, 0, angle) * new Vector3(thickness / 2, 0); vertex.position += new Vector3(unitWidth * point.x, unitHeight * point.y); vh.AddVert(vertex); } Any idea?
Here is the solution I have found thanks to this post: public bool PointIsOnLine(Vector3 point, UILineRenderer line) { Vector3 point1 = line.points[0]; Vector3 point2 = line.points[1]; var dirNorm = (point2 - point1).normalized; var t = Vector2.Dot(point - point1, dirNorm); var tClamped = Mathf.Clamp(t, 0, (point2 - point1).magnitude); var closestPoint = point1 + dirNorm * tClamped; var dist = Vector2.Distance(point, closestPoint); if(dist < line.thickness / 2) { return true; } return false; } The UILineRenderer class is the class I have which represents my lines. line.points[0] and line.points[1] contain the coordinates of the two points which determine the line length and position. line.thickness is the... thickness of the line :O
Rotating a PictureBox is cropping the Image
I have problem that image is getting cropped when I execute a function there are images which rotation do and my code: I copied this code from StackOverflow and searched for this quite a long time, so some help would be good I don't know why is cutting the image at every rotation. public static Bitmap RotateImage(Image image, float rotateAtX, float rotateAtY, float angle, bool bNoClip) { int W, H, X, Y; if (bNoClip) { double dW = (double)image.Width; double dH = (double)image.Height; double degrees = Math.Abs(angle); if (degrees <= 90) { double radians = 0.0174532925 * degrees; double dSin = Math.Sin(radians); double dCos = Math.Cos(radians); W = (int)(dH * dSin + dW * dCos); H = (int)(dW * dSin + dH * dCos); X = (W - image.Width) / 2; Y = (H - image.Height) / 2; } else { degrees -= 90; double radians = 0.0174532925 * degrees; double dSin = Math.Sin(radians); double dCos = Math.Cos(radians); W = (int)(dW * dSin + dH * dCos); H = (int)(dH * dSin + dW * dCos); X = (W - image.Width) / 2; Y = (H - image.Height) / 2; } } else { W = image.Width; H = image.Height; X = 0; Y = 0; } //create a new empty bitmap to hold rotated image Bitmap bmpRet = new Bitmap(W, H); bmpRet.SetResolution(image.HorizontalResolution, image.VerticalResolution); //make a graphics object from the empty bitmap Graphics g = Graphics.FromImage(bmpRet); //Put the rotation point in the "center" of the image g.TranslateTransform(rotateAtX + X, rotateAtY + Y); //rotate the image g.RotateTransform(angle); //move the image back g.TranslateTransform(-rotateAtX - X, -rotateAtY - Y); //draw passed in image onto graphics object g.DrawImage(image, new PointF(0 + X, 0 + Y)); return bmpRet; } public static Bitmap RotateImage(Image image, float angle) { // center of the image float rotateAtX = image.Width / 2; float rotateAtY = image.Height / 2; bool bNoClip = false; return RotateImage(image, rotateAtX, rotateAtY, angle, bNoClip); } public static Bitmap RotateImage(Image image, float angle, bool bNoClip) { // center of the image float rotateAtX = image.Width / 2; float rotateAtY = image.Height / 2; return RotateImage(image, rotateAtX, rotateAtY, angle, bNoClip); } private void DOWN_Click(object sender, EventArgs e) { locomotive.Image = RotateImage(locomotive.Image, 35); }
C# - Use of compute shaders
I'm trying to implement, using SharpDX11, a ray/mesh intersection method using the GPU. I've seen from an older post (Older post) that this can be done using the Compute Shader; but I need help in order to create and define the buffer outside the .hlsl code. My HLSL code is the following: struct rayHit { float3 intersection; }; cbuffer cbRaySettings : register(b0) { float3 rayFrom; float3 rayDir; uint TriangleCount; }; StructuredBuffer<float3> positionBuffer : register(t0); StructuredBuffer<uint3> indexBuffer : register(t1); AppendStructuredBuffer<rayHit> appendRayHitBuffer : register(u0); void TestTriangle(float3 p1, float3 p2, float3 p3, out bool hit, out float3 intersection) { //Perform ray/triangle intersection //Compute vectors along two edges of the triangle. float3 edge1, edge2; float distance; //Edge 1 edge1.x = p2.x - p1.x; edge1.y = p2.y - p1.y; edge1.z = p2.z - p1.z; //Edge2 edge2.x = p3.x - p1.x; edge2.y = p3.y - p1.y; edge2.z = p3.z - p1.z; //Cross product of ray direction and edge2 - first part of determinant. float3 directioncrossedge2; directioncrossedge2.x = (rayDir.y * edge2.z) - (rayDir.z * edge2.y); directioncrossedge2.y = (rayDir.z * edge2.x) - (rayDir.x * edge2.z); directioncrossedge2.z = (rayDir.x * edge2.y) - (rayDir.y * edge2.x); //Compute the determinant. float determinant; //Dot product of edge1 and the first part of determinant. determinant = (edge1.x * directioncrossedge2.x) + (edge1.y * directioncrossedge2.y) + (edge1.z * directioncrossedge2.z); //If the ray is parallel to the triangle plane, there is no collision. //This also means that we are not culling, the ray may hit both the //back and the front of the triangle. if (determinant == 0) { distance = 0.0f; intersection = float3(0, 0, 0); hit = false; } float inversedeterminant = 1.0f / determinant; //Calculate the U parameter of the intersection point. float3 distanceVector; distanceVector.x = rayFrom.x - p1.x; distanceVector.y = rayFrom.y - p1.y; distanceVector.z = rayFrom.z - p1.z; float triangleU; triangleU = (distanceVector.x * directioncrossedge2.x) + (distanceVector.y * directioncrossedge2.y) + (distanceVector.z * directioncrossedge2.z); triangleU = triangleU * inversedeterminant; //Make sure it is inside the triangle. if (triangleU < 0.0f || triangleU > 1.0f) { distance = 0.0f; intersection = float3(0, 0, 0); hit = false; } //Calculate the V parameter of the intersection point. float3 distancecrossedge1; distancecrossedge1.x = (distanceVector.y * edge1.z) - (distanceVector.z * edge1.y); distancecrossedge1.y = (distanceVector.z * edge1.x) - (distanceVector.x * edge1.z); distancecrossedge1.z = (distanceVector.x * edge1.y) - (distanceVector.y * edge1.x); float triangleV; triangleV = ((rayDir.x * distancecrossedge1.x) + (rayDir.y * distancecrossedge1.y)) + (rayDir.z * distancecrossedge1.z); triangleV = triangleV * inversedeterminant; //Make sure it is inside the triangle. if (triangleV < 0.0f || triangleU + triangleV > 1.0f) { distance = 0.0f; intersection = float3(0, 0, 0); hit = false; } //Compute the distance along the ray to the triangle. float raydistance; raydistance = (edge2.x * distancecrossedge1.x) + (edge2.y * distancecrossedge1.y) + (edge2.z * distancecrossedge1.z); raydistance = raydistance * inversedeterminant; //Is the triangle behind the ray origin? if (raydistance < 0.0f) { distance = 0.0f; intersection = float3(0, 0, 0); hit = false; } intersection = rayFrom + (rayDir * distance); hit = true; } [numthreads(64, 1, 1)] void CS_RayAppend(uint3 tid : SV_DispatchThreadID) { if (tid.x >= TriangleCount) return; uint3 indices = indexBuffer[tid.x]; float3 p1 = positionBuffer[indices.x]; float3 p2 = positionBuffer[indices.y]; float3 p3 = positionBuffer[indices.z]; bool hit; float3 p; TestTriangle(p1, p2, p3, hit, p); if (hit) { rayHit hitData; hitData.intersection = p; appendRayHitBuffer.Append(hitData); } } While the following is part of my c# implementation but I'm not able to understand how lo load buffers for compute shader. int count = obj.Mesh.Triangles.Count; int size = 8; //int+float for every hit BufferDescription bufferDesc = new BufferDescription() { BindFlags = BindFlags.UnorderedAccess | BindFlags.ShaderResource, Usage = ResourceUsage.Default, CpuAccessFlags = CpuAccessFlags.None, OptionFlags = ResourceOptionFlags.BufferStructured, StructureByteStride = size, SizeInBytes = size * count }; Buffer buffer = new Buffer(device, bufferDesc); UnorderedAccessViewDescription uavDescription = new UnorderedAccessViewDescription() { Buffer = new UnorderedAccessViewDescription.BufferResource() { FirstElement = 0, Flags = UnorderedAccessViewBufferFlags.None, ElementCount = count }, Format = SharpDX.DXGI.Format.Unknown, Dimension = UnorderedAccessViewDimension.Buffer }; UnorderedAccessView uav = new UnorderedAccessView(device, buffer, uavDescription); context.ComputeShader.SetUnorderedAccessView(0, uav); var code = HLSLCompiler.CompileFromFile(#"Shaders\TestTriangle.hlsl", "CS_RayAppend", "cs_5_0"); ComputeShader _shader = new ComputeShader(device, code); Buffer positionsBuffer = new Buffer(device, Utilities.SizeOf<Vector3>(), ResourceUsage.Default, BindFlags.None, CpuAccessFlags.None, ResourceOptionFlags.None, 0); context.UpdateSubresource(ref data, positionsBuffer); context.ComputeShader.Set(_shader); Inside my c# implementation i'm considering only one ray (with its origin and direction) and I would like to use the shader to check the intersection with all the triangles of the mesh. I'm already able to do that using the CPU but for 20k+ triangles the computation took too long even if i'm already using parallel coding.
Going from a cube to a pyramid in visual studio using C#?
Hey everyone im trying to figure out how to make a 3D pyramid out of existing code that is already a 3D cube in visual studio by changing some of the code. I've been messing around with the verts as my friend suggested but I am still unsuccessful. Here is the code.. // ================================================ // | Downloaded From | // | Visual C# Kicks - http://www.vcskicks.com/ | // ================================================ using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Drawing.Imaging; using System.Drawing.Drawing2D; namespace EulerRotation { public partial class Form1 : Form { Cube cube; public Form1() { InitializeComponent(); } private void btnReset_Click(object sender, EventArgs e) { tX.Value = 0; tY.Value = 0; tZ.Value = 0; render(); } private void Form1_Load(object sender, EventArgs e) { cube = new Cube(100); render(); } private void render() { //Set the rotation values cube.RotateX = tX.Value; cube.RotateY = tY.Value; cube.RotateZ = tZ.Value; //Cube is positioned based on center Point origin = new Point(picCube.Width / 2, picCube.Height / 2); picCube.Image = cube.drawCube(origin); } private void tX_Scroll(object sender, EventArgs e) { render(); } private void tY_Scroll(object sender, EventArgs e) { render(); } private void tZ_Scroll(object sender, EventArgs e) { render(); } } internal class Math3D { public class Point3D { //The Point3D class is rather simple, just keeps track of X Y and Z values, //and being a class it can be adjusted to be comparable public double X; public double Y; public double Z; public Point3D(int x, int y, int z) { X = x; Y = y; Z = z; } public Point3D(float x, float y, float z) { X = (double)x; Y = (double)y; Z = (double)z; } public Point3D(double x, double y, double z) { X = x; Y = y; Z = z; } public Point3D() { } public override string ToString() { return "(" + X.ToString() + ", " + Y.ToString() + ", " + Z.ToString() + ")"; } } public class Camera { //For 3D drawing we need a point of perspective, thus the Camera public Point3D Position = new Point3D(); } public static Point3D RotateX(Point3D point3D, double degrees) { //Here we use Euler's matrix formula for rotating a 3D point x degrees around the x-axis //[ a b c ] [ x ] [ x*a + y*b + z*c ] //[ d e f ] [ y ] = [ x*d + y*e + z*f ] //[ g h i ] [ z ] [ x*g + y*h + z*i ] //[ 1 0 0 ] //[ 0 cos(x) sin(x)] //[ 0 -sin(x) cos(x)] double cDegrees = (Math.PI * degrees) / 180.0f; //Convert degrees to radian for .Net Cos/Sin functions double cosDegrees = Math.Cos(cDegrees); double sinDegrees = Math.Sin(cDegrees); double y = (point3D.Y * cosDegrees) + (point3D.Z * sinDegrees); double z = (point3D.Y * -sinDegrees) + (point3D.Z * cosDegrees); return new Point3D(point3D.X, y, z); } public static Point3D RotateY(Point3D point3D, double degrees) { //Y-axis //[ cos(x) 0 sin(x)] //[ 0 1 0 ] //[-sin(x) 0 cos(x)] double cDegrees = (Math.PI * degrees) / 180.0; //Radians double cosDegrees = Math.Cos(cDegrees); double sinDegrees = Math.Sin(cDegrees); double x = (point3D.X * cosDegrees) + (point3D.Z * sinDegrees); double z = (point3D.X * -sinDegrees) + (point3D.Z * cosDegrees); return new Point3D(x, point3D.Y, z); } public static Point3D RotateZ(Point3D point3D, double degrees) { //Z-axis //[ cos(x) sin(x) 0] //[ -sin(x) cos(x) 0] //[ 0 0 1] double cDegrees = (Math.PI * degrees) / 180.0; //Radians double cosDegrees = Math.Cos(cDegrees); double sinDegrees = Math.Sin(cDegrees); double x = (point3D.X * cosDegrees) + (point3D.Y * sinDegrees); double y = (point3D.X * -sinDegrees) + (point3D.Y * cosDegrees); return new Point3D(x, y, point3D.Z); } public static Point3D Translate(Point3D points3D, Point3D oldOrigin, Point3D newOrigin) { //Moves a 3D point based on a moved reference point Point3D difference = new Point3D(newOrigin.X - oldOrigin.X, newOrigin.Y - oldOrigin.Y, newOrigin.Z - oldOrigin.Z); points3D.X += difference.X; points3D.Y += difference.Y; points3D.Z += difference.Z; return points3D; } //These are to make the above functions workable with arrays of 3D points public static Point3D[] RotateX(Point3D[] points3D, double degrees) { for (int i = 0; i < points3D.Length; i++) { points3D[i] = RotateX(points3D[i], degrees); } return points3D; } public static Point3D[] RotateY(Point3D[] points3D, double degrees) { for (int i = 0; i < points3D.Length; i++) { points3D[i] = RotateY(points3D[i], degrees); } return points3D; } public static Point3D[] RotateZ(Point3D[] points3D, double degrees) { for (int i = 0; i < points3D.Length; i++) { points3D[i] = RotateZ(points3D[i], degrees); } return points3D; } public static Point3D[] Translate(Point3D[] points3D, Point3D oldOrigin, Point3D newOrigin) { for (int i = 0; i < points3D.Length; i++) { points3D[i] = Translate(points3D[i], oldOrigin, newOrigin); } return points3D; } } internal class Cube { //Example cube class to demonstrate the use of 3D points and 3D rotation public int width = 0; public int height = 0; public int depth = 0; double xRotation = 0.0; double yRotation = 0.0; double zRotation = 0.0; Math3D.Camera camera1 = new Math3D.Camera(); Math3D.Point3D cubeOrigin; public double RotateX { get { return xRotation; } set { xRotation = value; } } public double RotateY { get { return yRotation; } set { yRotation = value; } } public double RotateZ { get { return zRotation; } set { zRotation = value; } } public Cube(int side) { width = side; height = side; depth = side; cubeOrigin = new Math3D.Point3D(width / 2, height / 2, depth / 2); } public Cube(int side, Math3D.Point3D origin) { width = side; height = side; depth = side; cubeOrigin = origin; } public Cube(int Width, int Height, int Depth) { width = Width; height = Height; depth = Depth; cubeOrigin = new Math3D.Point3D(width / 2, height / 2, depth / 2); } public Cube(int Width, int Height, int Depth, Math3D.Point3D origin) { width = Width; height = Height; depth = Depth; cubeOrigin = origin; } //Finds the othermost points. Used so when the cube is drawn on a bitmap, //the bitmap will be the correct size public static Rectangle getBounds(PointF[] points) { double left = points[0].X; double right = points[0].X; double top = points[0].Y; double bottom = points[0].Y; for (int i = 1; i < points.Length; i++) { if (points[i].X < left) left = points[i].X; if (points[i].X > right) right = points[i].X; if (points[i].Y < top) top = points[i].Y; if (points[i].Y > bottom) bottom = points[i].Y; } return new Rectangle(0, 0, (int)Math.Round(right - left), (int)Math.Round(bottom - top)); } public Bitmap drawCube(Point drawOrigin) { //FRONT FACE //Top Left - 7 //Top Right - 4 //Bottom Left - 6 //Bottom Right - 5 //Vars PointF[] point3D = new PointF[24]; //Will be actual 2D drawing points Point tmpOrigin = new Point(0, 0); Math3D.Point3D point0 = new Math3D.Point3D(0, 0, 0); //Used for reference //Zoom factor is set with the monitor width to keep the cube from being distorted double zoom = (double)Screen.PrimaryScreen.Bounds.Width / 1.5; //Set up the cube Math3D.Point3D[] cubePoints = fillCubeVertices(width, height, depth); //Calculate the camera Z position to stay constant despite rotation Math3D.Point3D anchorPoint = (Math3D.Point3D)cubePoints[4]; //anchor point double cameraZ = -(((anchorPoint.X - cubeOrigin.X) * zoom) / cubeOrigin.X) + anchorPoint.Z; camera1.Position = new Math3D.Point3D(cubeOrigin.X, cubeOrigin.Y, cameraZ); //Apply Rotations, moving the cube to a corner then back to middle cubePoints = Math3D.Translate(cubePoints, cubeOrigin, point0); cubePoints = Math3D.RotateX(cubePoints, xRotation); //The order of these cubePoints = Math3D.RotateY(cubePoints, yRotation); //rotations is the source cubePoints = Math3D.RotateZ(cubePoints, zRotation); //of Gimbal Lock cubePoints = Math3D.Translate(cubePoints, point0, cubeOrigin); //Convert 3D Points to 2D Math3D.Point3D vec; for (int i = 0; i < point3D.Length; i++) { vec = cubePoints[i]; if (vec.Z - camera1.Position.Z >= 0) { point3D[i].X = (int)((double)-(vec.X - camera1.Position.X) / (-0.1f) * zoom) + drawOrigin.X; point3D[i].Y = (int)((double)(vec.Y - camera1.Position.Y) / (-0.1f) * zoom) + drawOrigin.Y; } else { tmpOrigin.X = (int)((double)(cubeOrigin.X - camera1.Position.X) / (double)(cubeOrigin.Z - camera1.Position.Z) * zoom) + drawOrigin.X; tmpOrigin.Y = (int)((double)-(cubeOrigin.Y - camera1.Position.Y) / (double)(cubeOrigin.Z - camera1.Position.Z) * zoom) + drawOrigin.Y; point3D[i].X = (float)((vec.X - camera1.Position.X) / (vec.Z - camera1.Position.Z) * zoom + drawOrigin.X); point3D[i].Y = (float)(-(vec.Y - camera1.Position.Y) / (vec.Z - camera1.Position.Z) * zoom + drawOrigin.Y); point3D[i].X = (int)point3D[i].X; point3D[i].Y = (int)point3D[i].Y; } } //Now to plot out the points Rectangle bounds = getBounds(point3D); bounds.Width += drawOrigin.X; bounds.Height += drawOrigin.Y; Bitmap tmpBmp = new Bitmap(bounds.Width, bounds.Height); Graphics g = Graphics.FromImage(tmpBmp); //Back Face g.DrawLine(Pens.Black, point3D[0], point3D[1]); g.DrawLine(Pens.Black, point3D[1], point3D[2]); g.DrawLine(Pens.Black, point3D[2], point3D[3]); g.DrawLine(Pens.Black, point3D[3], point3D[0]); //Front Face g.DrawLine(Pens.Black, point3D[4], point3D[5]); g.DrawLine(Pens.Black, point3D[5], point3D[6]); g.DrawLine(Pens.Black, point3D[6], point3D[7]); g.DrawLine(Pens.Black, point3D[7], point3D[4]); //Right Face g.DrawLine(Pens.Black, point3D[8], point3D[9]); g.DrawLine(Pens.Black, point3D[9], point3D[10]); g.DrawLine(Pens.Black, point3D[10], point3D[11]); g.DrawLine(Pens.Black, point3D[11], point3D[8]); //Left Face g.DrawLine(Pens.Black, point3D[12], point3D[13]); g.DrawLine(Pens.Black, point3D[13], point3D[14]); g.DrawLine(Pens.Black, point3D[14], point3D[15]); g.DrawLine(Pens.Black, point3D[15], point3D[12]); //Bottom Face g.DrawLine(Pens.Black, point3D[16], point3D[17]); g.DrawLine(Pens.Black, point3D[17], point3D[18]); g.DrawLine(Pens.Black, point3D[18], point3D[19]); g.DrawLine(Pens.Black, point3D[19], point3D[16]); //Top Face g.DrawLine(Pens.Black, point3D[20], point3D[21]); g.DrawLine(Pens.Black, point3D[21], point3D[22]); g.DrawLine(Pens.Black, point3D[22], point3D[23]); g.DrawLine(Pens.Black, point3D[23], point3D[20]); g.Dispose(); //Clean-up return tmpBmp; } public static Math3D.Point3D[] fillCubeVertices(int width, int height, int depth) { Math3D.Point3D[] verts = new Math3D.Point3D[24]; //front face verts[0] = new Math3D.Point3D(0, 0, 0); verts[1] = new Math3D.Point3D(0, height, 0); verts[2] = new Math3D.Point3D(width, height, 0); verts[3] = new Math3D.Point3D(width, 0, 0); //back face verts[4] = new Math3D.Point3D(0, 0, depth); verts[5] = new Math3D.Point3D(0, height, depth); verts[6] = new Math3D.Point3D(width, height, depth); verts[7] = new Math3D.Point3D(width, 0, depth); //left face verts[8] = new Math3D.Point3D(0, 0, 0); verts[9] = new Math3D.Point3D(0, 0, depth); verts[10] = new Math3D.Point3D(0, height, depth); verts[11] = new Math3D.Point3D(0, height, 0); //right face verts[12] = new Math3D.Point3D(width, 0, 0); verts[13] = new Math3D.Point3D(width, 0, depth); verts[14] = new Math3D.Point3D(width, height, depth); verts[15] = new Math3D.Point3D(width, height, 0); //top face verts[16] = new Math3D.Point3D(0, height, 0); verts[17] = new Math3D.Point3D(0, height, depth); verts[18] = new Math3D.Point3D(width, height, depth); verts[19] = new Math3D.Point3D(width, height, 0); //bottom face verts[20] = new Math3D.Point3D(0, 0, 0); verts[21] = new Math3D.Point3D(0, 0, depth); verts[22] = new Math3D.Point3D(width, 0, depth); verts[23] = new Math3D.Point3D(width, 0, 0); return verts; } } } Right now when I run this code in visual studio 2015 it creates a 3D cube but how do i modify it to where I can get a pyramid?