A while back I made a software renderer and I wanted to do the same on the arduino. It was even easier, as the Adafruit display library already has a display.fillTriangle function. I got the display working and I was able to render text and scrolling using the Adafruit example sketches in the Arduino IDE. Then I copied the code from my software renderer and then deleted the triangle rasterization code, as I didn't need it anymore. I put everything together, added the rendering code and when I ran the program, only one of the pixels rendered and that specific pixel wasn't even in the triangle's shape. I did some debugging and found out that the final value for the first and the second vertex is zero. That would mean that all of the positions for the triangle are zeroes. The same code was working on my computer and I am unsure what could've caused this. This is the triangle rendering code:
void drawtriangle(float pos1[3], float pos2[3], float pos3[3]){
float v1[2];
float v2[2];
float v3[2];
char buf[10];
vertexshader(pos1, model, view, proj, v1);
vertexshader(pos2, model, view, proj, v2);
vertexshader(pos3, model, view, proj, v3);
display.fillTriangle(v1[0], v1[1], v2[0], v2[1], v3[0], v3[1], WHITE);
snprintf(buf, sizeof(buf), "%d", (int)v1[0]);
Serial.write(buf);
Serial.print(", ");
snprintf(buf, sizeof(buf), "%d", (int)v2[0]);
Serial.write(buf);
Serial.write("\n");
}
void drawtrianglearray(float *positions, int size){
float pos1[3];
float pos2[3];
float pos3[3];
int i;
for(i = 0; i < size / 9; i++){
pos1[0] = positions[i * 9];
pos1[1] = positions[i * 9 + 1];
pos1[2] = positions[i * 9 + 2];
pos2[0] = positions[i * 9 + 3];
pos2[1] = positions[i * 9 + 4];
pos2[2] = positions[i * 9 + 5];
pos3[0] = positions[i * 9 + 6];
pos3[1] = positions[i * 9 + 7];
pos3[2] = positions[i * 9 + 8];
drawtriangle(pos1, pos2, pos3);
}
}
This is the vertex shader:
void vertexshader(float position[3], float model[16], float view[16], float proj[16], float out[2]){
float int1[16];
float int2[16];
float int3[4];
float int4[4];
float int5[2];
float int6[2];
int3[0] = position[0];
int3[1] = position[1];
int3[2] = position[2];
int3[3] = 1.0f;
mat4_mul(view, model, int1);
mat4_mul(proj, int1, int2);
mat4_vec4_mul(int2, int3, int4);
int5[0] = int4[0] / int4[3];
int5[1] = int4[1] / int4[3];
int6[0] = int5[0] * 0.5f + 0.5f;
int6[1] = int5[1] * 0.5f + 0.5f;
out[0] = int6[0] * width;
out[1] = (1.0f - int6[1]) * height;
}
And this is the main loop:
void loop() {
display.clearDisplay();
drawtrianglearray(vertices, sizeof(vertices)/sizeof(float));
display.display();
angle += 1.0f;
mat4_rotate(angle, 1, model);
}
The mat4 functions are from a library I made. This is its code:
void mat2_mul(float a[4], float b[4], float *out){
out[0] = a[0] * b[0] + a[1] * b[1];
out[1] = a[0] * b[1] + a[1] * b[2];
out[2] = a[2] * b[0] + a[3] * b[2];
out[3] = a[2] * b[1] + a[3] * b[3];
}
void mat2_vec2_mul(float mat[4], float vec[2], float *out){
out[0] = mat[0] * vec[0] + mat[1] * vec[1];
out[1] = mat[2] * vec[0] + mat[3] * vec[1];
}
void mat4_mul(float l[16], float r[16], float *out){
out[0] = r[0] * l[0] + r[4] * l[1] + r[8] * l[2] + r[12] * l[3];
out[1] = r[1] * l[0] + r[5] * l[1] + r[9] * l[2] + r[13] * l[3];
out[2] = r[2] * l[0] + r[6] * l[1] + r[10] * l[2] + r[14] * l[3];
out[3] = r[3] * l[0] + r[7] * l[1] + r[11] * l[2] + r[15] * l[3];
out[4] = r[0] * l[4] + r[4] * l[5] + r[8] * l[6] + r[12] * l[7];
out[5] = r[1] * l[4] + r[5] * l[5] + r[9] * l[6] + r[13] * l[7];
out[6] = r[2] * l[4] + r[6] * l[5] + r[10] * l[6] + r[14] * l[7];
out[7] = r[3] * l[4] + r[7] * l[5] + r[11] * l[6] + r[15] * l[7];
out[8] = r[0] * l[8] + r[4] * l[9] + r[8] * l[10] + r[12] * l[11];
out[9] = r[1] * l[8] + r[5] * l[9] + r[9] * l[10] + r[13] * l[11];
out[10] = r[2] * l[8] + r[6] * l[9] + r[10] * l[10] + r[14] * l[11];
out[11] = r[3] * l[8] + r[7] * l[9] + r[11] * l[10] + r[15] * l[11];
out[12] = r[0] * l[12] + r[4] * l[13] + r[8] * l[14] + r[12] * l[15];
out[13] = r[1] * l[12] + r[5] * l[13] + r[9] * l[14] + r[13] * l[15];
out[14] = r[2] * l[12] + r[6] * l[13] + r[10] * l[14] + r[14] * l[15];
out[15] = r[3] * l[12] + r[7] * l[13] + r[11] * l[14] + r[15] * l[15];
}
void mat4_vec4_mul(float mat[16], float vec[4], float *out){
out[0] = vec[0] * mat[0] + vec[1] * mat[1] + vec[2] * mat[2] + vec[3] * mat[3];
out[1] = vec[0] * mat[4] + vec[1] * mat[5] + vec[2] * mat[6] + vec[3] * mat[7];
out[2] = vec[0] * mat[8] + vec[1] * mat[9] + vec[2] * mat[10] + vec[3] * mat[11];
out[3] = vec[0] * mat[12] + vec[1] * mat[13] + vec[2] * mat[14] + vec[3] * mat[15];
}
void mat4_rotate(float degrees, unsigned int axis, float *out){
float radians = degrees * (22.0f / 7.0f) / 180.0f;
if(axis == 0){
out[0] = 1.0f;
out[1] = 0.0f;
out[2] = 0.0f;
out[3] = 0.0f;
out[4] = 0.0f;
out[5] = cosf(radians);
out[6] = -sinf(radians);
out[7] = 0.0f;
out[8] = 0.0f;
out[9] = sinf(radians);
out[10] = cosf(radians);
out[11] = 0.0f;
out[12] = 0.0f;
out[13] = 0.0f;
out[14] = 0.0f;
out[15] = 1.0f;
}else if(axis == 1){
out[0] = cosf(radians);
out[1] = 0.0f;
out[2] = sinf(radians);
out[3] = 0.0f;
out[4] = 0.0f;
out[5] = 1.0f;
out[6] = 0.0f;
out[7] = 0.0f;
out[8] = -sinf(radians);
out[9] = 0.0f;
out[10] = cosf(radians);
out[11] = 0.0f;
out[12] = 0.0f;
out[13] = 0.0f;
out[14] = 0.0f;
out[15] = 1.0f;
}else if(axis == 2){
out[0] = cosf(radians);
out[1] = -sinf(radians);
out[2] = 0.0f;
out[3] = 0.0f;
out[4] = sinf(radians);
out[5] = cosf(radians);
out[6] = 0.0f;
out[7] = 0.0f;
out[8] = 0.0f;
out[9] = 0.0f;
out[10] = 1.0f;
out[11] = 0.0f;
out[12] = 0.0f;
out[13] = 0.0f;
out[14] = 0.0f;
out[15] = 1.0f;
}
}
I can't figure this out. Do you find a mistake in my code?
Edit: When I added the debug messages the program slowed down and was able to render one of the lines, but wasn't consistently rendering, as it was blinking a lot. And also I noticed that it might be rendering upside down. How much time does the library need to render it? I tried adding delays after the rendering of the triangle, but that makes it go back to only showing one pixel on the display.