Gå til innhold

Anbefalte innlegg

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 av LostOblivion
Lenke til kommentar
Videoannonse
Annonse

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 :p) men jeg skal komme tilbake med den.

 

Du burde også kikke på matriser.

Lenke til kommentar

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 av GeirGrusom
Lenke til kommentar

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.

Lenke til kommentar

GeirGrusom. Takk for fine formler, men før jeg kan bruke de, må du nesten forklare hva hver variabel er. :cool:

 

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. :D

Lenke til kommentar

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 av GeirGrusom
Lenke til kommentar

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
}
}

Lenke til kommentar

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 konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
×
×
  • Opprett ny...