SphereCam.m 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. function [in] = SphereCam()
  2. %SphereCam Render & look at a sphere in space
  3. % In order to create each sphere, takes in the following user input:
  4. % (vectors should be entered [x;y;z])
  5. % Viewpoint (the point from which rays are cast - vector)
  6. % (note: the z-value should be negative; origin - z taken for focal
  7. % length)
  8. % Resolution (the image is this many pixels square - scalar)
  9. % Size (the pixels fit into this distance - scalar)
  10. % Light direction vector (direction towards the light source at infinity)
  11. % Center of the sphere (vector)
  12. % Radius of the sphere (scalar)
  13. % Albedo of the sphere (how dark or light the surface is - scalar)
  14. % Gloss value (the proportion of non-Lambertian effect - scalar)
  15. % Gloss sharpness (closeness to mirror finish - scalar)
  16. % Ambient light level (how bright the background is - scalar)
  17. %
  18. % Then it renders the space specified, including the sphere if it is
  19. % in the field of view. The camera can be moved by additional user input
  20. %%%%%%%%%********* check it
  21. % Track: enter a translation vector [x;y;z].
  22. % x>0 moves view right; x<0 moves view left
  23. % y>0 moves view up; y<0 moves view down
  24. % z>0 moves towards sphere; z<0 moves away from sphere
  25. % [it zooms]
  26. % Pan: enter an angle in degrees
  27. % angle > 0 pans right; angle < 0 pans left
  28. % (pans right == sphere shifts left, and vice versa)
  29. % Tilt: enter an angle in degrees
  30. % angle > 0 tilts up; angle < 0 tilts down
  31. % (tilts up == sphere shifts down, and vice versa)
  32. %
  33. % Once the user is done playing with the camera, they can make a new
  34. % sphere or simply exit.
  35. in = input('New sphere? ', 's');
  36. while(in ~= 'n')
  37. % massive amounts of taking-in of input
  38. viewpoint = input('Viewpoint: ');
  39. viewdir = Normalize(viewpoint);
  40. res = input('View resolution: ');
  41. size = input('View size: ');
  42. % focal length is just the distance from the origin on z of view
  43. focallen = 0 - viewpoint(3);
  44. retina = MakeRetina(res, size, focallen);
  45. lightvec = input('Light direction vector: ');
  46. % light direction is the light vector normalized
  47. lightdir = Normalize(lightvec);
  48. center = input('Center of the sphere: ');
  49. Sr = input('Radius of the sphere: ');
  50. % I don't know how to make stripes
  51. albedo = input('Albedo of the sphere (unpatterned): ');
  52. gloss = input('Gloss value of sphere (0 to 1): ');
  53. glossSharp = input('Gloss sharpness of sphere: ');
  54. ambient = input('Ambient light level: ');
  55. paint = PaintSphere(viewpoint, retina);
  56. imshow(mat2gray(paint));
  57. in2 = input('Want to move the camera? ', 's');
  58. % any input except n will move this forward
  59. while(in2 ~= 'n')
  60. mvmt = input('Track (tr), Pan (p), or Tilt (t)? ', 's');
  61. switch(mvmt)
  62. case 'tr'
  63. trans = input('Translation vector: ');
  64. retina = Track(retina, trans);
  65. paint = PaintSphere(viewpoint, retina);
  66. imshow(mat2gray(paint));
  67. in2 = input('Again? ','s');
  68. case 'p'
  69. pan = input('Angle to pan: ');
  70. retina = Pan(retina, pan);
  71. paint = PaintSphere(viewpoint, retina);
  72. imshow(mat2gray(paint));
  73. in2 = input('Again? ','s');
  74. case 't'
  75. tilt = input('Angle to tilt: ');
  76. retina = Tilt(retina, tilt);
  77. paint = PaintSphere(viewpoint, retina);
  78. imshow(mat2gray(paint));
  79. in2 = input('Again? ','s');
  80. case 'n'
  81. in2 = 'n';
  82. otherwise
  83. in2 = input('Sorry, invalid choice. Try again? ', 's');
  84. end
  85. end
  86. in = input('Nother sphere? ', 's');
  87. end
  88. % the 'retina' is the frame on which the sphere is projected
  89. function retina = MakeRetina(n, mm, focallen)
  90. retina = zeros(3,n^2+1);
  91. k = mm/n; % the distance between pixels
  92. for l = 1:n^2
  93. % because it's basically a 1-D array of 3-vectors,
  94. % instead of a 2-D one, figuring out what row a
  95. % pixel actually belongs to is trickier
  96. if mod(l, n) == 0
  97. retina(1, l) = n*k - mm/2;
  98. else
  99. retina(1, l) = mod(l, n) * k - mm/2;
  100. end
  101. retina(2, l) = ceil(l/n) * k - mm/2;
  102. retina(3, l) = focallen;
  103. end
  104. retina(1:3, n^2+1) = viewpoint;
  105. %retina(2, n^2+1) = viewpoint(2);
  106. %retina(3, n^2+1) = viewpoint(3);
  107. % the final bit is the viewpoint, to make camera movement work
  108. end
  109. % translate the camera in space
  110. function newretina = Track(retina, trans)
  111. n = length(retina);
  112. newretina = zeros(3, n);
  113. for l = 1:n
  114. newretina(1:3,l) = retina(1:3,l) + trans;
  115. %newretina(2,l) = retina(2,l) + trans(2);
  116. %newretina(3,l) = retina(3,l) + trans(3);
  117. end
  118. viewpoint = newretina(1:3, n);
  119. %viewpoint(2) = newretina(2, n);
  120. %viewpoint(3) = newretina(3, n);
  121. end
  122. % look from left to right
  123. function newretina = Pan(retina, angle)
  124. RotY = [cosd(angle),0,sind(angle);0,1,0;-sind(angle),0,cosd(angle)];
  125. n = length(retina);
  126. newretina = zeros(3, n);
  127. for l = 1:n
  128. newretina(1:3,l) = retina(1:3,l)-viewpoint;
  129. newretina(1:3,l) = RotY*newretina(1:3,l);
  130. newretina(1:3,l) = newretina(1:3,l)+viewpoint;
  131. % retpt = zeros(3, 1);
  132. % retpt = retina(1:3,l);
  133. % %retpt(2) = retina(2,l);
  134. % %retpt(3) = retina(3,l);
  135. % newpt = RotY*(retpt - viewpoint) + viewpoint;
  136. % newretina(1,l) = newpt(1);
  137. % newretina(2,l) = newpt(2);
  138. % newretina(3,l) = newpt(3);
  139. end
  140. viewpoint = newretina(1:3, n);
  141. %viewpoint(2) = newretina(2, n);
  142. %viewpoint(3) = newretina(3, n);
  143. end
  144. % look up and down
  145. function newretina = Tilt(retina, angle)
  146. RotX = [1,0,0;0,cosd(angle),-sind(angle);0,sind(angle),cosd(angle)];
  147. n = length(retina);
  148. newretina = zeros(3, n);
  149. for l = 1:n
  150. newretina(1:3,l) = retina(1:3,l)-viewpoint;
  151. newretina(1:3,l) = RotX*newretina(1:3,l);
  152. newretina(1:3,l) = newretina(1:3,l)+viewpoint;
  153. % retpt = zeros(3,1);
  154. % retpt(1) = retina(1,l);
  155. % retpt(2) = retina(2,l);
  156. % retpt(3) = retina(3,l);
  157. % newpt = RotX*(retpt - viewpoint) + viewpoint;
  158. % newretina(1,l) = newpt(1);
  159. % newretina(2,l) = newpt(2);
  160. % newretina(3,l) = newpt(3);
  161. end
  162. viewpoint = newretina(1:3, n);
  163. %viewpoint(2) = newretina(2, n);
  164. %viewpoint(3) = newretina(3, n);
  165. end
  166. % Make a vector into a unit vector
  167. function norm = Normalize(point)
  168. w = sqrt(point(1)^2 + point(2)^2 + point(3)^2);
  169. norm = [point(1)/w; point(2)/w; point(3)/w];
  170. end
  171. % Paint the sphere onto the retina
  172. function paintmat = PaintSphere(viewpoint, retina)
  173. % find the surface normal vector of a point
  174. % normalize the point if the circle were centered on the origin
  175. function normal = SurfNorm(point)
  176. normal = Normalize(point - center);
  177. end
  178. % dot product of two vectors/points
  179. function dot = MyDot(point1, point2)
  180. dot = point1(1)*point2(2)+point1(2)*point2(2)+point1(3)*point2(3);
  181. end
  182. % the brightness at a given point on the sphere
  183. function bright = Brightness(point, intersect)
  184. if intersect > 0 % the point is on the sphere
  185. n = SurfNorm(point);
  186. if MyDot(n,lightdir) >= 0 % if I'm not self-shadowed
  187. % equation courtesy of the assignment materials
  188. C = 2*MyDot(n,lightdir)*MyDot(n,viewdir) - MyDot(viewdir,lightdir);
  189. bright = albedo*(gloss*C^glossSharp + (1-gloss)*MyDot(lightdir,n)) + ambient/2;
  190. if bright < 0 % if somehow the brightness is negative
  191. bright = 0+ambient/2;
  192. end
  193. else %self-shadowed brightness det. by ambient light
  194. bright = 0 + ambient/2;
  195. end
  196. else
  197. bright = ambient;
  198. end
  199. end
  200. % casting the ray of light to see if I hit the sphere
  201. % returns the point and the intersect value
  202. function [pointintersect] = Pixel2Point(pixel)
  203. x1 = viewpoint(1);
  204. y1 = viewpoint(2);
  205. z1 = viewpoint(3);
  206. x2 = pixel(1);
  207. y2 = pixel(2);
  208. z2 = pixel(3);
  209. x3 = center(1);
  210. y3 = center(2);
  211. z3 = center(3);
  212. % complicated equation from Bourke
  213. % to be plugged into au^2 + bu + c
  214. a = (x2-x1)^2 + (y2-y1)^2 + (z2-z1)^2;
  215. b = 2*((x2-x1)*(x1-x3)+(y2-y1)*(y1-y3)+(z2-z1)*(z1-z3));
  216. c = x3^2+y3^2+z3^2+x1^2+y1^2+z1^2-2*(x3*x1+y3*y1+z3*z1) - Sr^2;
  217. intersect = b^2 - 4*a*c;
  218. if intersect < 0 % then I don't hit the sphere
  219. dist = center(3);
  220. point = pixel;
  221. point(3) = point(3)+dist;
  222. else
  223. if intersect == 0 % I'm on the edge
  224. u = -b/(2*a);
  225. point = viewpoint + u*(pixel - viewpoint);
  226. else % intersect at two places
  227. u1 = (-b + sqrt(intersect))/(2*a);
  228. u2 = (-b - sqrt(intersect))/(2*a);
  229. u = max(u1, u2); % pick the larger intersect value
  230. point = viewpoint + u*(pixel - viewpoint);
  231. end
  232. end
  233. pointintersect = [point(1);point(2);point(3);intersect];
  234. end
  235. paintmat = zeros(res, res);
  236. pixel = zeros(3,1);
  237. for i = 1:res
  238. for j = 1:res
  239. % for each pixel, find its intersect & brightness
  240. pixel(1) = retina(1,j+(i-1)*res);
  241. pixel(2) = retina(2,j+(i-1)*res);
  242. pixel(3) = retina(3,j+(i-1)*res);
  243. px2pt = Pixel2Point(pixel);
  244. point = px2pt(1:3);
  245. intersect = px2pt(4);
  246. paintmat(i,j) = Brightness(point, intersect);
  247. end
  248. end
  249. end
  250. end