Technical Projects

Creating Custom Shaders

Shader Stills

  • Integrates Mathematical Systems including:

    • Fractional Brownian Motion

    • Random Noise

    • Cellular Noise

    • Trigonometry

  • Shaders animated using time.

Shadertoy Adaptions for Visualization

    vec2 st = gl_FragCoord.xy / u_resolution.xy;
    st.x *= u_resolution.x / u_resolution.y;

    vec3 color = vec3(0.0);


    vec2 q = vec2(0.0);
    q.x = fbm( st - 0.03 * (u_time));
    q.y = fbm( st + 0.05 * (u_time));

    vec2 r = vec2(0.);
    r.x = fbm(st * 6.008 + 4.0 * noise(st) + q + vec2(8.3, 2.8)
             + 0.1 * sin(u_time));
    r.y = fbm(st * 10.0 + 4. * noise(st) + q + vec2(8.3, 2.8)
             + 0.1 * cos(u_time));

    color += vec3(fbm(5.0 * st * fbm(r)), fbm(5.0 * st*fbm(q)),
                fbm(5.0 * st * fbm(r + q)));
    color -= vec3( 1.0 - distance(vec2(0,1), vec2(st.x, st.y)))
                * 0.1;
    color -= vec3( 1.0 - distance(vec2(1,0), vec2(st.x, st.y)))
                * 0.2;

    gl_FragColor = vec4(color, 1.0);
  vec2 st = gl_FragCoord.xy / u_resolution;

  float stripes = 0.2 + sin(st.x * 3.14 * smoothstep(-5.0, 1.0, 
                      sin(st.x * 4.0 + fbm(st.xx * vec2(1000.0, 20.0)) * 6.0)));
  vec3 color = vec3(fbm(stripes * st.yy - 0.07), fbm(stripes * st.yy + 0.01),
                  fbm(stripes * st.yy + 0.03));

  st *= 5.0;
  float v = cellular(st) * 0.2;

  color += vec3(v) * vec3(0.8, 0.8, 1.0);

  gl_FragColor = vec4(color, 1.0);

Demonstrating the Actions completed when system is ran.

Code Snippet

    # For each Texture, set up Texture import settings
    for i in range(len(images)): 
        assetTasks.append(ue.AssetImportTask())
        removeExtentions = images[i].split('.')

        getImageName = removeExtentions[0].split('_')
        generaltextureName = getImageName[0]
        textureType = getImageName[1]

        textureName = "T_" + generaltextureName + "_" + textureType

        assetTasks[i].filename = imagesDirectory + "/" + images[i]
        assetTasks[i].destination_path = textureDir
        assetTasks[i].destination_name = textureName
        assetTasks[i].replace_existing = True
        assetTasks[i].save = True

Texture Import and Material Instance Automation Tool

  • Developed a python tool to import a set of textures from a folder, create a material instance, and attach those Textures to the Material Instance.

  • Allows the user to take a texture set and create a material instance of a master material that requires the same 3 texture parameters.

  • Requires textures to match a naming structure to easily determine material instance generation and texture implementation.

Custom Raytracing

  • Developed in C++

  • The Raytracer is designed with custom classes for spheres, planes, and triangles.

  • A scene is defined by a collection of geometry, a collection of lights, and a camera.

Code Snippets

class Sphere
{
  public:
    // Constructor and Destructor
    Sphere(const Vector& p, const float rad, const Color& c);
    ~Sphere();

    // Functions
    float intersection(const Ray& r) const;
    const Color get_color() const;
    Color shade(const Vector& P, const Light& l);
    Vector& get_position();

  private:
    // Stored Data
    // Custom Vector class
    Vector position;
    float radius;
    // Custom Color class
    Color color;

};
// Constructor
Sphere::Sphere( const Vector& p, const float rad, const Color& c ) :
  position(p),
  radius(rad),
  color(c)
{}

// Destructor
Sphere::~Sphere(){}

// Intersection Function
float Sphere::intersection(const Ray& r) const
{
  // Get information from sphere and ray
  float f, t, tp, tn;
  Vector RoPc = r.get_position() - position;

  f = pow(radius, 2) - pow(RoPc.magnitude(), 2)
         + pow((r.get_direction() * RoPc), 2);

  // based on f get t
  if(f == 0.0){
    t = - (r.get_direction() * RoPc);
    return t;

  } else if(f > 0.0){

    tp = - (r.get_direction() * RoPc) + sqrt(f);
    tn = - (r.get_direction() * RoPc) - sqrt(f);

    // Find t based on gathered information
    if(tp > 0.0 && tn > 0.0){
      if(tp < tn){
        t = tp;
      } else {
        t = tn;
      }
    } else if (tp > 0.0 && tn < 0.0){
      t = tp;
    } else if (tn < 0.0 && tn > 0.0){
      t = tn;
    } else {
      t = -1.0f;
    }

  } else {

    t = -1.0f;

  }

  return t;

}

// Gets stored Color
const Color Sphere::get_color() const
{
  return color;
}

// Gets Diffuse Color information 
Color Sphere::shade(const Vector& P, const Light& l)
{
  float f;
  Vector L = (l.get_position() - P).unitvector();
  Vector normal = (P - position).unitvector();

  // If facing light get color
  if((L*normal) > 0) {
    f = L*normal;
  } else {
    f = 0.0f;
  }

  Color finColor = l.get_color() * color * f;

  return finColor;
}

// Gets Sphere position
Vector& Sphere::get_position(){return position;}
class Plane
{
  public:
    // Constructor and Destructor
    Plane( const Vector& p, const Vector& nd, const Color& c );
   ~Plane();

    // Functions
   float intersection(const Ray& r) const;
   const Color get_color() const;
   Color shade(const Vector& P, const Light& l);
   
  private:
    // Stored Data
    Plane(){};

    Vector position;
    Vector normalDirection;
    Color color;


};
// Constructor
Plane::Plane( const Vector& p, const Vector& nd, const Color& c ) :
  position(p),
  normalDirection(nd),
  color(c)
{}

// Destructor
Plane::~Plane(){}

// Intesection Function
float Plane::intersection(const Ray& r) const
{
  float tcheck;

  // Make sure that ray and plane CAN intersect
  float dnom = r.get_direction() * normalDirection;
  if(dnom == 0){
    return -1.0f;
  }

  // Check Intersection
  tcheck = - ((r.get_position() - position) * normalDirection)
      / dnom;

  if(tcheck < 0){
    return -1.0f;
  } else {
    return tcheck;
  }

}

// Get Color
const Color Plane::get_color() const
{
  return color;
}

// Get Shade based on light
Color Plane::shade(const Vector& P, const Light& l)
{
  float f;
  Vector L = (l.get_position() - P)
       / (l.get_position() - P).magnitude();
  Vector normal = normalDirection.unitvector();

  if(L*normal > 0)
    f = L * normal;
  else
    f = 0.0f;

  Color finColor = l.get_color() * color * f;

  return finColor;
}
    for (int j = 0; j < img_height; ++j) {
      for(int i = 0; i < img_width; ++i) {

        //remapping from pixel coordinates to image plane
        u = (1.0f - (2.0f * (float)(i) / (img_width - 1))) * tanhfov2;
        v = (1.0f - (2.0f * (float)(j) / (img_height - 1))) * tanvfov2;

        //ratrace magic
        Vector rayDir = firstScene.get_Camera().view(u, v);
        Ray ray = Ray(firstScene.get_Camera().get_position(),
           rayDir);
        pixel = Trace(ray, firstScene);

        //write into ppm
        int r = (int)(pixel.red() * 255.0f);
        int g = (int)(pixel.green() * 255.0f);
        int b = (int)(pixel.blue() * 255.0f);

        outFile << r << ' ' << g << ' ' << b << ' ';
      }
    }

Lunar Deep

Production

Producer for a game production project with a team of 18 people.

  • Developed game mechanics.

  • Implemented procedural materials

  • Assisted with character animation, surfacing, and VFX.