Visibilitas padatan Platonis

Saya melakukan apa yang akan menggambar padatan platonis dengan visibilitas dan bayangan konstan. Saya harus melakukannya tanpa opengl atau directX. Saya sekarang sedang memecahkan visibilitas. Saya mungkin bisa diselesaikan dengan algoritma pelukis tetapi saya tidak tahu bagaimana menerapkannya dalam kode saya. Begitulah cara saya menggambarnya. Jadi saya meminta saran bagaimana menerapkan alghoritma pelukis dalam kode saya. Saya sudah mengetahui sesuatu tentang alghoritma ini - secara teoritis. Dan mungkin cukup melakukan langkah pengurutan wajah berdasarkan koordinat z.

masukkan deskripsi gambar di sini
Untuk proyeksi saya menggunakan matriks proyeksi kelas dan saya memiliki array vertexBuffer dan indexBuffer seperti di OpenGL.
Saya melakukan semuanya di Visual studio 2010 di C#.

Matriks Proyeksi

   using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace KPG3D
{
    /// <summary>
    /// Structure of 3D point
    /// </summary>
    public struct Point3D
    {
        public float X;
        public float Y;
        public float Z;

        public Point3D(float x, float y, float z)
        {
            X = x;
            Y = y;
            Z = z;
        }
    }

    public class ProjectionMatrix
    {
        public float[,] projectionMatrix = new float[4, 4]; //projection matrix

        /// <summary>
        /// Konstructor of projection matrix
        /// </summary>
        public ProjectionMatrix()
        {
            setIdentity();
        }

        /// <summary>
        /// Konstructor of projection matrix
        /// </summary>
        public ProjectionMatrix(float zNear, float zFar, float viewportWidth, float viewportHeight)
        {
            setIdentity();
            float Q = zFar / (zFar - zNear);
            float w = 2 * zNear / viewportWidth;
            float h = 2 * zNear / viewportHeight;

            projectionMatrix[0, 0] = w;
            projectionMatrix[1, 1] = h;
            projectionMatrix[2, 2] = Q;
            projectionMatrix[3, 2] = 1;
            projectionMatrix[2, 3] = -Q * zNear;
        }

        /// <summary>
        /// Konstructor of projection matrix
        /// </summary>
        public ProjectionMatrix(float d, float z)
        {
            setIdentity();//set identity matrix

            projectionMatrix[0, 0] = d / (d - z);
            projectionMatrix[1, 1] = d / (d - z);
            projectionMatrix[2, 2] = 0;
        }

        /// <summary>
        /// Set the matrix to identity
        /// </summary>
        public void setIdentity()
        {
            projectionMatrix[0, 0] = 1;
            projectionMatrix[0, 1] = 0;
            projectionMatrix[0, 2] = 0;
            projectionMatrix[0, 3] = 0;

            projectionMatrix[1, 0] = 0;
            projectionMatrix[1, 1] = 1;
            projectionMatrix[1, 2] = 0;
            projectionMatrix[1, 3] = 0;

            projectionMatrix[2, 0] = 0;
            projectionMatrix[2, 1] = 0;
            projectionMatrix[2, 2] = 1;
            projectionMatrix[2, 3] = 0;

            projectionMatrix[3, 0] = 0;
            projectionMatrix[3, 1] = 0;
            projectionMatrix[3, 2] = 0;
            projectionMatrix[3, 3] = 1;
        }

        /// <summary>
        /// Aplicate projection on set point
        /// </summary>
        /// <param name="p">Point want to transformate</param>
        /// <returns>Transformated point</returns>
        public Point3D multiply(Point3D p)
        {
            Point3D result;

            float tmp = projectionMatrix[3, 0] * p.X + projectionMatrix[3, 1] * p.Y + projectionMatrix[3, 2] * p.Z + projectionMatrix[3, 3] * 1;

            result.X = (projectionMatrix[0, 0] * p.X + projectionMatrix[0, 1] * p.Y + projectionMatrix[0, 2] * p.Z + projectionMatrix[0, 3] * 1) / tmp;
            result.Y = (projectionMatrix[1, 0] * p.X + projectionMatrix[1, 1] * p.Y + projectionMatrix[1, 2] * p.Z + projectionMatrix[1, 3] * 1) / tmp;
            result.Z = (projectionMatrix[2, 0] * p.X + projectionMatrix[2, 1] * p.Y + projectionMatrix[2, 2] * p.Z + projectionMatrix[2, 3] * 1) / tmp;


            return result;
        }
    }
}

Formulir

    using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;


namespace KPG3D
{
    public partial class Form1 : Form
    {
        private Bitmap canvasBitmap; //bitmap of drawing area
        private Graphics g;          //access to graffics

        private List<Point3D> vertexBuffer = new List<Point3D>(); //list of all vertices
        private List<int> indexBuffer = new List<int>();//list of all indices
        private Point3D centroid = new Point3D(0, 0, 0);// center of object

        private ProjectionMatrix projection = null;   //projection matrix

        private bool rotation = false;
        private int objectID = 0;

        public Form1()
        {
            InitializeComponent();

            //create bitmap and set to canvas
            canvasBitmap = new Bitmap(canvas.Width, canvas.Height);
            canvas.Image = canvasBitmap;

            //prepare grafics
            g = Graphics.FromImage(canvasBitmap);
            g.SmoothingMode = SmoothingMode.AntiAlias;


            Matrix origin = new Matrix();
            origin.Translate(canvas.Width / 2, canvas.Height / 2);
            g.Transform = origin;
        }

        /// <summary>
        /// Reaction on click on start button
        /// </summary>
        private void buttonStart_Click(object sender, EventArgs e)
        {
            if (projection == null)
            {
                projection = new ProjectionMatrix(1, 100, 1, 1);
                //createBox();
                //createTetrahedron();
                createChosenObject();
            }

            Timer t = new Timer();
            t.Tick += new EventHandler(timerDrawing);//set tick method
            t.Interval = 30; //every 30 ms
            t.Enabled = true;
            t.Start();
        }


        /// <summary>
        /// Create tetrahedron
        /// </summary>
        private void createTetrahedron() 
        {



            Point3D a = new Point3D(-3,-3, 7);//h
            Point3D b = new Point3D( 3,-3,13);//c
            Point3D c = new Point3D( 3, 3, 7);//a
            Point3D d = new Point3D(-3, 3,13);//f

            vertexBuffer.Add(a);
            vertexBuffer.Add(b);
            vertexBuffer.Add(c);
            vertexBuffer.Add(d);

            //acb
            indexBuffer.Add(0);
            indexBuffer.Add(2);
            indexBuffer.Add(1);

            //adc
            indexBuffer.Add(0);
            indexBuffer.Add(3);
            indexBuffer.Add(2);

            //cdb
            indexBuffer.Add(2);
            indexBuffer.Add(3);
            indexBuffer.Add(1);

            //adb
            indexBuffer.Add(0);
            indexBuffer.Add(3);
            indexBuffer.Add(1);

            centroid = new Point3D(0, 0, 10);
        }


        /// <summary>
        /// Create chosen object
        /// </summary>
        private void createChosenObject() {
            switch (objectID) {
                case 1:
                    createTetrahedron();
                    break;
                case 2:
                    createHexahedron();
                    break;
                case 3:
                    createOctahedron();
                    break;
                case 4:
                    createDodecahedron();
                    break;
                case 5:
                    createIcosahedron();
                    break;
                default:
                    //do nothing
                    break;
            }

        }




        /// <summary>
        /// Rotate direcion vector by the specified angle
        /// </summary>
        /// <param name="vector">Direction vector</param>
        /// <param name="angle">Angle of rotation</param>
        /// <returns></returns>
        private Point3D rotateVector(Point3D vector, Point3D centroid, double angle)
        {
            vector.X -= centroid.X;
            vector.Y -= centroid.Y;
            vector.Z -= centroid.Z;

            Point3D result;
            result.X = vector.X * (float)Math.Cos(angle) - vector.Z * (float)Math.Sin(angle);
            result.Z = vector.X * (float)Math.Sin(angle) + vector.Z * (float)Math.Cos(angle);
            result.Y = vector.Y;

            result.X += centroid.X;
            result.Y += centroid.Y;
            result.Z += centroid.Z;

            return result;
        }




        /// <summary>
        /// Reaction on timer
        /// </summary>
        private void timerDrawing(Object obj, EventArgs ea)
        {

            //rotation of object
            if (rotation == true)
            {
                for (int i = 0; i < vertexBuffer.Count; i++)
                {
                    vertexBuffer[i] = rotateVector(vertexBuffer[i], centroid, 0.02);
                }
            }

            //drawing of object
            draw(vertexBuffer, indexBuffer);


            //refresh what is on canvas
            canvas.Invalidate();
        }

        /// <summary>
        ///Draw point and triangles
        /// </summary>
        /// <param name="vert"></param>
        /// <param name="ind"></param>
        private void draw(List<Point3D> vert, List<int> ind)
        {
            //clear drawing area
            g.Clear(Color.Maroon);

            //prepare pen and brush
            Pen pen = new Pen(Color.Black, 1);
            SolidBrush brush = new SolidBrush(Color.Black);
            SolidBrush faceBrush = new SolidBrush(Color.FromArgb(75, Color.Green));

            //draw edges
            for (int i = 0; i < ind.Count / 3; i++)
            {
                Point3D A = projection.multiply(vert[ind[3 * i + 0]]);
                Point3D B = projection.multiply(vert[ind[3 * i + 1]]);
                Point3D C = projection.multiply(vert[ind[3 * i + 2]]);

                //count to 2D
                PointF a = new PointF(A.X * 200, -A.Y * 200);
                PointF b = new PointF(B.X * 200, -B.Y * 200);
                PointF c = new PointF(C.X * 200, -C.Y * 200);

                g.FillPolygon(faceBrush, new PointF[] { a, b, c });

                //draw triangle
                g.DrawLine(pen, a, b);
                g.DrawLine(pen, b, c);
                g.DrawLine(pen, c, a);
            }

            //draw element
            for (int i = 0; i < vert.Count; i++)
            {



                Point3D p = projection.multiply(vert[i]); //projection from 3D to 2D
                g.FillRectangle(brush, p.X * 200 - 2, -p.Y * 200 - 2, 4, 4);


            }

        }



        /// <summary>
        /// Printscreen to file
        /// </summary>
        private void buttonPrintScreen_Click(object sender, EventArgs e)
        {
            canvas.Image.Save("out.png");
        }

        private void checkBoxRotate_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBoxRotate.Checked) rotation = true;
            else rotation = false;
        }



        private void objectChooser_SelectedIndexChanged(object sender, EventArgs e)
        {
            //set ide of chosen object
            if(objectChooser.SelectedItem.Equals("Tetrahedron")) objectID = 1;
            else if (objectChooser.SelectedItem.Equals("Box")) objectID = 2;
            else if (objectChooser.SelectedItem.Equals("Octahedron")) objectID = 3; 
            else if(objectChooser.SelectedItem.Equals("Dodecahedron")) objectID = 4;
            else if (objectChooser.SelectedItem.Equals("Icosahedron")) objectID = 5; 
        }


    }
}

person user1097772    schedule 11.05.2012    source sumber
comment
Saran seperti apa yang Anda perlukan? Algoritma pelukisnya cukup sederhana. Ide Anda untuk menggunakan penyortiran z sepertinya merupakan langkah pertama yang bagus. Apakah Anda diperbolehkan menerapkan Z-buffer?   -  person RustyTheBoyRobot    schedule 26.05.2012
comment
Tergantung maksud Anda mengimplementasikan Z-buffer - jika saya membuatnya sendiri ya, jika tidak, tidak. Saya tidak bisa menggunakan Z-buffer yang sudah diimplementasikan atau mungkin ada solusi pada GPU - Saya tidak tahu persis apa miliknya tapi saya menggunakannya di OpenGl di beberapa aplikasi lain.   -  person user1097772    schedule 26.05.2012


Jawaban (1)


Jika Anda harus memperhitungkan segitiga yang berpotongan (lihat gambar), menurut saya solusi termudah adalah dengan menggunakan z-buffer (cukup mudah dibuat dan digunakan). Jika Anda tidak harus merender segitiga yang berpotongan, solusi pengurutan z yang Anda usulkan akan lebih sederhana dan akan berfungsi dengan baik.

masukkan deskripsi gambar di sini

person RustyTheBoyRobot    schedule 26.05.2012