CODE SAMPLE - SIMPLE TRIANGLE Rasterizer
This is a simple software triangle rasterizer using just set-pixel.
It takes 3 vertices in screen space and renders a triangle between them. To the right is an example of how this rasterizer can be used to render a 3D scene. All the models in the scene to the right were stored in world space then before being rendered were translated to screen space and rendered with this function. |
// // Rasterize a Simple Triangle // void DrawTri(Vertex v1, Vertex v2, Vertex v3, unsigned char * texture, unsigned char drawtype) { //T for Top, M for Middle, B for Bottom //Note: Short var names for readability Vertex T, M, B; bool Left; //find which vertex is the T, M and B getTMB(v1, v2, v3, T, M, B, Left); float xL, xR; //Set to top xL = T.pos.x; xR = T.pos.x; int x, y; float mR, mL; //Top Half //Calc inverse slopes if(Left){ mL = (M.pos.x - T.pos.x) / (float)(M.pos.y - T.pos.y); mR = (B.pos.x - T.pos.x) / (float)(B.pos.y - T.pos.y); } else{ mL = (B.pos.x - T.pos.x) / (float)(B.pos.y - T.pos.y); mR = (M.pos.x - T.pos.x) / (float)(M.pos.y - T.pos.y); } //Preping for cross product to find abc for to get the increments Vector3 VecU, VecV; VecU.x = (float)M.pos.x - T.pos.x; VecU.y = (float)M.pos.y - T.pos.y; VecU.z = M.color.r - T.color.r; VecV.x = (float)B.pos.x - T.pos.x; VecV.y = (float)B.pos.y - T.pos.y; VecV.z = B.color.r - T.color.r; Vector3 vR = Vector3::cross(VecU, VecV); //since the z is the only thing that changes we only need to update .z VecU.z = M.color.g - T.color.g; VecV.z = B.color.g - T.color.g; Vector3 vG = Vector3::cross(VecU, VecV); VecU.z = M.color.b - T.color.b; VecV.z = B.color.b - T.color.b; Vector3 vB = Vector3::cross(VecU, VecV); VecU.z = M.uv.x - T.uv.x; VecV.z = B.uv.x - T.uv.x; Vector3 vtcU = Vector3::cross(VecU, VecV); VecU.z = M.uv.y - T.uv.y; VecV.z = B.uv.y - T.uv.y; Vector3 vtcV = Vector3::cross(VecU, VecV); float innerR, innerG, innerB, innerV, innerU; //inner increment for r,g,b, V and U float outerR, outerG, outerB, outerV, outerU; //outer increment //calculating the OUTER RGB increments outerR = (-vR.x * (float)mL - vR.y) / vR.z; outerG = (-vG.x * (float)mL - vG.y) / vG.z; outerB = (-vB.x * (float)mL - vB.y) / vB.z; outerU = (-vtcU.x * (float)mL - vtcU.y) / vtcU.z; outerV = (-vtcV.x * (float)mL - vtcV.y) / vtcV.z; //calculating the INNER RGB increments innerR = -vR.x / (float)vR.z; innerG = -vG.x / (float)vG.z; innerB = -vB.x / (float)vB.z; innerU = -vtcU.x / (float)vtcU.z; innerV = -vtcV.x / (float)vtcV.z; //initial r,g,b these values will be incremented //temp values for use in incrementing across the x axis float currR, currG, currB, currU, currV; float tempR, tempG, tempB, tempU, tempV; currR = T.color.r; currG = T.color.g; currB = T.color.b; currU = T.uv.x; currV = T.uv.y; tempR = currR; tempB = currB; tempG = currG; tempV = currV; tempU = currU; for(y = ceil(T.pos.y); y < ceil(M.pos.y); y++){ //calc right xl and xr for(x = xL; x < ceil(xR); x++){ SetPixelBlending(texture, tempU, tempV, x, y, drawtype, tempR, tempG, tempB); tempR += innerR; tempG += innerG; tempB += innerB; tempU += innerU; tempV += innerV; } xL += mL; xR += mR; currR += outerR; currB += outerB; currG += outerG; currU += outerU; currV += outerV; tempR = currR; tempB = currB; tempG = currG; tempV = currV; tempU = currU; } //Bottom Half if(Left){ mL = (B.pos.x - M.pos.x) / (float)(B.pos.y - M.pos.y); outerR = (-vR.x * (float)mL - vR.y) / vR.z; outerG = (-vG.x * (float)mL - vG.y) / vG.z; outerB = (-vB.x * (float)mL - vB.y) / vB.z; outerU = (-vtcU.x * (float)mL - vtcU.y) / vtcU.z; outerV = (-vtcV.x * (float)mL - vtcV.y) / vtcV.z; xL = M.pos.x; } else{ mR = (B.pos.x - M.pos.x) / (float)(B.pos.y - M.pos.y); xR = M.pos.x; } //second fill loop for(y = ceil(M.pos.y); y < ceil(B.pos.y); y++){ //calc right xl and xr for(x = ceil(xL); x < ceil(xR); x++){ SetPixelBlending(texture, tempU, tempV, x, y, drawtype, tempR, tempG, tempB); tempR += innerR; tempG += innerG; tempB += innerB; tempU += innerU; tempV += innerV; } xL += mL; xR += mR; currR += outerR; currB += outerB; currG += outerG; currV += outerV; currU += outerU; tempR = currR; tempB = currB; tempG = currG; tempV = currV; tempU = currU; } }