Computer Graphics Solutions to Homework 3 CS417/CS418 Fall 1998 Due Wednesday, February 24, 1999 ################################ CS417 part ################################# 1. simple solution: call the original (row-vector) version of raysphere in the following modification of the j loop in drawspheres: for j = 1:size(l,2) for j = 1:size(l,2) ...BODY... --> hit = 0; end for k = 1:size(c,2) if k~=i & raysphere([x y z],l(:,j)',c(:,k)',r(k)') hit = 1; end end if ~hit ...BODY... end end since "&" is not short-circuiting, we always shoot a ray from the sphere the pixel is "on". this can be avoided by changing the k loop to "for k = [1:i-1 i+1:size(c,2)]" and eliminating "k~=i &". here is an even better solution. there is no need to compute where an intersection occurs or the surface normal. since we're assuming few shadows/intersections), we expect to process all the spheres. and we wish to avoid loops. so add % create list of spheres with i-th sphere deleted otherc = c; otherc(:,i) = []; otherr = r; otherr(i) = []; at the very top of the i loop and modify the j loop to for j = 1:size(l,2) if ~rayspheres([x ; y ; z], l(:,j), otherc, otherr) ...BODY... end end where rayspheres is defined as follows: function [hit] = rayspheres(origin, direction, center, radius) % [HIT] = RAYSPHERES(ORIGIN,DIRECTION,CENTER,RADIUS) % compute whether a ray intersects any one of multiple spheres; % assume answer is usually NO % % ORIGIN: start of ray % DIRECTION: normalized direction of ray % CENTER: centers CENTER(1:3,i) of spheres % RADIUS: radii RADIUS(i) of spheres % % HIT: whether ray hits a sphere ( 0 = no, 1 = yes ) % % NOTE: assume the origin in strictly outside the spheres -- % no guarantees on result if origin is on or inside. nearestpoint = center' * direction - origin' * direction; i = find(nearestpoint>0); if isempty(i), hit=0; return; end; % avoid stupid bug in Matlab when i=[] origin = origin(:,ones(1,length(i))); % make 1 copy of origin for each i nearestpoint = direction * nearestpoint(i)' + origin - center(:,i); hit = any(sum(nearestpoint.^2) <= radius(i).^2); (page 2) here is a modification of the original "fancy" version, which first makes sure a light source is not "behind" the sphere before shooting rays towards the lightsource (using rayspheres above). alas, it is very hard to do this without loops, so a loop k is used. % get contributions of each light source where = [x' ; y' ; z']; otherc = c; otherc(:,i) = []; otherr = r; otherr(i) = []; for j = 1:size(l,2) dott = normal' * l(:,j); ok = find(dott>=0); ok2 = ok; % do shadows: test visibility for k = 1:length(ok) ok2(k) = rayspheres(where(:,ok(k)),l(:,j),otherc,otherr); end ok = ok(~ok2); if ~isempty(ok) % avoid stupid matlab problems with ok=[] dott = dott(ok)'; color(:,ok) = color(:,ok) + (kd(:,i) .* lc(:,j)) * dott; reflect = 2*normal(:,ok).*[dott;dott;dott] ... - l(:,j) * ones(1,length(ok)); dott = reflect' * v; dott = dott'; ok2 = dott >= 0; ok = ok(ok2); color(:,ok) = color(:,ok) + ks(i) * lc(:,j) * dott(ok2).^n(i); end end % for j _______________________________________________________________________________ 2. function [xx,yy,zz] = sweep(x,y,z,n) % [XX,YY,ZZ] = SWEEP(X,Y,Z,N) surface of revolution from sweeping curve % rotate curve given by equal-length row vectors x(1:m),y(1:m),z(1:m) % around z-axis, n samples, yielding (n+1)-by-m matrices for surf(xx,yy,zz) theta = linspace(0,2*pi,n+1); sintheta = sin(theta); costheta = cos(theta); xx = x' * costheta - y' * sintheta; yy = x' * sintheta - x' * costheta; zz = z' * ones(1,n+1); _______________________________________________________________________________ 3. % add a new column for orange ([1 ; .5 ; 0]) sphere c = [ ... % old: c = [ ... 20 40 30 0 % 20 40 30 50 30 15 10 % 50 30 15 0 30 20 20]; % 0 30 20]; r = [40 15 25 20]; % r = [40 15 25]; ka = [.1 .2 .3 .1]; % ka = [.1 .2 .3]; kd = [ ... % kd = [ ... .7 0 0 1 % .7 0 0 0 .8 0 .5 % 0 .8 0 0 0 1 0]; % 0 0 1]; ks = [.2 .4 .8 1]; % ks = [.2 .4 .8]; n = [1 5 10 20]; % n = [1 5 10]; (continued, with some white space suppressed to make things fit ...) (page 3) hold on; ambient = [.4 .4 0]'; l = [ 0 -1 -1 ; 1 -1 0 ; -1 -1 -1]; lc = [1 1 0 ; 1 0 1 ; 1 0 1]; for j = 1:size(l,2), light('Position',-l(:,j),'Color',lc(:,j)); end for i = 1:size(c,2) [x,y,z] = sphere; normals(:,:,1) = x; normals(:,:,2) = y; normals(:,:,3) = z; % N E W <---- x = x*r(i)+c(1,i); y = y*r(i)+c(2,i); z = z*r(i)+c(3,i); h = surf(x,y,z); set(h,'VertexNormals',normals); % N E W <---- set(h,'EdgeColor','none','FaceColor',kd(:,i),'AmbientStrength',ka(i)); set(h,'SpecularStrength',ks(i),'SpecularExponent',n(i)); end set(gca,'AmbientLightColor',ambient); axis equal; axis tight; lighting phong ################################ CS418 part ################################# 4. function [] = tree(position,direction,width) % tree(position,direction,width). recursively (until width<1) draw a tree as: % 1. a trunk of length 2*width and given width % rotated by direction radians counterclockwise % 2. two branches obtained by placing % a triangle with a random angle atop the trunk. % % example: clf; axis equal; hold on; tree([0 ; 0], pi/2, 20) if width<1, return; end length = 2*width; theta = rand * pi/2; normal = direction - pi/2; % vertices of rectangle, going clockwise v = position; v2 = position + [cos(direction) ; sin(direction)] * length; v4 = width*[cos(normal) ; sin(normal)]; v3 = v2 + v4; v4 = v4+position; a = width*cos(theta); % width of left branch normal = normal+theta; peak = v2+a*[cos(normal) ; sin(normal)]; % "peak" of triangle corners = [v v2 peak v3 v4 v]; colors = 'rgbcmyk'; % fill rectangle and triangle with a random color fill(corners(1,:),corners(2,:),colors(ceil(rand*7))); tree(v2, theta+direction, a); tree(peak, normal, sin(theta)*width); 5. see answer and example given in lecture. briefly: assume a pixel (x,y) covers a unit square with corners (x +/- 1/2, y +/- 1/2) and that its color "should" be the average (i.e. integral) of the color of each point in this square. then edges are jaggy because the color suddenly changes in the pixel, so the average color is very different from the color in the center of the pixel. however, pixels "inside" look good because the color changes gradually, so the center color is approximately the average color. also, the jumps in color between centers of pixels and average colors of pixels are about the same size.