Welcome, guest! Please login or register.

    * Shoutbox

    RefreshHistory
    • stCky: idk man im just a chat bot
      August 22, 2017, 11:14:52 PM
    • symantec: is this forum
      August 22, 2017, 09:02:56 PM
    • symantec: what the fudge
      August 22, 2017, 09:02:52 PM
    • symantec: I just joined to download datmaker, the links are broken and a user named i nelson i has a fudgeing weird signature
      August 22, 2017, 08:59:33 PM
    • stCky: ur so cool and edgy
      August 22, 2017, 04:15:50 PM
    • Deathspirit: anyways, i'm un ip banned now.. but don't even want to be that at this point lmfao
      August 22, 2017, 01:58:14 PM
    • Deathspirit: now it's some sell out half leeched server :')
      August 22, 2017, 01:57:53 PM
    • Deathspirit: gf moparscape, was the best rsps community i've been on since 2006
      August 22, 2017, 01:57:31 PM
    • stCky: yeah, nah. it's cooked. [link] might help u with a backup or something idk man im just a chat bot
      August 22, 2017, 12:13:25 AM
    • flew420: I sure hope someone has a copy of the forum before it was recked
      August 21, 2017, 11:40:52 PM
    • flew420: O wow i see now, just read thru all the news articles. :(  i've been out of the game for a couple years so coming back to this shit is sad.
      August 21, 2017, 11:39:46 PM
    • flew420: Huh?
      August 21, 2017, 10:49:51 PM
    • stCky: got bought by a russian dude, he put a shitty rsps on it for donations, now no one cares
      August 21, 2017, 10:48:30 PM
    • flew420: I came on for some nostalgic reading in old classic development, and it only goes back to 2014 wtf.
      August 21, 2017, 10:43:09 PM
    • flew420: what happened to this site??
      August 21, 2017, 10:42:36 PM
    • Sean56:[link]
      August 21, 2017, 05:33:45 PM
    • kb010: how can i play? i downloaded the client and it doesnt open.
      August 21, 2017, 10:52:56 AM
    • wodkode: shut it down or fix it
      August 20, 2017, 10:11:28 PM
    • wodkode: dude i cant goto no links on here from google
      August 20, 2017, 10:11:13 PM
    • Dell: Greetings
      August 20, 2017, 11:56:30 AM

    Author Topic: 3D Triangle Rasterization Tutorial  (Read 959 times)

    0 Members and 1 Guest are viewing this topic.

    OfflineLimits

    • Member
    • ****
    • Posts: 2,190
    • Thanks: +0/-0
      • View Profile
    3D Triangle Rasterization Tutorial
    « on: July 09, 2015, 12:30:06 AM »

    3D Triangle Rasterization Tutorial
    by Archive


    I decided to split up this tutorial into two sections:


    Goal
    Implementation


    Note that this is a continuation to my previous tutorial, which was basic 3D graphics (wireframe drawing).


    Section 1 : Goal


    The goal for rasterizing triangles is to go from the Y value of the uppermost projected vertex of the triangle to the Y value of the lowest projected vertex of the triangle while filling in the x values within the borders of the triangle.


    Now, you might be wondering how we are going to find the borders of the triangle. Well all we need to do is interpolate the X values between the Y values of each projected vertex.


    Image Key:
    Blue = known vertices of triangle
    Red = the interpolated X values
    White = showing the x-y coordinate plane



    Then after we interpolate the X across the Y, we fill in from X1 to X2.


    Section 2 : Implementation


    First we need to encapsulate a triangle into a class.


    Code: [Select]
    public class Triangle {

    private final List<Vector> vertices;


    private final Vector center;


    public Triangle(List<Vector> vertices) {
    this.vertices = vertices;
    this.center = calculateCenter();
    }


    public List<Vector> getVertices() {
    return vertices;
    }


    public Vector getVertex(int i) {
    return vertices.get(i);
    }


    public Vector calculateCenter() {
    float[] temp = new float[3];


    for (Vector v : vertices) {
    temp[0] += v.getX();
    temp[1] += v.getY();
    temp[2] += v.getZ();
    }


    for (int i = 0; i < temp.length; i++) {
    temp[i] /= vertices.size();
    }


    return new Vector(temp[0], temp[1], temp[2]);
    }


    public void rotate(Matrix mat) {
    for (Vector v : vertices) {
    v.subtract(center);
    }
    for (Vector v : vertices) {
    v.setTo(mat.multiply(v));
    }
    for (Vector v : vertices) {
    v.add(center);
    }
    }


    public void interpret(Vector camera) {
    for (Vector v : vertices) {
    v.interpret(camera);
    }
    }


    public void perspectiveProject() {
    for (Vector v : vertices) {
    v.perspectiveProject();
    }
    }


    public Vector getCenter() {
    return center;
    }


    }


    Beautiful, so now we can create a triangle.


    We need to use interpolation to find the X values right? Well let's implement interpolation.


    I prefer to use an array of the interpolated values rather than doing it as we go for the sake of readability.
    This goes in your utilities file.


    Code: [Select]
                // Lerp is short for "Linear Interpolation" public static float[] lerpList(int steps, float a, float b) {
    if (steps == 0) {
    return new float[] { a };
    }


    float slope = (b - a) / steps;


    float f = a;
    float[] interpolatedValues = new float[steps];
    for (int i = 0; i < steps; i++) {
    interpolatedValues[i] = f;
    f += slope;
    }


    return interpolatedValues;
    }


    So now let's implement the drawing of the triangle.


    Code: [Select]
    public void draw(Surface surface) {


    Vector v1 = vertices.get(0);
    Vector v2 = vertices.get(1);
    Vector v3 = vertices.get(2);


    int color = 0xFFFFFF; // Color of triangle (white)


    float[] x = new float[3]; // (array containing the x values of the projected vertices)
    float[] y = new float[3]; // (array containing the y values of the projected vertices)


    x[0] = v1.getX();
    x[1] = v2.getX();
    x[2] = v3.getX();
    y[0] = v1.getY();
    y[1] = v2.getY();
    y[2] = v3.getY();


                    // Do these swaps to make sure we start drawing from top to bottom
    if (y[0] > y[1]) {
    MathUtil.swap(x, 0, 1);
    MathUtil.swap(y, 0, 1);
    }
    if (y[0] > y[2]) {
    MathUtil.swap(x, 0, 2);
    MathUtil.swap(y, 0, 2);
    }
    if (y[1] > y[2]) {
    MathUtil.swap(x, 1, 2);
    MathUtil.swap(y, 1, 2);
    }
                    // distance (in pixels) between the Y values
    int steps01 = (int) Math.abs(y[1] - y[0]);
    int steps12 = (int) Math.abs(y[2] - y[1]);
    int steps02 = (int) Math.abs(y[2] - y[0]);

    float[] x01 = MathUtil.lerpList(steps01, x[0], x[1]);
    float[] x12 = MathUtil.lerpList(steps12, x[1], x[2]);
    float[] x02 = MathUtil.lerpList(steps02, x[0], x[2]);


                    // from top Y to middle Y
    for (int i = (int) y[0]; i < y[1]; i++) {
    int pos = (int) (i - y[0]); // position in the interpolation lists. Basically what "i" would be if it started from 0
    if (pos >= x01.length) { // don't go out of bounds!
    pos = x01.length - 1;
    }
    surface.drawHorizontalLine((int) x01[pos], (int) x02[pos], i, color);
    }
                    // from middle Y to bottom Y
    for (int i = (int) y[1]; i < y[2]; i++) {
    int pos = (int) (i - y[0]); // same logic however we need to change it for the x12 list.
    int pos1 = (int) (i - y[1]);
    if (pos1 >= x12.length) {
    pos1 = x12.length - 1;
    }
    if (pos >= x02.length) {
    pos = x02.length - 1;
    }
    surface.drawHorizontalLine((int) x12[pos1], (int) x02[pos], i, color);
    }
    }


    Now to prepare/draw the triangle, in the Rasterizer class...


    Code: [Select]
    public void rasterize() {
    display.getSurface().clear();

    Vector camera = new Vector(0, 0, -75);


    List<Vector> vertices = new ArrayList<Vector>();
    vertices.add(new Vector(-5, -5, -10));
    vertices.add(new Vector(10, 10, -10));
    vertices.add(new Vector(-10, 10, -10));


    Triangle tri = new Triangle(vertices);

    Matrix mat = new Matrix();


    x += 0.05f;
    if (x > 6.28f) { //2 pi for full rotation
    x = 0;
    }

    mat.rotateY(x);

    tri.rotate(mat);
    tri.interpret(camera);
    tri.perspectiveProject();

    tri.draw(display.getSurface());
    }


    This is what you should have created from this code (after weaving it into your program):



     

    Copyright © 2017 MoparScape. All rights reserved.
    Powered by SMFPacks SEO Pro Mod |
    SimplePortal 2.3.5 © 2008-2012, SimplePortal