Archived

This topic is now archived and is closed to further replies.

EDI

Parabolic Maddness

Recommended Posts

no, it''s not a fatal mental dissease ;-) i am working on drawing a directional ''light'' on a 2d surface, i have discoverd how to make a very perfect symetrical radial light sphere by using the distance formula to plot a circle inside a square and determine alpha values, but what i would really like to do is draw a parabolic light, e.g kinda like a floodlight, i was able to draw a parabola between 3 control points using the quadradic equasion, unfortunetly, filling it is another story, i first tried walking up each edge and filling horizontaly, but when the light was rotated to certain angles it would show ''holes'' between the fill lines, so i guess my question is does anyone know how to plot out a directional light?
  
      /\\
      /\ \
      / \ \        
      [dest]

forgive the horrible ascii art, but that is sort of a top view of what i need to draw,

any infromation is apreciated,
thanks in advance
:-)

  
Raymond Jacobs, Profesional Web Applications Developer, Weekend Game Developer, www.EtherealDarkness.com

Share this post


Link to post
Share on other sites
It *might* be easier to actually do a trace from each point back to the light and use spotlight formulae to work out the intensity. Depends what you want to use it for I guess.

Share this post


Link to post
Share on other sites
JuNC is on the right track here. Drawing a parabola really is a hack. It will almost certainly be easier to use the real equations instead, and it will look good from any angle.

Just treat your light as a 3D source projecting on your 2D world. The calculations to perform are very easy: for each point, just take a vector from the point on the 2D surface towards the lightsource, normalize it, and compute the dotproduct between this vector and the plane normal of your 2D surface. If your 2D surface is axis aligned (most likely), then this computation can be highly simplified, as two normal components will be zero.

/ Yann

Share this post


Link to post
Share on other sites
i have tried that,

the problem is when i draw the lines out from the vector,
they either leave holes or overlap, im using a common line algorythm,when the lines overlay the alpha builds up and causes an unatual patern to the light




i use something like this


for(t=0;t<45;t++)
{
//draw a line at angle t with length of 100
}

this leaves holes,

if i increase t by floating point increments it closes up the holes but they areas of the light are drawn twice
and the alpha build up makes the light look unnatural

Raymond Jacobs,
Profesional Web Applications Developer,
Weekend Game Developer,
www.EtherealDarkness.com

[edited by - EDI on October 18, 2002 9:06:34 AM]

[edited by - EDI on October 18, 2002 9:10:24 AM]

Share this post


Link to post
Share on other sites
I think you may have misinterpreted what they were saying. Instead of drawing it by doing lots of lines, cycle through and do it pixel by pixel, checking the exact intensity of the light as it affects that specific pixel and use that to draw that single pixel. Then move to the next one, lather, rinse and repeat.

There are no holes, because you do each pixel individually, and there is no overdraw.

Trying is the first step towards failure.

Share this post


Link to post
Share on other sites
i have also tried the method pixel for pixel,

the problem is that im using sine and cosine to determine the position of a pixel at a certain angle,

depending on the precision i use as the length increases the distance between pixels increases,
so twoards the source the overdraw is very great and twoards the end holes might apear

Raymond Jacobs,
Profesional Web Applications Developer,
Weekend Game Developer,
www.EtherealDarkness.com

Share this post


Link to post
Share on other sites
I don''t understand, why you''d need to use cos/sin to determine the pixels affected. The usual way to do that, is as follows:

*) project the light''s bounding area onto the plane, create an axis aligned bounding rectangle containing it.

*) scan through all points in this rectangle (simply two nested loops) and compute the light intensity at each pixel using the dotproduct.

The result will be a nice projected light cone, without any holes. Alternatively, instead of computing the bounding rectangle, you could simply loop through all the pixels on your surface. That''s quite a waste of performance, but it doesn''t really matter that muc if your lighting is done as a preprocess.

/ Yann

Share this post


Link to post
Share on other sites
i dont know what you mean by
"
*) project the light's bounding area onto the plane
"

here are my inputs,

the source coordinets x,y
the theta *direction* of the light
and the angle relative to the theta where it will depart from the light source
*apeture*
*think of a lighthouse, but looking straight down on top of it, that is what i want the light to look like*



"
create an axis aligned bounding rectangle containing it.
"
what do you mean by axis algined?
"
*) scan through all points in this rectangle (simply two nested loops) and compute the light intensity at each pixel using the dotproduct.
"

i know how to scan through a rectangle, but i havent
really used dotproduct, i know is is multiplication of scalars or somthing, right?

anyway, if there is a tutorial, of if anyone wants to offer some psuedo code, or even real code that will be helpful, since i havent ever doing anything with light theory

Raymond Jacobs,
Profesional Web Applications Developer,
Weekend Game Developer,
www.EtherealDarkness.com

[edited by - EDI on October 18, 2002 10:25:25 AM]

Share this post


Link to post
Share on other sites

Question: do you want a 100% 2D light cone ? In that case, just use your original radial light equation, and include an agle dependend cutoff value for the spot effect. This is a logical extension to your spherical light sphere. But it will look totally 2D.

Or do you want a pseudo-3D effect, eg. like when seing a lighthouse from above: the cone will touch the ground from a certain height, so the 2D cone will be somewhat distorted due to the perspective, which gives a ''3D feeling'' to the lightsource (neglecting the fact, that a lighthouse that actually projects it''s cone onto the ground would be malfunctioing in the real world )

In the later case, you''ll have to use real 3D computations onto the 2D surface, as described above. If that''s what you want, let me know, I could post some pseudo code (it''s pretty simple).

/ Yann

Share this post


Link to post
Share on other sites
what i want is basicly this,

take a cone, sit it on it's base

slice the cone in half verticly,

then lay the cone down on the flat side that was created from the slice

it's outline is roughly the shape of a pizza slice,

but because the cone is a 3d object light brightness will be greator on the top of the cone and falloff the edges,

, but basicly,


i want a pizza slice, wheerin the pixels that are plotted decrase in brightness the futher away they are , falloff.

i can acive the computation for the dimming, but i dont know how to plot the slice without holes forming or without drawing certain pixels more than once,

ive only managed to draw an entire circle, not a slice, using the rectangular method,

so i guess my need is, how do i draw a slice of a filled circle,wherein no pixels overlap in the fill



Raymond Jacobs,
Profesional Web Applications Developer,
Weekend Game Developer,
www.EtherealDarkness.com

[edited by - EDI on October 18, 2002 10:44:01 AM]

Share this post


Link to post
Share on other sites
OK, no 3D then. Makes it easier

As a base, take your spherical light renderer. I assume that you have a center for the light sphere (xc, yc) and then loop through the rectangle around it, while computing the intensities.

Now, you have a normalized vector from the center to each pixel under consideration. The vector you computed to get the intensity of the pixel, ie. the distance from the center to the pixel. You can do more with that vector.

Assume that you have three new paramaters for your light: the direction of the cone (a normalized 2D vector), the cutoff angle (controls how wide the resulting cone will be) and a spotlight exponent (controls, how hard or soft the gradients in the spot cone will be) [Note: yes, that's the spot model from OpenGL ].

The normalized direction vector (from above) defines not only a distance, but also a direction. So first, you have to make sure that this direction is within the cone defined by the cone's direction vector and the maximum cutoff angle. You also need to know where in the cone the direction vector lies, so that the falloff gradients can be computed.

All that seems very complex, but it isn't. All you need is a simple dotproduct. A dotproduct is a mathematical operation between two vectors, the result is the cosine of the minimum angle between those.

Pseudo-code:

// xc, yc = center of your light
// cutoff = aperture angle of your cone / 2
// dir_x, dir_y = direction of the cone (normalized vector)
// spot_exp = spotlight exponent (range from 0.0 to infinity)

// loop through the rectangle around the center:
for( y=y1; y<=y2; y++ ) for( x=x1; x<=x2; x++ ) {
// compute the intensity of the radial sphere as you did before
intensity = (... your radial formula ...)

// get direction vector from center to current pixel
// (note that you might already have this vector from your calculation above)
v_x = x-xc;
v_y = y-yc;

// normalize it
l = sqrt(v_x*v_x + v_y*v_y);
if( l==0 ) continue;
v_x /= l;
v_y /= l;

// get the angle between the requested spot direction and the current pixel direction (dotproduct)
d = v_x*dir_x + v_y*dir_y;

// is the direction out of the cutoff bounds ? If yes, then continue
// (note that we compare to the cosine of the cutoff, as the result from the dotproduct was a cosine)
if( d < cos(cutoff) ) continue;

// OK, the pixel is within the cone.
// The dotproduct already computed the falloff, let's apply the exponent
spot_factor = pow(d, spot_exp);

// Finally, multiply the light sphere intensity from above with the spot factor
intensity *= spot_factor;

// Done. Plot the pixel
plotpixel(x, y, intensity);

}

That's it. Note that it's straight out of my head and untested, so there might be some little bug somewhere. Let me know if it doesn't work And it's obviously not optimized for speed (eg. the cos(cutoff) should be precomputed outside of the loop, etc).

/ Yann


[edited by - Yann L on October 18, 2002 11:25:40 AM]

Share this post


Link to post
Share on other sites
Thank you very much,

i will give it a try when i get home tonight,

@ work now,

ill reply here to let you know how it turns out ;-)

thanks again

Raymond Jacobs,
Profesional Web Applications Developer,
Weekend Game Developer,
www.EtherealDarkness.com

Share this post


Link to post
Share on other sites
mmm, quick question

// dir_x, dir_y = direction of the cone (normalized vector)

these values arnt set in the proccess, which i guess means i need to provide them,

could you explain what these values are supposed to be



hmm?? are they the end point of the line?

source(x,y)
'\'
'\'
'\'
(dir x,y)??


like the x2,y2 of a line?


Raymond Jacobs,
Profesional Web Applications Developer,
Weekend Game Developer,
www.EtherealDarkness.com

[edited by - EDI on October 18, 2002 11:53:02 AM]

[edited by - EDI on October 18, 2002 11:53:45 AM]

Share this post


Link to post
Share on other sites
dir_(xy) is just a (normalized) vector giving the spot direction. Imagine a little arrow sticking out from the center of the light. The direction of that arrow defines the direction the light cone is pointing towards. That arrow is dir_(xy). For a first try, set it to (0, 1). The light will then shine straight up (or down, depends on how you defined your coordinate system).

/ Yann

Share this post


Link to post
Share on other sites
hmm,
the code doesnt seem to work, ive tried a few ways to modify it but i cant seem to get it to work,

i looked in a linear alegebra book last night and like u said the dot or scalar product is the cosine of the triangle formed using the 2 vectors and the origin,

anyway, i still cant seem to get it to work,

could you please verify that the code you wrote works, and let me know and/or post code revisions

-thanks

Raymond Jacobs,
Profesional Web Applications Developer,
Weekend Game Developer,
www.EtherealDarkness.com

Share this post


Link to post
Share on other sites
Works fine over here. I just compiled a quick and dirty console version (the image is saved as a TGA file):


    
//

//


#include <math.h>
#include <stdio.h>

// Simple radial intensity function

float GetRadialIntensity(int x, int y, int xc, int yc)
{
float v_x = x-xc;
float v_y = y-yc;

float v = sqrt(v_x*v_x + v_y*v_y) * 2.0f;

return( 255.0f - (v > 255.0f ? 255.0f : v) );
}

// Spotlight function

void ComputeSpot(char *buffer)
{
float intensity, spot_factor;
float l, d, v_x, v_y;

// xc, yc = center of your light

int xc = 128;
int yc = 128;

// cutoff = aperture angle of your cone / 2

float cutoff = 40.0f;

// dir_x, dir_y = direction of the cone (normalized vector)

float dir_x = 0;
float dir_y = 1;

// spot_exp = spotlight exponent (range from 0.0 to infinity)

float spot_exp = 7.0f;

// convert to radians

cutoff = (cutoff / 180.0f) * 3.1415926f;

// loop through the rectangle around the center:

for( int y=0; y<=255; y++ ) for( int x=0; x<=255; x++ ) {

// compute the intensity of the radial sphere as you did before

intensity = GetRadialIntensity(x, y, xc, yc);

// get direction vector from center to current pixel

// (note that you might already have this vector from your calculation above)

v_x = x-xc;
v_y = y-yc;

// normalize it

l = sqrt(v_x*v_x + v_y*v_y);
if( l==0 ) continue;
v_x /= l;
v_y /= l;

// get the angle between the requested spot direction and the current pixel direction (dotproduct)

d = v_x*dir_x + v_y*dir_y;

// is the direction out of the cutoff bounds ? If yes, then continue

// (note that we compare to the cosine of the cutoff, as the result from the dotproduct was a cosine)

if( d < cos(cutoff) ) continue;

// OK, the pixel is within the cone.

// The dotproduct already computed the falloff, let's apply the exponent

spot_factor = pow(d, spot_exp);

// Finally, multiply the light sphere intensity from above with the spot factor

intensity *= spot_factor;

// Done. Plot the pixel

buffer[y*256+x] = intensity;
}
}

// Very quick'n'dirty TGA writer

void SaveTGA(char *fname, int xs, int ys, char *buffer)
{
FILE *fp = fopen(fname, "wb");

if( !fp ) {
printf("Couldn't write output file !\n");
return;
}

char header[18] = { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 4, 4, 24, 32 };
char rgb[3];

// write header

((unsigned short *)header)[6] = xs;
((unsigned short *)header)[7] = ys;
fwrite(header, 1, 18, fp);

// write body

for( int a=0; a<xs*ys; a++ ) {
rgb[0] = rgb[1] = rgb[2] = buffer[a];
fwrite(rgb, 3, 1, fp);
}

fclose(fp);
}

int main()
{
char *buffer = new char[256*256];

ComputeSpot(buffer);

SaveTGA("C:\\radial.tga", 256, 256, buffer);

delete [] buffer;
}


Here is the result:


Keep in mind, that this is highly unoptimized code.



[edited by - Yann L on October 21, 2002 1:57:56 PM]

Share this post


Link to post
Share on other sites
that is so exellent!!!!

thank you so much, it''s exactly what i was looking for!

Raymond Jacobs,
Profesional Web Applications Developer,
Weekend Game Developer,
www.EtherealDarkness.com

Share this post


Link to post
Share on other sites
the code works excellent,

i was just wondering, how would i rotate the light direction,

i know that changing

dir_x and dir_y

will change it on 90degree angles,

but what about 45''s and arbitrary angles

for instance

if i do dir_x=1 and dir_y=1

the spotlight becomes warped

any ideas?


Raymond Jacobs,
Profesional Web Applications Developer,
Weekend Game Developer,
www.EtherealDarkness.com

Share this post


Link to post
Share on other sites
quote:

if i do dir_x=1 and dir_y=1

the spotlight becomes warped


Yeah, because (1,1) is not normalized. Choose a target point on your 2D surface. Then: dir_(xy) = Target point - Lightcenter. Normalize dir_(xy), and it should work.

If you only want to specify a light direction angle, use dir_x = cos(angle), dir_y = sin(angle); (careful, angle must be in radians).

/ Yann

Share this post


Link to post
Share on other sites
perfect,

i used the cos/sin method
mainly because i dont know what a ''normal'' vector is,

after reading my linear alegebra book this is my take on a normal vector,

a normal vector is a vector length,

the distance between the origin and some orderd pair

n=sqrt(x*x+y*y)

but in that example i get back a legth, in this we are using an x and a y,

where am i going wrong,

i would like to be able to set a point and have the light point at it,

the way im thinking now,

is to use arctan to get the angle between cx,cy and somepointx and somepointy
then use that angle in cos and sin,
but it seems im doing more work than neccisary, am i wrong?

thanks,


Raymond Jacobs,
Profesional Web Applications Developer,
Weekend Game Developer,
www.EtherealDarkness.com

Share this post


Link to post
Share on other sites
light_x,y is point of light

target_x,y is target point

dir_x = target_x - light_x
dir_y = target_y - light_y

dir_x,y is now the vector from the light point to the target point. Now normalize it:

len = sqrt( dir_x*dir_x + dir_y*dir_y )

dir_x /= len
dir_y /= len

(of course check for division by 0 before doing this)

Share this post


Link to post
Share on other sites
thanks,

ok things have worked out great,
ive implemented the light into my engine

and things are working perfectly,

here are some screen shots

they are from the game im making,
it's entirely 2D

this screen shot uses the GDI adaptor
*my graphics engine uses a common API adaption interface
to make it graphics api indipendant*


before any lighting *day scene*:
http://rubberneck.net/raymond/tid_0131.jpg

light locked to character with wide beam
http://rubberneck.net/raymond/tid_015.jpg

light locked to character with narrow beam
http://rubberneck.net/raymond/tid_016.jpg

thank you very much Yann L

Raymond Jacobs,
Profesional Web Applications Developer,
Weekend Game Developer,
www.EtherealDarkness.com

[edited by - EDI on October 23, 2002 8:53:59 AM]

Share this post


Link to post
Share on other sites