Guest User

Untitled

a guest
Feb 20th, 2018
92
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.63 KB | None | 0 0
  1. //
  2. // Simple ambient occlusion renderer with ActionScript3
  3. //
  4. // Compile: $ mxmlc AmbientOcclusion.as
  5. //
  6. package {
  7. import flash.display.*;
  8. import flash.text.*;
  9. import flash.utils.getTimer;
  10.  
  11. public class AmbientOcclusion extends Sprite
  12. {
  13. private var bitmap:Bitmap;
  14. private var bitmapData:BitmapData;
  15.  
  16. public static const NAO_SAMPLES:int = 8;
  17.  
  18. private var spheres:Array;
  19. private var plane:Plane;
  20.  
  21. public function initScene():void
  22. {
  23. spheres = new Array(3);
  24. spheres[0] = new Sphere(new Vec3(-2.0, 0.0, -3.5), 0.5);
  25. spheres[1] = new Sphere(new Vec3(-0.5, 0.0, -3.0), 0.5);
  26. spheres[2] = new Sphere(new Vec3(1.0, 0.0, -2.2), 0.5);
  27. plane = new Plane(new Vec3(0.0, -0.5, 0.0), new Vec3(0.0, 1.0, 0.0));
  28. }
  29.  
  30.  
  31. public function mkColor(r:Number, g:Number, b:Number):uint
  32. {
  33. var ri:uint = uint(r * 255.5);
  34. if (ri < 0) ri = 0;
  35. if (ri > 255) ri = 255;
  36.  
  37. var gi:uint = uint(g * 255.5);
  38. if (gi < 0) gi = 0;
  39. if (gi > 255) gi = 255;
  40.  
  41. var bi:uint = uint(b * 255.5);
  42. if (bi < 0) bi = 0;
  43. if (bi > 255) bi = 255;
  44.  
  45. return (ri << 16) | (gi << 8) | bi;
  46.  
  47. }
  48.  
  49. public function orthoBasis(basis:Array, n:Vec3):void
  50. {
  51. basis[2] = new Vec3(n.x, n.y, n.z);
  52. basis[1] = new Vec3(0.0, 0.0, 0.0);
  53.  
  54. if ((n.x < 0.6) && (n.x > -0.6)) {
  55. basis[1].x = 1.0;
  56. } else if ((n.y < 0.6) && (n.y > -0.6)) {
  57. basis[1].y = 1.0;
  58. } else if ((n.z < 0.6) && (n.z > -0.6)) {
  59. basis[1].z = 1.0;
  60. } else {
  61. basis[1].x = 1.0;
  62. }
  63.  
  64. basis[0] = basis[1].cross(basis[2]);
  65. basis[0].normalize();
  66.  
  67. basis[1] = basis[2].cross(basis[0]);
  68. basis[1].normalize();
  69.  
  70. }
  71.  
  72. public function computeAO(isect:Intersection):Vec3
  73. {
  74. var i:int, j:int;
  75.  
  76. var ntheta:int = NAO_SAMPLES;
  77. var nphi:int = NAO_SAMPLES;
  78. var eps:Number = 0.0001;
  79.  
  80. // Slightly move ray org towards ray dir to avoid numerical probrem.
  81. var p:Vec3 = new Vec3(isect.p.x + eps * isect.n.x,
  82. isect.p.y + eps * isect.n.y,
  83. isect.p.z + eps * isect.n.z);
  84.  
  85. // Calculate orthogonal basis.
  86. var basis:Array; basis = new Array(3);
  87. orthoBasis(basis, isect.n);
  88.  
  89. var occlusion:Number = 0.0;
  90.  
  91.  
  92. for (j = 0; j < ntheta; j++) {
  93. for (i = 0; i < nphi; i++) {
  94.  
  95. // Pick a random ray direction with importance sampling.
  96. // p = cos(theta) / PI
  97. var r:Number = Math.random();
  98. var phi:Number = 2.0 * Math.PI * Math.random();
  99.  
  100. var x:Number = Math.cos(phi) * Math.sqrt(1.0 - r);
  101. var y:Number = Math.sin(phi) * Math.sqrt(1.0 - r);
  102. var z:Number = Math.sqrt(r);
  103.  
  104. // local -> global
  105. var rx:Number = x * basis[0].x + y * basis[1].x + z * basis[2].x;
  106. var ry:Number = x * basis[0].y + y * basis[1].y + z * basis[2].y;
  107. var rz:Number = x * basis[0].z + y * basis[1].z + z * basis[2].z;
  108.  
  109. var raydir:Vec3 = new Vec3(rx, ry, rz);
  110.  
  111. var ray:Ray = new Ray(p, raydir);
  112.  
  113. var occIsect:Intersection = new Intersection();
  114. spheres[0].intersect(occIsect, ray);
  115. spheres[1].intersect(occIsect, ray);
  116. spheres[2].intersect(occIsect, ray);
  117. plane.intersect(occIsect, ray);
  118.  
  119. if (occIsect.hit) occlusion += 1.0;
  120.  
  121. }
  122. }
  123.  
  124. // [0.0, 1.0]
  125. occlusion = (ntheta * nphi - occlusion) / (ntheta * nphi);
  126.  
  127. return new Vec3(occlusion, occlusion, occlusion);
  128.  
  129. }
  130.  
  131.  
  132.  
  133. public function AmbientOcclusion()
  134. {
  135.  
  136. initScene();
  137.  
  138. var w:int = 256;
  139. var h:int = 256;
  140. var nsubsamples:int = 2;
  141.  
  142. bitmapData = new BitmapData(w, h);
  143. bitmap = new Bitmap(bitmapData);
  144. addChild(bitmap);
  145.  
  146. var startTime:uint, endTime:uint;
  147. startTime = getTimer();
  148.  
  149. for (var i:int = 0; i < w; i++) {
  150. for (var j:int = 0; j < h; j++) {
  151.  
  152. var fcol:Vec3 = new Vec3(0.0, 0.0, 0.0);
  153.  
  154. // subsampling
  155. for (var v:int = 0; v < nsubsamples; v++) {
  156. for (var u:int = 0; u < nsubsamples; u++) {
  157. var px:Number = (i + (u / Number(nsubsamples)) - (w / 2.0))/(w / 2.0);
  158. var py:Number = (j + (v / Number(nsubsamples)) - (h / 2.0))/(h / 2.0);
  159. py = -py; // flip Y
  160.  
  161. trace(py);
  162.  
  163. var t:Number = 10000.0;
  164. var eye:Vec3 = new Vec3(px, py, -1.0);
  165. eye.normalize();
  166.  
  167. var ray:Ray = new Ray(new Vec3(0.0, 0.0, 0.0), new Vec3(eye.x, eye.y, eye.z));
  168.  
  169. var isect:Intersection = new Intersection();
  170. spheres[0].intersect(isect, ray);
  171. spheres[1].intersect(isect, ray);
  172. spheres[2].intersect(isect, ray);
  173. plane.intersect(isect, ray);
  174.  
  175. if (isect.hit) {
  176.  
  177. var col:Vec3 = computeAO(isect);
  178.  
  179. fcol.x += col.x;
  180. fcol.y += col.y;
  181. fcol.z += col.z;
  182. }
  183. }
  184. }
  185.  
  186. fcol.x /= Number(nsubsamples * nsubsamples);
  187. fcol.y /= Number(nsubsamples * nsubsamples);
  188. fcol.z /= Number(nsubsamples * nsubsamples);
  189.  
  190. bitmapData.setPixel(i, j, mkColor(fcol.x, fcol.y, fcol.z));
  191. //bitmapData.setPixel(i, j, mkColor(eye.x, eye.y, eye.z));
  192. }
  193. }
  194.  
  195. endTime = getTimer();
  196.  
  197. var elapsed:uint = (endTime - startTime) / 1000; // msec -> sec
  198.  
  199. // display render time
  200. var text:TextField = new TextField();
  201. text.text= elapsed + " sec";
  202. text.x = 10;
  203. text.y = 10;
  204. text.textColor = 0xFFFFFF;
  205. addChild(text);
  206. }
  207. }
  208. }
  209.  
  210. //
  211. // -- Common classes for a global illumination renderer.
  212. //
  213. class Vec3
  214. {
  215. public var x:Number;
  216. public var y:Number;
  217. public var z:Number;
  218.  
  219. public function Vec3(x:Number = 0.0, y:Number = 0.0, z:Number = 0.0)
  220. {
  221. this.x = x;
  222. this.y = y;
  223. this.z = z;
  224. }
  225.  
  226. public function length():Number
  227. {
  228. return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
  229. }
  230.  
  231. public function normalize():void
  232. {
  233. var dist:Number = this.length();
  234.  
  235. var invdist:Number = 1.0
  236. if (Math.abs(dist) > 1.0e-6) {
  237. invdist = 1.0 / dist;
  238. }
  239.  
  240. this.x *= invdist;
  241. this.y *= invdist;
  242. this.z *= invdist;
  243. }
  244.  
  245. public function add(b:Vec3):Vec3
  246. {
  247. return new Vec3(this.x + b.x, this.y + b.y, this.z + b.z);
  248. }
  249.  
  250. public function sub(b:Vec3):Vec3
  251. {
  252. return new Vec3(this.x - b.x, this.y - b.y, this.z - b.z);
  253. }
  254.  
  255. public function cross(b:Vec3):Vec3
  256. {
  257. var s:Number = this.y * b.z - this.z * b.y;
  258. var t:Number = this.z * b.x - this.x * b.z;
  259. var q:Number = this.x * b.y - this.y * b.x;
  260.  
  261. return new Vec3(s, t, q);
  262. }
  263.  
  264. public function dot(b:Vec3):Number
  265. {
  266. return this.x * b.x + this.y * b.y + this.z * b.z;
  267. }
  268.  
  269. }
  270.  
  271. class Ray
  272. {
  273. public var org:Vec3;
  274. public var dir:Vec3;
  275.  
  276. public function Ray(o:Vec3, d:Vec3)
  277. {
  278. this.org = o;
  279. this.dir = d;
  280. }
  281. }
  282.  
  283. class Intersection
  284. {
  285. public var t:Number;
  286. public var p:Vec3; // hit point
  287. public var n:Vec3; // normal
  288. public var hit:Boolean;
  289.  
  290. public function Intersection() {
  291. hit = false;
  292. t = 1.0e+30;
  293. n = new Vec3(0.0, 0.0, 0.0);
  294. }
  295. }
  296.  
  297. class Sphere
  298. {
  299. public var center:Vec3;
  300. public var radius:Number;
  301.  
  302. public function Sphere(center:Vec3, radius:Number) {
  303. this.center = center;
  304. this.radius = radius;
  305. }
  306.  
  307. public function intersect(isect:Intersection, ray:Ray):void
  308. {
  309. // rs = ray.org - sphere.center
  310. var rs:Vec3 = ray.org.sub(this.center);
  311. var B:Number = rs.dot(ray.dir);
  312. var C:Number = rs.dot(rs) - (this.radius * this.radius);
  313. var D:Number = B * B - C;
  314.  
  315. if (D > 0.0) {
  316. var t:Number = -B - Math.sqrt(D);
  317. if ( (t > 0.0) && (t < isect.t) ) {
  318. isect.t = t;
  319. isect.hit = true;
  320.  
  321. // calculate normal.
  322. var p:Vec3 = new Vec3(ray.org.x + ray.dir.x * t,
  323. ray.org.y + ray.dir.y * t,
  324. ray.org.z + ray.dir.z * t);
  325. var n:Vec3 = p.sub(center);
  326. n.normalize();
  327. isect.n = n;
  328. isect.p = p;
  329. }
  330. }
  331. }
  332. }
  333.  
  334. class Plane
  335. {
  336. public var p:Vec3; // point on the plane
  337. public var n:Vec3; // normal to the plane
  338.  
  339. public function Plane(p:Vec3, n:Vec3) {
  340. this.p = p;
  341. this.n = n;
  342. }
  343.  
  344. public function intersect(isect:Intersection, ray:Ray):void
  345. {
  346. // d = -(p . n)
  347. // t = -(ray.org . n + d) / (ray.dir . n)
  348. var d:Number = -p.dot(n);
  349. var v:Number = ray.dir.dot(n);
  350.  
  351. if (Math.abs(v) < 1.0e-6) return; // the plane is parallel to the ray.
  352.  
  353. var t:Number = -(ray.org.dot(n) + d) / v;
  354.  
  355. if ( (t > 0) && (t < isect.t) ) {
  356. isect.hit = true;
  357. isect.t = t;
  358. isect.n = n;
  359.  
  360. var p:Vec3 = new Vec3(ray.org.x + t * ray.dir.x,
  361. ray.org.y + t * ray.dir.y,
  362. ray.org.z + t * ray.dir.z);
  363. isect.p = p;
  364. }
  365. }
  366. }
Add Comment
Please, Sign In to add comment