Advertisement
AlexD77

Untitled

Nov 7th, 2021
225
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. declare function sqrt(v: number): number;
  2. declare function floor(v: number): number;
  3. declare function pow(v: number, s: number): number;
  4.  
  5. class Math {
  6.     static sqrt(v: number): number {
  7.     return sqrt(v);
  8.     }
  9.  
  10.     static floor(v: number): number {
  11.         return floor(v);
  12.     }
  13.  
  14.     static pow(v: number, s: number): number {
  15.         return pow(v, s);
  16.     }
  17. }
  18.  
  19. class Vector {
  20.     constructor(public x: number,
  21.         public y: number,
  22.         public z: number) {
  23.     }
  24.     static times(k: number, v: Vector) { return new Vector(k * v.x, k * v.y, k * v.z); }
  25.     static minus(v1: Vector, v2: Vector) { return new Vector(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); }
  26.     static plus(v1: Vector, v2: Vector) { return new Vector(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z); }
  27.     static dot(v1: Vector, v2: Vector) { return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; }
  28.     static mag(v: Vector) { return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z); }
  29.     static norm(v: Vector) {
  30.         let mag = Vector.mag(v);
  31.         let div = (mag === 0) ? Infinity : 1.0 / mag;
  32.         return Vector.times(div, v);
  33.     }
  34.     static cross(v1: Vector, v2: Vector) {
  35.         return new Vector(v1.y * v2.z - v1.z * v2.y,
  36.             v1.z * v2.x - v1.x * v2.z,
  37.             v1.x * v2.y - v1.y * v2.x);
  38.     }
  39. }
  40.  
  41. class Color {
  42.     constructor(public r: number,
  43.         public g: number,
  44.         public b: number) {
  45.     }
  46.     static scale(k: number, v: Color) { return new Color(k * v.r, k * v.g, k * v.b); }
  47.     static plus(v1: Color, v2: Color) { return new Color(v1.r + v2.r, v1.g + v2.g, v1.b + v2.b); }
  48.     static times(v1: Color, v2: Color) { return new Color(v1.r * v2.r, v1.g * v2.g, v1.b * v2.b); }
  49.     static white = new Color(1.0, 1.0, 1.0);
  50.     static grey = new Color(0.5, 0.5, 0.5);
  51.     static black = new Color(0.0, 0.0, 0.0);
  52.     static background = Color.black;
  53.     static defaultColor = Color.black;
  54.     static toDrawingColor(c: Color) {
  55.         let legalize = (d: number) => d > 1 ? 1 : d;
  56.         return {
  57.             r: Math.floor(legalize(c.r) * 255),
  58.             g: Math.floor(legalize(c.g) * 255),
  59.             b: Math.floor(legalize(c.b) * 255)
  60.         }
  61.     }
  62. }
  63.  
  64. class Camera {
  65.     public forward: Vector;
  66.     public right: Vector;
  67.     public up: Vector;
  68.  
  69.     constructor(public pos: Vector, lookAt: Vector) {
  70.         let down = new Vector(0.0, -1.0, 0.0);
  71.         this.forward = Vector.norm(Vector.minus(lookAt, this.pos));
  72.         this.right = Vector.times(1.5, Vector.norm(Vector.cross(this.forward, down)));
  73.         this.up = Vector.times(1.5, Vector.norm(Vector.cross(this.forward, this.right)));
  74.     }
  75. }
  76.  
  77. interface Ray {
  78.     start: Vector;
  79.     dir: Vector;
  80. }
  81.  
  82. interface Intersection {
  83.     thing: Thing;
  84.     ray: Ray;
  85.     dist: number;
  86. }
  87.  
  88. interface Surface {
  89.     diffuse: (pos: Vector) => Color;
  90.     specular: (pos: Vector) => Color;
  91.     reflect: (pos: Vector) => number;
  92.     roughness: number;
  93. }
  94.  
  95. interface Thing {
  96.     intersect(ray: Ray): Intersection;
  97.     normal(pos: Vector): Vector;
  98.     surface: Surface;
  99. }
  100.  
  101. interface Light {
  102.     pos: Vector;
  103.     color: Color;
  104. }
  105.  
  106. interface Scene {
  107.     things: Thing[];
  108.     lights: Light[];
  109.     camera: Camera;
  110. }
  111.  
  112. class Sphere implements Thing {
  113.     public radius2: number;
  114.  
  115.     constructor(public center: Vector, radius: number, public surface: Surface) {
  116.         this.radius2 = radius * radius;
  117.     }
  118.     normal(pos: Vector): Vector { return Vector.norm(Vector.minus(pos, this.center)); }
  119.     intersect(ray: Ray): Intersection {
  120.         let eo = Vector.minus(this.center, ray.start);
  121.         let v = Vector.dot(eo, ray.dir);
  122.         let dist = 0;
  123.         if (v >= 0) {
  124.             let disc = this.radius2 - (Vector.dot(eo, eo) - v * v);
  125.             if (disc >= 0) {
  126.                 dist = v - Math.sqrt(disc);
  127.             }
  128.         }
  129.         if (dist === 0) {
  130.             return null;
  131.         } else {
  132.             return { thing: <Thing>this, ray: ray, dist: <number>dist };
  133.         }
  134.     }
  135. }
  136.  
  137. class Plane implements Thing {
  138.     constructor(public norm: Vector, public offset: number, public surface: Surface) {
  139.     }
  140.     public normal(pos: Vector): Vector { return this.norm; }
  141.     public intersect(ray: Ray): Intersection {
  142.         let denom = Vector.dot(this.norm, ray.dir);
  143.         if (denom > 0) {
  144.             return null;
  145.         } else {
  146.             let dist = (Vector.dot(this.norm, ray.start) + this.offset) / (-denom);
  147.             return { thing: <Thing>this, ray: ray, dist: <number>dist };
  148.         }
  149.     }
  150. }
  151.  
  152. module Surfaces {
  153.     export let shiny: Surface = {
  154.         diffuse: function (pos: Vector) { return Color.white; },
  155.         specular: function (pos: Vector) { return Color.grey; },
  156.         reflect: function (pos: Vector) { return 0.7; },
  157.         roughness: 250.0
  158.     }
  159.     export let checkerboard: Surface = {
  160.         diffuse: function (pos: Vector) {
  161.             if ((Math.floor(pos.z) + Math.floor(pos.x)) % 2 !== 0) {
  162.                 return Color.white;
  163.             } else {
  164.                 return Color.black;
  165.             }
  166.         },
  167.         specular: function (pos: Vector) { return Color.white; },
  168.         reflect: function (pos: Vector) {
  169.             if ((Math.floor(pos.z) + Math.floor(pos.x)) % 2 !== 0) {
  170.                 return 0.1;
  171.             } else {
  172.                 return 0.7;
  173.             }
  174.         },
  175.         roughness: 150.0
  176.     }
  177. }
  178.  
  179.  
  180. class RayTracer {
  181.     private maxDepth = 5;
  182.  
  183.     private intersections(ray: Ray, scene: Scene) {
  184.         let closest = +Infinity;
  185.         let closestInter: Intersection = undefined;
  186.         for (let i in scene.things) {
  187.             let inter = scene.things[i].intersect(ray);
  188.             if (inter != null && inter.dist < closest) {
  189.                 closestInter = inter;
  190.                 closest = inter.dist;
  191.             }
  192.         }
  193.  
  194.         return closestInter;
  195.     }
  196.  
  197.     private testRay(ray: Ray, scene: Scene) {
  198.         let isect = this.intersections(ray, scene);
  199.         if (isect != null) {
  200.             return isect.dist;
  201.         } else {
  202.             return undefined;
  203.         }
  204.     }
  205.  
  206.     private traceRay(ray: Ray, scene: Scene, depth: number): Color {
  207.         let isect = this.intersections(ray, scene);
  208.         if (isect === undefined) {
  209.             return Color.background;
  210.         } else {
  211.             return this.shade(isect, scene, depth);
  212.         }
  213.     }
  214.  
  215.     private shade(isect: Intersection, scene: Scene, depth: number) {
  216.         let d = isect.ray.dir;
  217.         let pos = Vector.plus(Vector.times(isect.dist, d), isect.ray.start);
  218.         let normal = isect.thing.normal(pos);
  219.         let reflectDir = Vector.minus(d, Vector.times(2, Vector.times(Vector.dot(normal, d), normal)));
  220.         let naturalColor = Color.plus(Color.background,
  221.             this.getNaturalColor(isect.thing, pos, normal, reflectDir, scene));
  222.         let reflectedColor = (depth >= this.maxDepth) ? Color.grey : this.getReflectionColor(isect.thing, pos, normal, reflectDir, scene, depth);
  223.         return Color.plus(naturalColor, reflectedColor);
  224.     }
  225.  
  226.     private getReflectionColor(thing: Thing, pos: Vector, normal: Vector, rd: Vector, scene: Scene, depth: number) {
  227.         return Color.scale(thing.surface.reflect(pos), this.traceRay({ start: pos, dir: rd }, scene, depth + 1));
  228.     }
  229.  
  230.     private getNaturalColor(thing: Thing, pos: Vector, norm: Vector, rd: Vector, scene: Scene) {
  231.         const addLight = (col: Color, light: Light) => {
  232.             let ldis = Vector.minus(light.pos, pos);
  233.             let livec = Vector.norm(ldis);
  234.             let neatIsect = this.testRay({ start: pos, dir: livec }, scene);
  235.             let isInShadow = (neatIsect === undefined) ? false : (neatIsect <= Vector.mag(ldis));
  236.             if (isInShadow) {
  237.                 return col;
  238.             } else {
  239.                 let illum = Vector.dot(livec, norm);
  240.                 let lcolor = (illum > 0) ? Color.scale(illum, light.color)
  241.                     : Color.defaultColor;
  242.                 let specular = Vector.dot(livec, Vector.norm(rd));
  243.                 let scolor = (specular > 0) ? Color.scale(Math.pow(specular, thing.surface.roughness), light.color)
  244.                     : Color.defaultColor;
  245.                 return Color.plus(col, Color.plus(Color.times(thing.surface.diffuse(pos), lcolor),
  246.                     Color.times(thing.surface.specular(pos), scolor)));
  247.             }
  248.         }
  249.         //return scene.lights.reduce(addLight, Color.defaultColor);
  250.         let resColor = Color.defaultColor;
  251.         for (const light of scene.lights) {
  252.             resColor = addLight(resColor, light);
  253.         }
  254.  
  255.         return resColor;
  256.     }
  257.  
  258.     render(scene: Scene, screenWidth: number, screenHeight: number) {
  259.         const getPoint = (x: number, y: number, camera: Camera) => {
  260.             const recenterX = (x: number) => (x - (screenWidth / 2.0)) / 2.0 / screenWidth;
  261.             const recenterY = (y: number) => - (y - (screenHeight / 2.0)) / 2.0 / screenHeight;
  262.             return Vector.norm(Vector.plus(camera.forward, Vector.plus(Vector.times(recenterX(x), camera.right), Vector.times(recenterY(y), camera.up))));
  263.         }
  264.  
  265.         for (let y = 0; y < screenHeight; y++) {
  266.             for (let x = 0; x < screenWidth; x++) {
  267.                 let color = this.traceRay({ start: scene.camera.pos, dir: getPoint(x, y, scene.camera) }, scene, 0);
  268.                 let c = Color.toDrawingColor(color);
  269.                 //ctx.fillStyle = "rgb(" + String(c.r) + ", " + String(c.g) + ", " + String(c.b) + ")";
  270.                 //ctx.fillRect(x, y, x + 1, y + 1);
  271.         // next line eats stack (or memory?)
  272.         print(`<rect x="${x}" y="${y}" width="1" height="1" style="fill:rgb(${c.r},${c.g},${c.b});" />`);
  273.             }
  274.         }
  275.     }
  276. }
  277.  
  278.  
  279. function defaultScene(): Scene {
  280.     return {
  281.         things: [<Thing>new Plane(new Vector(0.0, 1.0, 0.0), 0.0, Surfaces.checkerboard),
  282.         <Thing>new Sphere(new Vector(0.0, 1.0, -0.25), 1.0, Surfaces.shiny),
  283.         <Thing>new Sphere(new Vector(-6, 3.0, -5.0), 1.0, Surfaces.shiny),
  284.         // new Sphere(new Vector(-6, 8.0, 15.0), 5.0, Surfaces.shiny),
  285.         <Thing>new Sphere(new Vector(-1.0, 0.5, 1.5), 0.5, Surfaces.shiny)],
  286.  
  287.         lights: [<Light>{ pos: new Vector(-2.0, 2.5, 0.0), color: new Color(0.49, 0.07, 0.07) },
  288.         <Light>{ pos: new Vector(1.5, 2.5, 1.5), color: new Color(0.07, 0.07, 0.49) },
  289.         <Light>{ pos: new Vector(1.5, 2.5, -1.5), color: new Color(0.07, 0.49, 0.071) },
  290.         <Light>{ pos: new Vector(0.0, 3.5, 0.0), color: new Color(0.21, 0.21, 0.35) }],
  291.         camera: new Camera(new Vector(3.0, 2.0, 4.0), new Vector(-1.0, 0.5, 0.0))
  292.     };
  293. }
  294.  
  295. function exec() {
  296.     let rayTracer = new RayTracer();
  297.     rayTracer.render(defaultScene(), 256, 256);
  298. }
  299.  
  300.  
  301. function main() {
  302.     print("start...");
  303.  
  304.     exec();
  305.  
  306.     print("done.");
  307. }
  308.                                                                      
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement