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