// simple project with rotating 3D cube using Arduino UNO and Transparent 128x64 OLED Display,
// created by upir, 2022
// youtube channel: https://www.youtube.com/upir_upir
// full tutoral is here: https://youtu.be/kBAcaA7NAlA
// Turbo pressure gauge tutorial: https://youtu.be/JXmw1xOlBdk
// Transparent OLED tutorial: https://youtu.be/hIFDcksXgBk
// Knob + OLED tutorial: https://youtu.be/NPfaLKKsf_Q
// useful links:
// u8g documentation: https://github.com/olikraus/u8glib/wiki/userreference
// Wokwi starting project: https://wokwi.com/arduino/projects/300867986768527882
// Arduino UNO: http://store.arduino.cc/products/arduino-uno-rev3
// Arduino UNO MINI: https://store.arduino.cc/products/uno-mini-le
// Multidimensional arrays: https://www.tutorialspoint.com/arduino/arduino_multi_dimensional_arrays.htm
// 2D Rotation: https://en.wikipedia.org/wiki/Rotation_(mathematics)
// Normal OLED Display: https://www.aliexpress.com/item/4001051535838.html
// Transparent OLED Display: https://a.aliexpress.com/_mKGmhKg
// Big OLED Display: https://www.aliexpress.com/item/1005003091769556.html
// Arduino breadboard prototyping shield: https://www.adafruit.com/product/2077
#include "U8glib.h" // u8g library, note there is a newer version u8g2, please use the older one
const uint8_t upir_logo[] U8G_PROGMEM = { // another simple way how to define pictures for u8g library
B00010101, B11010111, // ░░░█░█░███░█░███
B00010101, B01000101, // ░░░█░█░█░█░░░█░█
B00010101, B10010110, // ░░░█░█░██░░█░██░
B00011001, B00010101 // ░░░██░░█░░░█░█░█
};
// uncomment the correct connection - fast I2C, slow I2C, SPI
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0 | U8G_I2C_OPT_NO_ACK | U8G_I2C_OPT_FAST); // Fast I2C / TWI
//U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0 | U8G_I2C_OPT_NO_ACK); // slow I2C / TWI -- I had to use "slow I2C" in my case
//U8GLIB_SSD1306_128X64 u8g(13, 11, 8, 9, 10); // SPI connection - SCL = 13, SDA = 11, RES = 10, DC = 9, CS = 8
int points[64][2] = {
{75,23},
{56,26},
{63,30},
{71,6},
{63,29},
{51,18},
{77,11},
{71,15},
{62,7},
{52,22},
{56,22},
{76,16},
{70,28},
{68,16},
{59,3},
{50,14},
{70,16},
{57,8},
{70,10},
{58,27},
{68,4},
{76,11},
{54,24},
{64,6},
{60,4},
{60,4},
{59,28},
{61,16},
{72,14},
{77,10},
{65,4},
{52,18},
{64,3},
{65,22},
{73,5},
{69,11},
{51,17},
{57,27},
{64,10},
{61,7},
{55,8},
{70,28},
{62,26},
{76,8},
{69,28},
{56,28},
{72,13},
{58,25},
{54,20},
{53,12},
{75,21},
{67,15},
{56,6},
{74,6},
{71,13},
{56,24},
{53,10},
{53,16},
{53,9},
{63,21},
{77,19},
{69,3},
{76,20},
{78,14}
};
float orig_points [64][3] = { // eight 3D points - set values for 3D cube
{-0.366938759,-0.675151759,0.639942223},
{0.753083689,0.319448347,-0.575167551},
{0.795280596,-0.291245568,0.531699908},
{-0.450777761,0.883756871,0.125591418},
{0.402606198,-0.435010718,-0.805402958},
{-0.471703749,-0.590806153,0.654556081},
{0.897206867,0.303641082,0.320658589},
{-0.896225859,0.377774436,-0.23252029},
{-0.474915861,0.871579041,0.121675391},
{-0.686409767,-0.673241125,-0.274932756},
{-0.363776242,0.931410032,0.011924684},
{0.572088211,0.165591854,0.803302195},
{0.578560154,0.389082563,-0.716856267},
{0.809520489,-0.008707925,0.587027044},
{0.5006245,0.30824289,0.808926097},
{-0.849592276,-0.525674099,0.043124308},
{0.164463889,0.287828432,0.943454516},
{0.250307439,0.216766097,0.943588176},
{-0.992778821,-0.114358057,0.036227708},
{0.911268935,-0.285147775,0.297118956},
{-0.679969724,-0.721396726,0.131255242},
{0.201209357,-0.737963933,0.644145968},
{-0.95046991,0.262421679,0.166558738},
{0.17267416,0.683849513,-0.708895957},
{0.594954144,0.463740431,-0.656486389},
{-0.332850593,0.936979481,-0.106207036},
{-0.607577692,0.336152248,-0.719618659},
{0.940270712,0.307366934,0.146343966},
{-0.303948165,-0.706726773,0.63886836},
{-0.284942183,0.913626971,0.289989154},
{-0.803427323,-0.545395985,0.238846721},
{-0.693831041,0.581018269,0.425460053},
{0.299550658,-0.445244166,0.843816945},
{-0.615509643,0.741800183,0.266233673},
{0.876616715,-0.197721627,0.43869043},
{-0.764787051,-0.502206166,0.403596002},
{-0.395108198,-0.10079904,-0.913087655},
{0.151893803,-0.987789826,-0.034634274},
{0.551257262,0.404570666,-0.729683498},
{-0.156952559,-0.932990898,-0.323873245},
{-0.299629512,-0.585160578,0.753531189},
{-0.166735529,0.055973205,-0.984411633},
{-0.439250961,0.847058406,0.299250146},
{-0.325440029,0.395921619,-0.858682048},
{0.154504624,-0.591500951,0.791362715},
{0.369940955,-0.02429475,0.92873756},
{0.802621282,0.476329295,0.359039665},
{-0.602222261,-0.546096379,0.582329025},
{-0.301326595,0.692087586,-0.655909336},
{-0.136799732,0.051062561,-0.989281784},
{0.086600591,0.680523784,0.72759035},
{0.927061664,-0.243878187,-0.284745678},
{0.794524964,-0.586393067,-0.157712561},
{0.538407994,-0.444121057,-0.716151743},
{-0.0195855,-0.473961576,0.880327685},
{0.561294137,0.536194829,-0.630431596},
{0.083531039,0.991529745,-0.099455166},
{-0.72521044,0.687267924,-0.041624723},
{-0.173511887,-0.09194481,0.980530355},
{-0.289729539,0.754156733,0.58932539},
{0.620459929,0.468535225,-0.628891262},
{0.176762033,-0.527543929,0.830934767},
{0.596524724,-0.663855337,-0.451059138},
{0.123050949,-0.750354794,0.649481445}
};
float rotated_3d_points [64][3]; // eight 3D points - rotated around Y axis
float angle_deg = 60.0; // rotation around the Y axis
float z_offset = -4.0; // offset on Z axis
float cube_size = 90.0; // cube size (multiplier)
float time_frame; // ever increasing time value
void setup() {
u8g.setColorIndex(1); // set color to white
}
void loop() {
time_frame++; // increase the time frame value by 1
//cube_size = 50 + sin(time_frame * 0.2)*20; // oscilate cube size between values 30 - 70
//z_offset = -2.0; //
//cube_size = 18.0; // uncomment those two lines for a "wide angle camera" -- bigger perspective distort
// increase the angle by 3° increments
if (angle_deg < 360-5) {
angle_deg = angle_deg + 3;
} else {
angle_deg = 0;
}
// calculate the points
for (int i=0; i<64; i++) {
// rotate 3d points around the Y axis (rotating X nad Z positions)
rotated_3d_points [i][0] = orig_points [i][0] * cos(radians(angle_deg));
rotated_3d_points [i][0] -= orig_points [i][2] * sin(radians(angle_deg));
rotated_3d_points [i][1] = orig_points [i][1];
rotated_3d_points [i][2] = orig_points [i][0] * sin(radians(angle_deg));
rotated_3d_points [i][2] += orig_points [i][2] * cos(radians(angle_deg)) + z_offset;
}
/*
for (int i=0; i<64; i++) {
// project 3d points into 2d space with perspective divide -- 2D x = x/z, 2D y = y/z
points[i][0] = round(64 + rotated_3d_points [i][0] / rotated_3d_points [i][2] * cube_size);
points[i][1] = round(32 + rotated_3d_points [i][1] / rotated_3d_points [i][2] * cube_size);
}
*/
u8g.firstPage();
do {
for (int i=0; i<64; i++) {
//Serial.println(rotated_3d_points [i][2]);
if(rotated_3d_points [i][2]>z_offset) // hide the back ones
{
u8g.drawPixel(get2dx(rotated_3d_points [i][0], rotated_3d_points [i][2]),
get2dy(rotated_3d_points [i][1], rotated_3d_points [i][2]));
}
}
// connect the lines between the individual points
/*u8g.drawLine(points[ 0 ][ 0 ], points[ 0 ][ 1 ] , points[ 1 ][ 0 ] , points[ 1 ][ 1 ] ); // connect points 0-1
u8g.drawLine(points[ 1 ][ 0 ], points[ 1 ][ 1 ] , points[ 2 ][ 0 ] , points[ 2 ][ 1 ] ); // connect points 1-2
u8g.drawLine(points[ 2 ][ 0 ], points[ 2 ][ 1 ] , points[ 3 ][ 0 ] , points[ 3 ][ 1 ] ); // connect points 2-3
u8g.drawLine(points[ 3 ][ 0 ], points[ 3 ][ 1 ] , points[ 0 ][ 0 ] , points[ 0 ][ 1 ] ); // connect points 3-0
u8g.drawLine(points[ 4 ][ 0 ], points[ 4 ][ 1 ] , points[ 5 ][ 0 ] , points[ 5 ][ 1 ] ); // connect points 4-5
u8g.drawLine(points[ 5 ][ 0 ], points[ 5 ][ 1 ] , points[ 6 ][ 0 ] , points[ 6 ][ 1 ] ); // connect points 5-6
u8g.drawLine(points[ 6 ][ 0 ], points[ 6 ][ 1 ] , points[ 7 ][ 0 ] , points[ 7 ][ 1 ] ); // connect points 6-7
u8g.drawLine(points[ 7 ][ 0 ], points[ 7 ][ 1 ] , points[ 4 ][ 0 ] , points[ 4 ][ 1 ] ); // connect points 7-4
u8g.drawLine(points[ 0 ][ 0 ], points[ 0 ][ 1 ] , points[ 4 ][ 0 ] , points[ 4 ][ 1 ] ); // connect points 0-4
u8g.drawLine(points[ 1 ][ 0 ], points[ 1 ][ 1 ] , points[ 5 ][ 0 ] , points[ 5 ][ 1 ] ); // connect points 1-5
u8g.drawLine(points[ 2 ][ 0 ], points[ 2 ][ 1 ] , points[ 6 ][ 0 ] , points[ 6 ][ 1 ] ); // connect points 2-6
u8g.drawLine(points[ 3 ][ 0 ], points[ 3 ][ 1 ] , points[ 7 ][ 0 ] , points[ 7 ][ 1 ] ); // connect points 3-7
*/
// draw upir logo
//u8g.drawBitmapP(112, 0, 2, 4, upir_logo);
} while ( u8g.nextPage() ); // u8g library specific, has to be there
}
int get2dx(float x,float z)
{
return round(64 + x / z * cube_size);
}
int get2dy(float y,float z)
{
return round(32 + y / z * cube_size);
}