trevortomesh
12/7/2016 - 5:45 AM

raytrace.ino

#include "LCD4884.h" 

// x-y-relation for prepairing pictures is 28 x 19 ~ 3 x 2
// because LCD-pixels in 84x48 matrix seem to bee not quadratic
// use a high density 3x2 picture, resize to 84x48 non propotional
// and change to black and white 
// google for bmp to pic converter to prepare include-file 

#define DELAY1 200
#define DELAY2 1000
#define DELAY3 5000
#define height 19
#define width 28
#define LCD_BACKLIGHT_PIN  7
unsigned char bildbmp[height*width];
float colorGradients[][4] = {{0,0,0,255},{255,255,255,0}};

//----------- Our math functions ------------
float length(float x,float y,float z){
  return sqrt(x*x+y*y+z*z);
}

float norm(int x, int y,int z){
  float l = length(x,y,z);
  return x/1, y/1, z/1;
}

float dot(float xa, float ya, float za, float xb, float yb, float zb){
  return xa*xb+ya*yb + za*zb;
}
//-------------------------------------------

// define the camera
float ex = 0;
float ey = 1;
float ez = -1.5;
float fov = 90;

float tmin = .1;
float tmax = 100;

int maxSteps = 45;

//define light
float lx, ly, lz = norm(.2,.5,-.6);

//Distance Field Functions----------------
float plane(int x, int y, int z){
  return y; //this is silly
}

float sphere(float x, float y, float z, float radius){
  float manhattanDistance = x + y + z;
  if(manhattanDistance > radius * 2){
    return manhattanDistance; //because.. good enough!
  }
  return length(x,y,z) - radius; 
}
//----------------------------------------

float unio(float a, float am, float b, float bm){
  if(a < b){
    return a, am;
  }

  else return b, bm;
}

float scene(float x, float y, float z){
  float d = tmax;
  float m = 0;
  d, m = unio(d, m, plane(x, y, z), 255);
  d, m = unio(d, m, sphere(x, y-1, z, .5), 0);
  return d,m;
  
}

float sceneNormal(float x, float y, float z){
  float eps = 0.1;
  float xa = scene(x+eps, y, z);
  float xb = scene(x, y+eps, z);
  
  float ya = scene(x, y+eps, z);
  float yb = scene(x, y-eps ,z);
  float za = scene(x, y, z+eps);
  float zb = scene(x, y, z-eps);
  return norm(xa-xb, ya-yb, za-zb);
}

float noDither(int x,int y, float gradient[], float value){
  float whole = floor(value * sizeof(gradient));
  float fraction = value * sizeof(gradient) - whole;
  int low = gradient[int(min(whole+1, sizeof(gradient)))];
  int high = gradient[int(min(min(whole + 1, sizeof(gradient)) + 1, sizeof(gradient)))];
  
  if(fraction < 1.0/7.0){
    return low;
  }
  
  if(fraction < 2.0/7.0){ 
  if ((x+1) % 3 == 0 && y % 3 == 0){ 
    return high; 
    
  }
    else return low;
    
  }
  
  if( fraction < 3.0/7.0){
    if(x%2==0 && y%2==0){
      return high;
        
  }
      else return low;
      
    }
  
  if(fraction < 4.0/7.0){
    if(x%2==0 && y%2==0 || x%2!=0 && y%2!=0){
      return high;
        
  }
      else return low;
      
    }
     
  if(fraction < 5.0/7.0){
    if(x%2==0 && (y+1)%2==0){
      return low;
        
  }
      else return high; 
      
    }
    
  if(fraction < 6.0/7.0){
    if((x+1)%3==0 && y%3==0){
      return low;
        
  }
      else return high; 
        
  } 
    return high;  
  }


float getShadowPoint( int t, int x, int y, int z){
  return x+lx*t, y+ly*t, z+lz*t;
}

float shadow(int x,int y,int z){
  //t starts at 0.2 so the shadow ray doesn't intersect
  //the object it's trying to shadow
  float res=1;
  float t = 0.2;
  float distance = 0;
  float sx = 0;
  float sy = 0;
  float sz = 0;
  for(int i = 1; i < 6; i++){
    sx, sy, sz = getShadowPoint(t, x, y, z);
    distance = scene(sx, sy, sz); //we don't care about the color
    res = min(res, 2 * distance / t); //increase 2 to get sharper shadows
    t += min(max(distance, .02), .2);
    if(distance < .05 or t > 10.0){
      break;
    }
  }
  return min(max(res, 0), 1);
}

//calculates the final lighting and color
float render(int x, int y, int t, float tx, float ty, float tz, float rx, float ry, float rz, int color){
  float nx, ny, nz = sceneNormal(tx, ty, tz);
  float light = 0;
  light += min(max(dot(nx, ny, nz, lx, ly, lz), 0), 1); //sun light
  light *= shadow(tx,ty,tz); //shadow color
  light = min(max(light, 0), 1); //clamp final light value
  //return dither(x, y, colorGradients[color], light);
  Serial.println(noDither(x,y,colorGradients[color],light));
  return noDither(x,y,colorGradients[color],light);
  
}

float getRayDirection(int x, int y){
  return norm(x / 64 - 1, (128 - y) / 64 - 1, 90 / fov);
}

float getTestPoint(float t, float rx, float ry, float rz){
  return ex + rx * t, ey + ry * t, ez + rz * t;
}

float trace(int x,int y){
  float rx, ry, rz = getRayDirection(x, y);
  float tx = 0;
  float ty = 0;
  float tz = 0;
  float t = 0;
  float distance = 0;
  int color = 0;
  for(int i = 1; i < maxSteps; i++){
    tx, ty, tz = getTestPoint(t, rx, ry, rz);
    distance, color = scene(tx, ty, tz);
    //--the test point is close enough, render
    if(distance < .05){
      return render(x, y, t, tx, ty, tz, rx, ry, rz, color);
    }
    //--the test point is too far, give up, draw the sky
    if(distance >= tmax){
      break;
    }
    //--move forward by some fraction
      t += distance * .7;
  }
}

void setup()
{
  Serial.begin(9600);
  lcd.LCD_init(); // creates instance of LCD
  for(int i = 0; i < width*height; i+=2){
  bildbmp[i] = 0x00;
  bildbmp[i+1] = 0xFF;

  }
  }

void loop()
{  
   digitalWrite(LCD_BACKLIGHT_PIN, LOW);
   unsigned char i=0, line=0, pos=0, offset;
   unsigned char mychar;
   int x = 0;
   int y = 0;
   /*********** 1st ***********/
   lcd.LCD_clear(); // blanks the display
   lcd.LCD_draw_bmp_pixel(0,0, bildbmp, 84,48);
   for(x = 0; x < width; x++){
    for(y = 0; y < height; y++){
      Serial.println(trace(x,y));
      
    }
   }
}