Distance formula troubles
I''m writing a 2D lighting demo kinda thing in DirectDraw.
Basically, the light has a color (RGB) and a radius. Then it takes the light color and multiplies it by (radius - distance) / radius. then it makes that pixel that color. Heres the code:
for (int index = 0; index < lplight->radius * 2; index++)
{
for (int index2 = 0; index2 < lplight->radius * 2; index2++)
{
float distancefactor = (float)(lplight->radius - (float)Calc_Distance(x,y,index,index2)) / float(lplight->radius);
pset(index,index2,_RGB16BIT565((int)((float)red_color * distancefactor), (int)((float)green_color * distancefactor), (int)((float)blue_color * distancefactor)),(unsigned short *)ddsd.lpSurface,ddsd.lPitch
}
}
pset is a function that looks like this:
void pset(int x1, int y1, long color, USHORT *VidData, int mempitch)
{
VidData[x1 + y1 * (mempitch >> 1)] = color;
}
the *VidData is a pointer to the surface returned from a DirectX call to Lock(). The mempitch is also returned from Lock().
Heres the Calc_Distance() function:
inline float Calc_Distance(int x1, int y1, int x2, int y2)
{
float answer;
answer = (double)sqrt((x1 - x2) ^ 2 + (y1 - y2) ^ 2);
return(answer);
}
All the typecasts are form me trying to figure out what is wrong.
When I run all this code, it draws a plad (sp?) pattern, not a light looking thing. I''m pretty sure its the distance function thats screwing up because when i get it to find the distance of some numbers i know, it returns something really crazy (like Calc_Distance(64,64,128,128) = 0 and Calc_Distance(74,23, 67,200) = 7...stuff like that.)
Any help?
I like the DARK layout!
I can tell you exactly why this doesn't work. In C++, the caret operator (^) doesn't mean exponent, but exclusive or , or XOR. So when you think that (x1 - x2) ^ 2 is squaring the result (lets use the Calc_Distance(64,64,128,128) example), it's really taking x1 - x2, which is -64, and XORing it to the number 2! This results in -62! Add this to another -62 and we get -124. But you get zero. The reason is because the ^ operator has an extremely low level of precedence, lower than most operators you use, including the addition operator. So what it does is all the additions first, and then the XOR. That would mean you get something like this as the true expression:
answer = sqrt(((x1 - x2) ^ (2 + (y1 - y2))) ^ 2;
If we evaluate this, we get 0. It has nothing to do with floating points or data types, just misuse of operators. The ^ is the exponent symbol in VB though, so if you program in VB you would get confused at first.
To fix this, use the pow(double x, double y) function. So this is the statement you really want:
answer = sqrt(pow(x1 - x2,2) + pow(y1-y2,2));
Edited by - Zipster on May 2, 2001 9:36:43 PM
answer = sqrt(((x1 - x2) ^ (2 + (y1 - y2))) ^ 2;
If we evaluate this, we get 0. It has nothing to do with floating points or data types, just misuse of operators. The ^ is the exponent symbol in VB though, so if you program in VB you would get confused at first.
To fix this, use the pow(double x, double y) function. So this is the statement you really want:
answer = sqrt(pow(x1 - x2,2) + pow(y1-y2,2));
Edited by - Zipster on May 2, 2001 9:36:43 PM
Don''t use the pow() function for this problem. You know you are squaring every time, the exponent is not a variable. Just precalc x2-x1 or whatever and multiply it by itself:
int dx = x2 - x1;
int dy = y2 - y1;
dist = sqrt(dx*dx + dy*dy);
There''s no point in wasting the overhead for a pow() call if you are just squaring.
int dx = x2 - x1;
int dy = y2 - y1;
dist = sqrt(dx*dx + dy*dy);
There''s no point in wasting the overhead for a pow() call if you are just squaring.
I made those changes, and it works...sort of.
Insead of that cool plad pattern, its creating a bull''s eye pattern. There are these little rings, each starting as the light''s color, then fading to black as it goes further out.
This is sort of what i want, except i want just 1 "ring", not a bull''s eye.
i''ll keep working with it, but if anyone has any idea''s why its doing THIS now, i''d appreciate hearing it.
Thanks!
Insead of that cool plad pattern, its creating a bull''s eye pattern. There are these little rings, each starting as the light''s color, then fading to black as it goes further out.
This is sort of what i want, except i want just 1 "ring", not a bull''s eye.
i''ll keep working with it, but if anyone has any idea''s why its doing THIS now, i''d appreciate hearing it.
Thanks!
I like the DARK layout!
Qoy: that''s true, but I thought it would be good to introduce the pow function to him, since what if he wants to do x^11 one day? it wouldn''t look good to do x*x*x*x*x*x*x*x*x*x*x. he didn''t know that ^ isn''t exponent so hey its good to know about pow. but yeah in this case just an x*x and y* is good.
No point in taking the sqrt to check distances ![](smile.gif)
Just square the other side (*much* faster).
And I think it''s supposed to be (r - d)/r²
Rings eh? Convert all the ints into floats, then do the math to see if it goes away.
Magmai Kai Holmlor
- The disgruntled & disillusioned
![](smile.gif)
Just square the other side (*much* faster).
And I think it''s supposed to be (r - d)/r²
Rings eh? Convert all the ints into floats, then do the math to see if it goes away.
Magmai Kai Holmlor
- The disgruntled & disillusioned
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
quote:
No point in taking the sqrt to check distances
Just square the other side (*much* faster).
Hmmm... "Um, no" is all I can think of to say. We need to find the exact value of d for the equation here, and skipping a crutial step doesn''t work. If we were doing relative comparisons on the distances, then yeah, we could just skip the squareroot altogether, but not here. Otherwise, in order to be able to skip a squareroot we need to somehow adjust the entire equation to adapt, and it''s not worth the work. Otherwise I just misunderstood what you were trying to say...
Here''s some things I found in the DX 7 SDK:
---------------------------------------------------------------
Direct3D determines the distance between a light source and a vertex being lit by taking the magnitude of the vector that exists between the light''s position and the vertex. This is represented by the following formula:
D = || VL ||
In the preceding formula, D is the distance being calculated, V is the position of the vertex being lit, and L is the light source''s position. If D is greater than the light''s range (dvRange), no further attenuation calculations are made and no light effects from the light are applied to the vertex. If the distance is within the light''s range, Direct3D then applies the following formula to calculate light attenuation over distance for point lights and spotlights (directional lights don''t attenuate):
A = 1 / (dvAttenuation0 + D*dvAttenuation1 + D*D*dvAttenuation2)
In this attenuation formula, A is the calculated total attenuation and D is the distance from the light source to the vertex. The dvAttenuation0, dvAttenuation1, and dvAttenuation2 values are the light''s constant, linear, and quadratic attenuation factors as specified by the members of a light object''s D3DLIGHT7 structure. (Not surprisingly, the corresponding structure members are dvAttenuation0, dvAttenuation1, and dvAttenuation2.) The system normalizes D to be within the range [0.0,1.0], where 0.0 indicates no light at the vertex, and 1.0 indicates full light intensity at the vertex.
The constant, linear and quadratic attenuation factors act as coefficients in the formula—you can produce a wide variety of attenuation curves by making simple adjustments to them . You could set the constant attenuation factor to 1.0 to create a light that doesn''t attenuate (but will still be limited by range), or you can experiment with different values to achieve various attenuation effects.
The attenuation formula used by Direct3D computes an attenuation value that typically ranges from 1.0 at the light source to 0.0 at the maximum range of the light. The attenuation value is multiplied into the red, green and blue components of the light''s color to scale the light''s intensity as a factor of the distance light travels to a vertex. After computing the light attenuation, Direct3D also considers spotlight effects (if applicable), the angle that the light reflects from a surface, as well as the reflectance of the current material to come up with the diffuse and specular components for that vertex. For more information, see Spotlight Falloff Model and Reflectance Model.
----------------------------------------------------------
---------------------------------------------------------------
Direct3D determines the distance between a light source and a vertex being lit by taking the magnitude of the vector that exists between the light''s position and the vertex. This is represented by the following formula:
D = || VL ||
In the preceding formula, D is the distance being calculated, V is the position of the vertex being lit, and L is the light source''s position. If D is greater than the light''s range (dvRange), no further attenuation calculations are made and no light effects from the light are applied to the vertex. If the distance is within the light''s range, Direct3D then applies the following formula to calculate light attenuation over distance for point lights and spotlights (directional lights don''t attenuate):
A = 1 / (dvAttenuation0 + D*dvAttenuation1 + D*D*dvAttenuation2)
In this attenuation formula, A is the calculated total attenuation and D is the distance from the light source to the vertex. The dvAttenuation0, dvAttenuation1, and dvAttenuation2 values are the light''s constant, linear, and quadratic attenuation factors as specified by the members of a light object''s D3DLIGHT7 structure. (Not surprisingly, the corresponding structure members are dvAttenuation0, dvAttenuation1, and dvAttenuation2.) The system normalizes D to be within the range [0.0,1.0], where 0.0 indicates no light at the vertex, and 1.0 indicates full light intensity at the vertex.
The constant, linear and quadratic attenuation factors act as coefficients in the formula—you can produce a wide variety of attenuation curves by making simple adjustments to them . You could set the constant attenuation factor to 1.0 to create a light that doesn''t attenuate (but will still be limited by range), or you can experiment with different values to achieve various attenuation effects.
The attenuation formula used by Direct3D computes an attenuation value that typically ranges from 1.0 at the light source to 0.0 at the maximum range of the light. The attenuation value is multiplied into the red, green and blue components of the light''s color to scale the light''s intensity as a factor of the distance light travels to a vertex. After computing the light attenuation, Direct3D also considers spotlight effects (if applicable), the angle that the light reflects from a surface, as well as the reflectance of the current material to come up with the diffuse and specular components for that vertex. For more information, see Spotlight Falloff Model and Reflectance Model.
----------------------------------------------------------
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement