public _3DModelViewer() { InitializeComponent(); this.simpleOpenGlControl1.InitializeContexts(); Init(); try { file = new ThreeDSFile("./models/Airplane.3ds"); model = file.Model; modelCenter = new Vector((file.MaxX - file.MinX) / 2 + file.MinX, (file.MaxY - file.MinY) / 2 + file.MinY, (file.MaxZ - file.MinZ) / 2 + file.MinZ); // move eye so model is entirely visible at startup modelRotation = new Vector(0, 0, 0); // center x/y at model's center x/y double width = file.MaxX - file.MinX; double height = file.MaxY - file.MinY; eye[0] = Convert.ToSingle(file.MinX + width / 2); eye[1] = Convert.ToSingle(file.MinY + height / 2); // use trigonometry to calculate the z value that exposes the model eye[2] = Convert.ToSingle(file.MaxZ + (width > height ? width : height / 2) / Math.Tan((Math.PI / 180) * 90 / 2)); } catch (Exception ex) { } }
public void TestNormalize() { Vector v = new Vector(12,14,5); Vector v2 = v.Normalize(); Assert.AreEqual(v2.Length(), 1d, 0d); }
/// <summary> /// Calculates the surface normals for all vertices. /// A surface normal is a vector perpendicular to the tangent plane to that surface. /// http://en.wikipedia.org/wiki/Surface_normal /// </summary> public void CalculateNormals() { if ( indices == null ) return; // a normal is created for each vertex normals = new Vector [vertices.Length]; // first let's create a surface normal for each triangle Vector[] temps = new Vector [ indices.Length ]; for ( int ii=0 ; ii < indices.Length ; ii++ ) { Triangle tr = indices [ii]; Vector v1 = vertices [ tr.Vertex1 ] - vertices [ tr.Vertex2 ]; Vector v2 = vertices [ tr.Vertex2 ] - vertices [ tr.Vertex3 ]; temps [ii] = v1.CrossProduct ( v2 ); } // then merge the triangle's vectors for each vertex for ( int ii = 0; ii < vertices.Length ; ii++ ) { // create a new origin vector (0,0,0) Vector v = new Vector (); // we'll do this by looping through all of the triangles for ( int jj = 0; jj < indices.Length ; jj++ ) { Triangle tr = indices [jj]; // and check if this triangle shares this vertex if ( tr.Vertex1 == ii || tr.Vertex2 == ii || tr.Vertex3 == ii ) { // if so, add this vector to our vector // which has the effect of combining the two's magnitude and direction // causing a smoothing effect on the entity v += temps [jj]; } } // finally normalize the vector normals [ii] = v.Normalize (); } normalized = true; }
Vector[] ReadVertices( ThreeDSChunk chunk ) { ushort numVerts = reader.ReadUInt16 (); chunk.BytesRead += 2; Console.WriteLine ( " Vertices: {0}", numVerts ); Vector[] verts = new Vector[numVerts]; for ( int ii=0; ii < verts.Length ; ii++ ) { float f1 = reader.ReadSingle(); float f2 = reader.ReadSingle(); float f3 = reader.ReadSingle(); Vector v = new Vector ( f1, f3, -f2 ); // track the boundaries of this model if (v.X > maxX) maxX = v.X; if (v.Y > maxY) maxY = v.Y; if (v.Z > maxZ) maxZ = v.Z; if (v.X < minX) minX = v.X; if (v.Y < minY) minY = v.Y; if (v.Z < minZ) minZ = v.Z; verts[ii] = v; //Console.WriteLine ( verts [ii] ); } //Console.WriteLine ( "{0} {1}", verts.Length * ( 3 * 4 ), chunk.Length - chunk.BytesRead ); chunk.BytesRead += verts.Length * ( 3 * 4 ) ; //chunk.BytesRead = (int) chunk.Length; //SkipChunk ( chunk ); return verts; }
/// <summary> /// Main method /// </summary> /// <param name="argv"> /// A <see cref="System.String"/> /// </param> public static void Main(string[] argv) { // instantiate GLUT for our windowing provider Glut.glutInit(); //Glut.glutInitDisplayMode(Glut.GLUT_DOUBLE | Glut.GLUT_RGB | Glut.GLUT_ALPHA | Glut.GLUT_DEPTH); Glut.glutInitDisplayMode(Glut.GLUT_DOUBLE | Glut.GLUT_RGB | Glut.GLUT_DEPTH); Glut.glutInitWindowSize( winW, winH ); Glut.glutCreateWindow("Salmon Viewer"); // initialize our OpenGL parameters Init(); // if no arguments, show message if (argv.Length <= 0) { Console.WriteLine("No file was specified."); return; } file = null; switch (Path.GetExtension(argv[0]).ToLower()) { case ".3ds": try { // Load our 3DS model from the command line argument file = new ThreeDSFile( argv[0] ); model = file.Model; } catch (Exception ex) { Console.WriteLine("An Error occured: " + ex.Message); } break; // case ".obj": // new ObjFile(argv[0]); // break; default: Console.WriteLine("Not a supported file type."); break; } modelCenter = new Vector((file.MaxX-file.MinX)/2+file.MinX, (file.MaxY-file.MinY)/2+file.MinY, (file.MaxZ-file.MinZ)/2+file.MinZ); // move eye so model is entirely visible at startup // center x/y at model's center x/y double width = file.MaxX-file.MinX; double height = file.MaxY-file.MinY; eye[0] = Convert.ToSingle(file.MinX+width/2); eye[1] = Convert.ToSingle(file.MinY+height/2); // use trigonometry to calculate the z value that exposes the model eye[2] = Convert.ToSingle(file.MaxZ + (width > height ? width : height / 2) / Math.Tan((Math.PI/180) * 90/2)); // print viewer control keys to Console PrintInstructions(); // instantiate GLUT event handlers Glut.glutDisplayFunc(new Glut.DisplayCallback(Display)); Glut.glutIdleFunc(new Glut.IdleCallback (Idle) ); Glut.glutKeyboardFunc(new Glut.KeyboardCallback(Keyboard)); Glut.glutKeyboardUpFunc(new Glut.KeyboardUpCallback(KeyboardUp)); Glut.glutReshapeFunc(new Glut.ReshapeCallback(Reshape)); Glut.glutMotionFunc (new Glut.MotionCallback (Motion) ); // start loop and wait for user input Glut.glutMainLoop(); }
/// <summary> /// returns a scalar quantity /// </summary> /// <param name="v"> /// A <see cref="Vector"/> /// </param> /// <returns> /// A <see cref="System.Double"/> /// </returns> public double DotProduct( Vector v ) { return X*v.X + Y*v.Y + Z*v.Z; }
/// <summary> /// Returns a vector which is perpendicular to the two vectors /// </summary> /// <param name="v"> /// A <see cref="Vector"/> /// </param> /// <returns> /// A <see cref="Vector"/> /// </returns> public Vector CrossProduct( Vector v ) { return new Vector ( Y * v.Z - Z * v.Y, Z * v.X - X * v.Z, X * v.Y - Y * v.X ); }