// This is free and unencumbered software released into the public domain. // Anyone is free to copy, modify, publish, use, compile, sell, or // distribute this software, either in source code form or as a compiled // binary, for any purpose, commercial or non-commercial, and by any // means. // In jurisdictions that recognize copyright laws, the author or authors // of this software dedicate any and all copyright interest in the // software to the public domain. We make this dedication for the benefit // of the public at large and to the detriment of our heirs and // successors. We intend this dedication to be an overt act of // relinquishment in perpetuity of all present and future rights to this // software under copyright law. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // For more information, please refer to import java.util.Random; // I can't stand arbitrary output // Image parameters: This is the stuff that's easy to change final int w = 640, h = 640, d = 640; // Other locals PImage img = createImage(w, h, RGB); // Generic setup code: Nothing of interest happens here, I promise. // This function just normalizes the x/y values to [0,1] and passes // them to colAt() one by one to populate the image. In a fragment // shader, this function would not exist. void setup() { size(w, h); } float zat = -1; void draw() { if (++zat > d) zat = 0; img.loadPixels(); int ind = 0; for (int y = 0; y < h; ++y) { float yf = y / (float)h; for (int x = 0; x < w; ++x) img.pixels[ind++] = colAt(x / (float)w, yf, zat / d); } img.updatePixels(); image(img, 0, 0); } // Utility functions, boilerplate boilerplate boilerplate static float sqr(float x) { return x*x; } static float hypot(float x, float y) { return sqrt(sqr(x) + sqr(y)); } // This is where the actual logic starts. float distLine(float x1, float y1, float z1, float x2, float y2, float z2, float x, float y, float z) { float l2 = sqr(x1 - x2) + sqr(y1 - y2) + sqr(z1 - z2); // System.out.println("(" + x1 + ", " + y1 + ") -> (" + x + ", " + y + ") = " + hypot(x - x1, y - y1)); if (l2 == 0) return sqrt(sqr(x - x1) + sqr(y - y1) + sqr(z - z1)); float t = ((x - x1) * (x2 - x1) + (y - y1) * (y2 - y1) + (z - z1) * (z2 - z1)) / l2; if (t < 0) return sqrt(sqr(x-x1) + sqr(y-y1) + sqr(z-z1)); if (t > 1) return sqrt(sqr(x-x2) + sqr(y-y2) + sqr(z-z2)); return sqrt(sqr(x - (x1 + t * (x2 - x1))) + sqr(y - (y1 + t * (y2 - y1))) + sqr(z - (z1 + t * (z2 - z1)))); } float lineLight(float x1, float y1, float z1, float x2, float y2, float z2, float r, float x, float y, float z) { float dist = distLine(x1, y1, z1, x2, y2, z2, x, y, z); if (dist >= r) return 0; return 1 - dist / r; } // This function samples a pixel and is called millions of times to draw your image color colAt(float x, float y, float z) { return lerpColor(0x000000, 0xAFFFCF, lineLight(w/5, h/5, d*2.25/5, w*4/5, h*4/5, d*2.75/5, hypot(w/8, h/8), x * w, y * h, z * d)); }