LostOblivion Skrevet 20. august 2007 Skrevet 20. august 2007 (endret) Hei, Jeg har lurt på dette lenge. Svært enkelt, hvis man hadde en kube med åtte punkter (et i hvert hjørne), hvordan skulle man kunne prosjisere disse 8 punktene (denne 3D-figuren) på en 2D-flate som skal vises av f eks 500x350 piksler. Man skulle også kunne bevege "kamera"punktet rundt i rommet selvfølgelig. Jeg snakker ikke om streker mellom punktene, eller flater og shaders og alt det der (selv om linjer ikke ville vært vanskelig kanskje), men svært enkelt prinsippet bak numerisk beregning av visning av 3D-objekter. Noen som evt har guider til dette. Tenkte å gjøre dette i Java ved å bruke simpel vektorregning, for det er slik man gjør det hva? Altså uten en 3D-API, bare vha Java sin Graphics og Graphics2D objekt. Postet det under generell programmering, siden det ikke egentlig det er Java det er snakk om her. Endret 20. august 2007 av LostOblivion
GeirGrusom Skrevet 20. august 2007 Skrevet 20. august 2007 Tja, dette er ikke egentlig så vanskelig, i sin aller enkleste form er det Point a = Point(vec.x / vec.z, vec.y / z) Men dette gir litt feilberegninger, men er en start. Nå har jeg ikke den eksakte formelen i hode, men jeg skal lete den opp på den egentlige maskinen min (skjermkortet eller AGP porten konka, og så har jeg ikke giddet å gjøre noe med det ) men jeg skal komme tilbake med den. Du burde også kikke på matriser.
LostOblivion Skrevet 20. august 2007 Forfatter Skrevet 20. august 2007 Takk! Men tenkte kanskje at det må være et perspektiv. Som i 50 grader FOV og at kameraet kan bevege seg rundt. Men du sier du kommer tilbake med mer, så takk!
GeirGrusom Skrevet 20. august 2007 Skrevet 20. august 2007 (endret) X / Z, Y / Z gir perspektiv, men det er ikke realistisk perspektiv. For å bevege kameraet bør du bruke matriser, det er den enkleste måten å få det til på. Les om Matriser på Wikipedia eller på GameDev.net Matriser gjør, tro det eller ei, jobben mye enklere for å lage 3D grafikk, og det er ikke så vanskelig som det kan virke ved første øyekast. edit: leif Endret 20. august 2007 av GeirGrusom
-kristoffer- Skrevet 20. august 2007 Skrevet 20. august 2007 Jeg gjorde akkurat dette for endel år siden. Husker ingen formel, men jeg regnet det ut manuelt ved å ta utgangspunkt i at øyet som ser står en bestemt avstand foran skjermen, mens punktet som skal tegnes står ved en bestemt posisjon (høyde, bredde, dybde) "bak" skjermen. Det er egentlig bare å beregne skjæringspunktet til linjen mellom øyet og det andre punktet gjennom skjermflaten. Kom fram til formelen ved å tegne dette opp i en figur og bruke geometri.
GeirGrusom Skrevet 20. august 2007 Skrevet 20. august 2007 Det er en forholdsvis enkel formel, men det er litt Tangens inne i bildet husker jeg
GeirGrusom Skrevet 21. august 2007 Skrevet 21. august 2007 x2 = (x1 * (w / tan(a) ) ) / z + (1/2) * w y2 = (y1 * (h / tan(b) ) ) / z + (1/2) * h hvor a er horisontale radianer, og b er vertikale radianer. og som kjent, er 2PI = 360°, dermed må man mulitplisere med PI / 180 for å gjøre om grader til radianer.
LostOblivion Skrevet 21. august 2007 Forfatter Skrevet 21. august 2007 GeirGrusom. Takk for fine formler, men før jeg kan bruke de, må du nesten forklare hva hver variabel er. Uansett, jeg regnet meg fram til noe jeg tror kan funke ved algebra av vektorer. Altså ved bruk av punktet til "øyet", senter av skjermbildet (flaten), punktet som skal prosjiseres på flaten, og en vektor fra sentrum av skjermbildet som bestemmer hvordan kameraet er rotert... Jeg håper jeg regnet riktig. Gjorde det tre ganger, så er ganske sikker. Jeg kan poste det senere hvis noen skulle være interessert... Finnes sikkert enklere metoder da.
GeirGrusom Skrevet 21. august 2007 Skrevet 21. august 2007 (endret) w, h = størrelsen av "viewporten" i pixels x1, y1, z = Input vektor x2, y2 = resultat punkt a = horisontale vinkelen til "kameraet" i radianer b = vertikale vinkelen til "kameraet" i radianer typedef struct _point { int x; int y; } point; typedef struct _vector { float x; float y; float z; } vector; point ProjectVector(vector * src, float width, float height, float angle) { point ret; float ang = angle * (((float)PI) / 180); ret.x = (int)((src->x * (width / tan(ang) ) ) / src->z + (width / 2)); ret.y = (int)((src->y * (height / tan(ang) ) ) / src->z + (height / 2)); return ret; } Noe slikt skrevet i C Endret 21. august 2007 av GeirGrusom
LostOblivion Skrevet 21. august 2007 Forfatter Skrevet 21. august 2007 (endret) Takk! Hvor fikk du dette fra? Andre ting: I disse formlene må man gå ut ifra noen ting da. Kameraet kan ikke roteres eller flyttes? Endret 21. august 2007 av LostOblivion
GeirGrusom Skrevet 22. august 2007 Skrevet 22. august 2007 Nei, man flytter aldri "kameraet" man flytter hele verden rundt kameraet. Viewporten vil alltid ligge på 0, 0, 0. Som jeg har sagt tidligere, les om matriser, det er det man bruker til å rotere kameraet med
LostOblivion Skrevet 22. august 2007 Forfatter Skrevet 22. august 2007 AHA! Takk for at du gjorde det klart. Man lærer så lenge man lever. :!:
LostOblivion Skrevet 22. august 2007 Forfatter Skrevet 22. august 2007 Hvor kommer field of view inn i bildet da? Eller hva er funksjonen? Takk!
LostOblivion Skrevet 22. august 2007 Forfatter Skrevet 22. august 2007 Sorry for trippelpost... Hvis man skal bevege "kameraet" rundt blir funksjonen sånn her da? Eller er det mer komplisert enn det? x2 = ((x1 - campos.x) * (w / tan(a) ) ) / (z - campos.z) + (1/2) * w y2 = ((y1 - campos.y) * (h / tan(b) ) ) / (z - campos.z) + (1/2) * h Takk!
GeirGrusom Skrevet 22. august 2007 Skrevet 22. august 2007 FOV er A og B i funksjonen, a er horisontal FOV, b er vertikal fov funksjonen er forresten stjålet fra MrMeanies 3D Algorithm Page Man trenger ikke endre denne funksjonen for å rotere. Jeg har skrevet et Matrix klasse i C#, jeg gjetter at den vil fungere i Java med få endringer, ta vekk operator overloading og slikt, men det vet jo du bedre en meg. Klikk for å se/fjerne innholdet nedenfor using System; using System.Collections.Generic; using System.Text; namespace Glorg { using System; public struct FarNear { private float m_far; private float m_near; public float Far { get { return m_far; } set { m_far = value; } } public float Near { get { return m_near; } set { m_near = value; } } public FarNear(float far, float near) { m_far = far; m_near = near; } } /// <summary> /// Matrix class<br /> /// Standard class for manipulating matrices<br /> /// Column major<br /> /// </summary> public class Matrix : System.ICloneable, IComparable { internal float[,] m_mat; /// <summary> /// Default identity matrix /// Multiplying with this matrix is the same as multiplying with 1 i.e. no change. /// </summary> public readonly static Matrix Identity = new Matrix(new float[4, 4] { { 1.0f, .0f, .0f, .0f }, { .0f, 1.0f, .0f, .0f }, { .0f, .0f, 1.0f, .0f }, { .0f, .0f, .0f, 1.0f } }); /// <summary> /// A empty matrix (filled with 0) /// </summary> public readonly static Matrix Empty = new Matrix(new float[4, 4] { { .0f, .0f, .0f, .0f }, { .0f, .0f, .0f, .0f }, { .0f, .0f, .0f, .0f }, { .0f, .0f, .0f, .0f } }); internal static float degreeconv = ((float)Math.PI / 180); /// <summary> /// Gets or sets the translation of the matrix /// </summary> public Vertex Translation { get { return new Vertex(m_mat[0, 3], m_mat[1, 3], m_mat[2, 3]); } set { m_mat[0, 3] = value.X; m_mat[1, 3] = value.Y; m_mat[2, 3] = value.Z; } } /// <summary> /// Sets or gets the scale of the matrix /// </summary> public Vertex Scaling { get { return new Vertex(m_mat[0, 0], m_mat[1, 1], m_mat[2, 2]); } set { m_mat[0, 0] = value.X; m_mat[1, 1] = value.Y; m_mat[2, 2] = value.Z; } } /// <summary> /// Function for copying a matrix into another /// </summary> /// <param name="src"></param> /// <param name="dst"></param> public static void Copy(Matrix src, Matrix dst) { for (int x = 0; x < 4; x++) for (int y = 0; y < 4; y++) dst.m_mat[x, y] = src.m_mat[x, y]; } /// <summary> /// Default constructor /// </summary> public Matrix() { this.m_mat = new float[4, 4]; Matrix.Copy(Matrix.Identity, this); } public void CopyTo(Matrix dst) { Matrix.Copy(this, dst); } /// <summary> /// Constructor for setting values immediatly /// </summary> /// <param name="val">Value of the matrix</param> public Matrix(float[,] val) { m_mat = val; } /// <summary> /// Fills this matrix with the identity matrix /// </summary> public void LoadIdentity() { Matrix.Copy(Matrix.Identity, this); } public void LookAt(Vertex eye, Vertex center, Vertex up) { Matrix new_mat = Matrix.Identity.Clone() as Matrix; center.Normalize(); eye.Normalize(); Vertex f = center - eye; Vertex s; Vertex u; f.Normalize(); s = f * up; u = s * f; new_mat[0, 0] = s.X; new_mat[0, 1] = s.Y; new_mat[0, 2] = s.Z; new_mat[1, 0] = u.X; new_mat[1, 1] = u.Y; new_mat[1, 2] = u.Z; new_mat[2, 0] = -f.X; new_mat[2, 1] = -f.X; new_mat[2, 2] = -f.X; MultiplyMatrix(new_mat); } /// <summary> /// Macro for X rotation in degrees /// </summary> /// <param name="angle">Angle (in degrees)</param> public void RotateDegreeX(float angle) { RotateX(angle * degreeconv); } /// <summary> /// Macro for Y rotation in degrees /// </summary> /// <param name="angle">Angle (in degrees)</param> public void RotateDegreeY(float angle) { RotateY(angle * degreeconv); } /// <summary> /// Macro for Z rotation in degrees /// </summary> /// <param name="angle">Angle (in degees)</param> public void RotateDegreeZ(float angle) { RotateZ(angle * degreeconv); } /// <summary> /// X rotation matrix /// </summary> /// <param name="angle">Angle (in radians)</param> public void RotateX(float angle) { Matrix new_mat = (Matrix)Matrix.Identity.Clone(); new_mat[1, 1] = (float)Math.Cos(angle); new_mat[2, 1] = (float)-Math.Sin(angle); new_mat[1, 2] = -new_mat[2, 1]; new_mat[2, 2] = new_mat[1, 1]; MultiplyMatrix(new_mat); } /// <summary> /// Y rotation matrix /// </summary> /// <param name="angle">Angle (in radians)</param> public void RotateY(float angle) { Matrix new_mat = (Matrix)Matrix.Identity.Clone(); new_mat[0, 0] = (float)Math.Cos(angle); new_mat[2, 0] = (float)Math.Sin(angle); new_mat[0, 2] = -new_mat[2, 0]; new_mat[2, 2] = new_mat[0, 0]; MultiplyMatrix(new_mat); } /// <summary> /// Z rotation matrix /// </summary> /// <param name="angle">Angle (in radians)</param> public void RotateZ(float angle) { Matrix new_mat = (Matrix)Matrix.Identity.Clone(); new_mat[0, 0] = (float)Math.Cos(angle); new_mat[1, 0] = (float)-Math.Sin(angle); new_mat[0, 1] = -new_mat[1, 0]; new_mat[1, 1] = new_mat[0, 0]; MultiplyMatrix(new_mat); } /// <summary> /// Translation matrix /// </summary> /// <param name="offset">Offset values (X, Y and Z)</param> public void Translate(Vertex offset) { Matrix new_mat = Matrix.Identity.Clone() as Matrix; new_mat[3, 0] = offset.X; new_mat[3, 1] = offset.Y; new_mat[3, 2] = offset.Z; MultiplyMatrix(new_mat); } /// <summary> /// Scale matrix /// </summary> /// <param name="scale">X, Y and Z scaling values</param> public void Scale(Vertex scale) { Matrix new_mat = (Matrix)Matrix.Identity.Clone(); new_mat[0, 0] = scale.X; new_mat[1, 1] = scale.Y; new_mat[2, 2] = scale.Z; MultiplyMatrix(new_mat); } public void Ortho(FarNear x, FarNear y, FarNear z) { Ortho(x.Near, x.Far, y.Near, y.Far, z.Near, z.Far); } public unsafe void Ortho(float left, float right, float top, float bottom, float near, float far) { Matrix new_mat = (Matrix)Matrix.Identity.Clone(); new_mat[0, 0] = 2 / (right - left); new_mat[1, 1] = 2 / (top - bottom); new_mat[2, 2] = -2 / (far - near); new_mat[3, 3] = 1; // OpenGL documentation says this should be -1.... // But looking at the matrix OpenGL makes, tells me it should be 1 // [3, 1] and [3, 0] have swapped place new_mat[3, 1] = (right + left) / (right - left); new_mat[3, 0] = (top + bottom) / (top - bottom); new_mat[3, 2] = (far + near) / (far - near); MultiplyMatrix(new_mat); /*float[,] f = new float[4, 4]; OpenGL.NativeOpenGL.glMatrixMode(OpenGL.NativeOpenGL.GL_PROJECTION); OpenGL.NativeOpenGL.glPushMatrix(); OpenGL.NativeOpenGL.glLoadIdentity(); OpenGL.NativeOpenGL.glOrtho(left, right, bottom, top, near, far); fixed (float* ptr = f) OpenGL.NativeOpenGL.glGetFloatv(OpenGL.NativeOpenGL.GL_PROJECTION_MATRIX, ptr); OpenGL.NativeOpenGL.glPopMatrix(); OpenGL.NativeOpenGL.glMatrixMode(OpenGL.NativeOpenGL.GL_MODELVIEW);*/ } /// <summary> /// Frustum matrix /// </summary> /// <param name="x">X clipping plane</param> /// <param name="y">Y clipping plane</param> /// <param name="z">Z clipping plane</param> public void Frustum(FarNear x, FarNear y, FarNear z) { Matrix new_mat = (Matrix)Matrix.Identity.Clone(); new_mat[0, 0] = (2 * z.Near) / (x.Far - x.Near); new_mat[1, 1] = (2 * z.Near) / (y.Near - y.Far); new_mat[2, 0] = (x.Far + x.Near) / (x.Far - x.Near); new_mat[2, 1] = (y.Near + y.Far) / (y.Near - y.Far); new_mat[2, 2] = (z.Far + z.Near) / (z.Far - z.Near); new_mat[3, 2] = (2 * z.Far * z.Near) / (z.Far - z.Near); MultiplyMatrix(new_mat); } /// <summary> /// Left hand field of view perspective matrix /// </summary> /// <param name="fov">Field of view (in degrees)</param> /// <param name="aspect">Aspect ration (should be width/height)</param> /// <param name="zplane">Z clipping plane</param> public void PerspectiveFovLH(float fov, float aspect, FarNear zplane) { float h, w; Matrix new_mat = new Matrix(); h = Cotan((fov * degreeconv) / 2); w = h * aspect; new_mat[0, 0] = w; new_mat[1, 1] = h; new_mat[2, 2] = zplane.Far / (zplane.Far - zplane.Near); new_mat[2, 3] = 1.0f; new_mat[3, 2] = -zplane.Near * zplane.Far / (zplane.Far - zplane.Near); new_mat[3, 3] = 0.0f; MultiplyMatrix(new_mat); } protected static float Cotan(float t) { return 1.0f / (float)Math.Tan(t); } /// <summary> /// Creates a pespective matrix, and multiplies it with itself /// Same mathematics as used in gluPerspective /// </summary> /// <param name="fov">Field of view in Y direction measured in degrees</param> /// <param name="aspect">Aspect ratio (w/h)</param> /// <param name="far">Far clipping plane</param> /// <param name="near">Near clipping plane</param> public void Perspective(float fov, float aspect, float far, float near) { Matrix new_mat = (Matrix)Matrix.Empty.Clone(); // HACK: (Resolved) Inverted FOV in Perspective matrix to render correctly float f = Cotan((fov * degreeconv) / 2); new_mat.m_mat[0, 0] = f / aspect; new_mat.m_mat[1, 1] = f; new_mat.m_mat[2, 2] = (far + near) / (near - far); new_mat.m_mat[3, 2] = (2 * far * near) / (near - far); new_mat.m_mat[2, 3] = -1.0f; MultiplyMatrix(new_mat); } /// <summary> /// Right hand perspective field of view matrix /// </summary> /// <param name="fov">Field of view (in radians)</param> /// <param name="aspect">Aspect ratio (should be width/height)</param> /// <param name="zplane">Z clipping plane</param> public void PerspectiveFovRH(float fov, float aspect, FarNear zplane) { float h, w; Matrix new_mat = new Matrix(); h = Cotan((fov * degreeconv) / 2); w = h * aspect; new_mat[0, 0] = w; new_mat[1, 1] = h; new_mat[2, 2] = zplane.Far / (zplane.Far - zplane.Near); new_mat[2, 3] = -1.0f; new_mat[3, 2] = -zplane.Near * zplane.Far / (zplane.Far - zplane.Near); new_mat[3, 3] = 0.0f; MultiplyMatrix(new_mat); } /// <summary> /// Multplies a matrix with another matrix /// </summary> /// <param name="a">Matrix source a</param> /// <param name="b">Matrixs ource b</param> /// <returns>Result of multiplication</returns> public static Matrix operator *(Matrix a, Matrix b) { Matrix result; result = (Matrix)Matrix.Empty.Clone(); for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) for (int k = 0; k < 4; k++) result.m_mat[i, j] += a.m_mat[i, k] * b.m_mat[k, j]; return result; } /// <summary> /// Multiplies this matrix with another, only used internally /// </summary> /// <param name="other">The target matrix to multiply with</param> protected void MultiplyMatrix(Matrix other) { Matrix result; result = (Matrix)Matrix.Empty.Clone(); for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) for (int k = 0; k < 4; k++) result.m_mat[i, j] += this.m_mat[i, k] * other.m_mat[k, j]; for (int x = 0; x < 4; x++) for (int y = 0; y < 4; y++) this.m_mat[x, y] = result.m_mat[x, y]; } public static Vertex operator *(Vertex vert, Matrix mat) { Vertex v = new Vertex(); v.X = vert.X * mat.m_mat[0, 0] + vert.Y * mat.m_mat[0, 1] + vert.Z * mat.m_mat[0, 2] + mat.m_mat[0, 3]; v.Y = vert.X * mat.m_mat[1, 0] + vert.Y * mat.m_mat[1, 1] + vert.Z * mat.m_mat[1, 2] + mat.m_mat[1, 3]; v.Z = vert.X * mat.m_mat[2, 0] + vert.Y * mat.m_mat[2, 1] + vert.Z * mat.m_mat[2, 2] + mat.m_mat[2, 3]; return v; } public static Vertex operator *(IVertex<float> vert, Matrix mat) { Vertex v = new Vertex(); v.X = vert.X * mat.m_mat[0, 0] + vert.Y * mat.m_mat[0, 1] + vert.Z * mat.m_mat[0, 2] + mat.m_mat[0, 3]; v.Y = vert.X * mat.m_mat[1, 0] + vert.Y * mat.m_mat[1, 1] + vert.Z * mat.m_mat[1, 2] + mat.m_mat[1, 3]; v.Z = vert.X * mat.m_mat[2, 0] + vert.Y * mat.m_mat[2, 1] + vert.Z * mat.m_mat[2, 2] + mat.m_mat[2, 3]; return v; } public Vertex Multiply(IVertex<float> vert) { Vertex v = new Vertex(); v.X = vert.X * m_mat[0, 0] + vert.Y * m_mat[0, 1] + vert.Z * m_mat[0, 2] + m_mat[0, 3]; v.Y = vert.X * m_mat[1, 0] + vert.Y * m_mat[1, 1] + vert.Z * m_mat[1, 2] + m_mat[1, 3]; v.Z = vert.X * m_mat[2, 0] + vert.Y * m_mat[2, 1] + vert.Z * m_mat[2, 2] + m_mat[2, 3]; return v; } public float[,] Array { get { return m_mat; } set { m_mat = value; } } public float[] LinearArray { get { float[] arr = new float[16]; arr[0] = m_mat[0, 0]; arr[1] = m_mat[0, 1]; arr[2] = m_mat[0, 2]; arr[3] = m_mat[0, 3]; arr[4] = m_mat[1, 0]; arr[5] = m_mat[1, 1]; arr[6] = m_mat[1, 2]; arr[7] = m_mat[1, 3]; arr[8] = m_mat[2, 0]; arr[9] = m_mat[2, 1]; arr[10] = m_mat[2, 2]; arr[11] = m_mat[2, 3]; arr[12] = m_mat[3, 0]; arr[13] = m_mat[3, 1]; arr[14] = m_mat[3, 2]; arr[15] = m_mat[3, 3]; return arr; } set { }//m_mat = value; } } public float this[int column, int row] { get { return m_mat[column, row]; } set { m_mat[column, row] = value; } } public override string ToString() { return "matrix{" + m_mat[0, 0].ToString() + ", " + m_mat[0, 1].ToString() + ", " + m_mat[0, 2].ToString() + ", " + m_mat[0, 3].ToString() + ", " + "\n" + m_mat[1, 0].ToString() + ", " + m_mat[1, 1].ToString() + ", " + m_mat[1, 2].ToString() + ", " + m_mat[1, 3].ToString() + ", " + "\n" + m_mat[2, 0].ToString() + ", " + m_mat[2, 1].ToString() + ", " + m_mat[2, 2].ToString() + ", " + m_mat[2, 3].ToString() + ", " + "\n" + m_mat[3, 0].ToString() + ", " + m_mat[3, 1].ToString() + ", " + m_mat[3, 2].ToString() + ", " + m_mat[3, 3].ToString() + "}"; } #region ICloneable Members public object Clone() { Matrix ret = new Matrix(); Matrix.Copy(this, ret); return ret; } #endregion #region IComparable Members public int CompareTo(object obj) { bool result = false; int x, y; for (x = 0; x < 4; x++) for (y = 0; y < 4; y++) result = result && (((Matrix)obj).m_mat[x, y] == m_mat[x, y]); return (result ? 0 : 1); } #endregion } }
Anbefalte innlegg
Opprett en konto eller logg inn for å kommentere
Du må være et medlem for å kunne skrive en kommentar
Opprett konto
Det er enkelt å melde seg inn for å starte en ny konto!
Start en kontoLogg inn
Har du allerede en konto? Logg inn her.
Logg inn nå