0

I am playing around with a simple code that generates a shaded sphere. I don't yet fully understand the math but I am figuring it out as I play with the code. I was wondering how one might implement specular shading into this based on this code. Any suggestions?

for (y=0;y<screenHeight;y++)
for (x=0;x<screenWidth;x++)
if (sqr((x-xcenter)*(x-xcenter)+(y-ycenter)*(y-ycenter))<radius)
 {
 vx=(x-xcenter);
 vy=(y-xcenter);
 vz=sqr(radius*radius-vx*vx-vy*vy);
 vl=sqr(vx*vx+vy*vy+vz*vz);
 co_angle=(lx*vx+ly*vy+lz*vz)/(ll*vl);
 pixel=co_angle*255;
 }

I was looking at this thread and the second image is what I am after. But I also don't fully understand the math there either: Trouble with Phong Shading

Thanks in advance.

Community
  • 1
  • 1
Rich95
  • 199
  • 1
  • 3
  • 18
  • lx,ly,lz are light location. ll is light length: ll=sqr(lx*lx+ly*ly+lz*lz); – Rich95 May 23 '15 at 06:01
  • just a silly suggestion since this is tagged C++ didn't you mean `sqrt` instead of all the `sqr` ? Also if you compare against `radius*radius` you can ignore the sqrt for more speed,... Also I would compute the `vx,vy` before `if` and use `if (vx*vx+vy*vy – Spektre May 23 '15 at 07:41
  • Sorry, there was a typo in my first comment. Here it is again: lx,ly,lz are light location. ll is light length: `ll=sqr(lx*lx+ly*ly+lz*lz);` Spektre, I agree with your comments but any suggestions about the specularity? – Rich95 May 24 '15 at 00:11

1 Answers1

0

To add reflection first you need mirror light vector by surface normal

  • reflections
  • all these are unit vectors:
  • l - (yellow) to light source
  • n - (aqua) surface normal
  • r - (green) reflected light direction
  • e - (orange) to eye/camera direction
  • points:
  • p - (red) - rendered pixel position
  • q - (magenta) - reflection midpoint
  • axises:
  • brown - reflection midpoint
  • yellow - to light
  • gray - to eye/camera

So how to do it?

  • n,p,e,l are knowns or can be easily computed
  • if light is directional then l is constant for all pixels
  • if light source is a point then l=light_pos-p; l/=|l|;
  • e=eye_pos-p; e/=|e|;
  • now you need to find point q I use dot product for this q=p+(n*dot(l,n));
  • now the r vector is easy r=(p+l)+2*(q-(p+l))-p=2*(q-p)-l;
  • hope I did not make a silly math mistake/typo somewhere but it should be clear how I obtain the equations

now you have reflection vector r

  • so add shading by multiplying pixel color by m=light_color*dot(r,e)+ambient_light;
  • to add specular spots you need add to m the maximal reflections which are present only near r
  • so ca=cos(ang)=dot(r,e); you do not need ang directly cosine is fine
  • now to limit the specular cone size do ca=pow(ca,5.0) can use any exponent
  • this will lower the values below one so it is much much less then raw cosine
  • the bigger the exponent the smaller spot cone size so now:
  • m=(light_color*0.5*(ca+dot(r,e)))+ambient_light;
  • you can also add mixing coefficients to change the ratio between specular and normal reflection light strength
  • now render pixel p with color=surface_color*m;

Hope I didn't forget something it is a while I coded something like this...

Spektre
  • 49,595
  • 11
  • 110
  • 380
  • Hey guys - thanks for a very detailed question. Since I'm trying to understand the maths behind all this, and more importantly how to implement it in C, I'll ask some potentially dumb questions. Such as: how do you calculate a dot product? So how would one calculate `dot(l,n)`? Also, what does the bar on each side of a variable mean: `|l|`. And if anyone has suggestions on how this is applied with the original code, that might help get me started as well. Thanks! – Rich95 May 25 '15 at 17:34
  • @Rich95 LOL that is basic vector math ... the "bars" `|x|` means `abs(x)` for scalars and if `x` is vector then it means its size so `|x|=sqrt(x.x*x.x+x.y*x.y+x.z*x.z)`and `dot(a,b)=a.x*b.x+a.y*b.y+a.z*b.z` where `a,b` are vectors and the result is scalar (single value) .. sometimes it is written like this: `(a.b)` and if both `a,b` are unit vectors (they have size=1) then the result is `cos(angle between a,b)` How to heck you get to 3D shading without basic vector math knowledge? btw the line `co_angle=` in your code is dot product ... – Spektre May 25 '15 at 19:25