Is this code correct ?

J

johnnash

In my project I need to shoot rays from the source.I know you cannot
follow all the rays from the source as you can actually shoot rays at
infinite angles,therefore my plan is to launch rays from the
trasmitter in all directions spaced eg. x degrees or something. This
is the logic I have used for a C program -

consider the source to be centre of the unit sphere.

0<=theta<=180(zenith)
0<=phi<=360 (azimuth)

Then run a for loop like this -

for( theta = 0 ; theta <=180; theta = theta + 5 ) /* taking some 5
degree difference or there will be infinite rays */
for( phi = 0; phi <=360; phi = phi + 5 )
{
/*Calculate the cartesian coordinates of a point p(a struct) on
sphere*/
P.x = r*sin(theta)*cos(phi);

P.y = r * sin(theta) *sin(phi);

P.z = r * cos(theta);

direction[index] = VectorSubtract(P, Center_of_Sphere);

VectorNormalize(direction[index]);

/*direction is just a list that will store ray directions */
 
E

Eric Sosman

johnnash said:
In my project I need to shoot rays from the source.I know you cannot
follow all the rays from the source as you can actually shoot rays at
infinite angles,therefore my plan is to launch rays from the
trasmitter in all directions spaced eg. x degrees or something. This
is the logic I have used for a C program -

consider the source to be centre of the unit sphere.

0<=theta<=180(zenith)
0<=phi<=360 (azimuth)

Then run a for loop like this -

for( theta = 0 ; theta <=180; theta = theta + 5 ) /* taking some 5
degree difference or there will be infinite rays */
for( phi = 0; phi <=360; phi = phi + 5 )
{
/*Calculate the cartesian coordinates of a point p(a struct) on
sphere*/
P.x = r*sin(theta)*cos(phi);

P.y = r * sin(theta) *sin(phi);

P.z = r * cos(theta);

direction[index] = VectorSubtract(P, Center_of_Sphere);

VectorNormalize(direction[index]);

/*direction is just a list that will store ray directions */

What's your question?

Your outline looks all right, but there are a few
points worth mentioning:

1) C's trigonometric functions work in radians, not
in degrees, so the code as written will not give the
results you presumably expect. Multiply each argument
by pi/180 before passing it to sin() or cos().

2) Your phi steps from 0 degrees up to and including
360 degrees. Since 0 and 360 are the same angle, each
zenith has one ray that's shot twice.

3) It is not good to worry too much about efficiency,
but some features of your code are so inefficient that
I can't resist pointing them out. In the inner loop you
evaluate sin(theta) twice and cos(theta) once -- but
theta remains unchanged while phi steps all around the
circle, so you get the same pair of answers over and over
again. Instead, consider calculating the functions of
theta once before entering the phi loop:

for (theta = 0; theta <= 180; theta += 5) {
double sint = sin(pi / 180 * theta);
double cost = cos(pi / 180 * theta);
for (phi = 0; phi < 360; phi += 5) {
P.x = r * sint * cos(pi / 180 * phi);
P.y = r * sint * sin(pi / 180 * phi);
P.z = r * cost;
...

3b) To avoid even more function evaluations, consider
interchanging the theta and phi loops and pre-calculating
sin(pi / 180 * phi) and cos(pi / 180 * phi) instead. (In
the inner theta loop, you would of course call sin() only
once.)

4) Since you say you're using a unit sphere, I imagine
that r == 1 -- in which case, why bother multiplying by it?
 
J

johnnash

johnnash said:
In my project I need to shoot rays from the source.I know you cannot
follow all the rays from the source as you can actually shoot rays at
infinite angles,therefore my plan is to launch rays from the
trasmitter in all directions spaced eg. x degrees or something. This
is the logic I have used for a C program -
consider the source to be centre of the unit sphere.
0<=theta<=180(zenith)
0<=phi<=360 (azimuth)
Then run a for loop like this -
for( theta = 0 ; theta <=180; theta = theta + 5 ) /* taking some 5
degree difference or there will be infinite rays */
for( phi = 0; phi <=360; phi = phi + 5 )
{
/*Calculate the cartesian coordinates of a point p(a struct) on
sphere*/
P.x = r*sin(theta)*cos(phi);
P.y = r * sin(theta) *sin(phi);
P.z = r * cos(theta);
direction[index] = VectorSubtract(P, Center_of_Sphere);
VectorNormalize(direction[index]);

/*direction is just a list that will store ray directions */

What's your question?

Your outline looks all right, but there are a few
points worth mentioning:

1) C's trigonometric functions work in radians, not
in degrees, so the code as written will not give the
results you presumably expect. Multiply each argument
by pi/180 before passing it to sin() or cos().

2) Your phi steps from 0 degrees up to and including
360 degrees. Since 0 and 360 are the same angle, each
zenith has one ray that's shot twice.

3) It is not good to worry too much about efficiency,
but some features of your code are so inefficient that
I can't resist pointing them out. In the inner loop you
evaluate sin(theta) twice and cos(theta) once -- but
theta remains unchanged while phi steps all around the
circle, so you get the same pair of answers over and over
again. Instead, consider calculating the functions of
theta once before entering the phi loop:

for (theta = 0; theta <= 180; theta += 5) {
double sint = sin(pi / 180 * theta);
double cost = cos(pi / 180 * theta);
for (phi = 0; phi < 360; phi += 5) {
P.x = r * sint * cos(pi / 180 * phi);
P.y = r * sint * sin(pi / 180 * phi);
P.z = r * cost;
...

3b) To avoid even more function evaluations, consider
interchanging the theta and phi loops and pre-calculating
sin(pi / 180 * phi) and cos(pi / 180 * phi) instead. (In
the inner theta loop, you would of course call sin() only
once.)

4) Since you say you're using a unit sphere, I imagine
that r == 1 -- in which case, why bother multiplying by it?

Thank you very much. However I did not understand the 2nd point.
 
M

Micah Cowan

Thank you very much. However I did not understand the 2nd point.

There are 360 degrees to a circle. 0 through 360 is 361. Shooting at phi
== 0 and again at phi == 360 is exactly the same as shooting at phi == 0
twice.

You want that for statement to begin like:
for (phi = 0; phi < 360; phi += 5)
^^^
rather than with <=.
 
C

Coos Haak

Op Thu, 28 Feb 2008 10:31:20 -0800 (PST) schreef johnnash:
In my project I need to shoot rays from the source.I know you cannot
follow all the rays from the source as you can actually shoot rays at
infinite angles,therefore my plan is to launch rays from the
trasmitter in all directions spaced eg. x degrees or something. This
is the logic I have used for a C program -

consider the source to be centre of the unit sphere.

0<=theta<=180(zenith)
0<=theta<=90 is enough.
 
T

Thad Smith

johnnash said:
In my project I need to shoot rays from the source.I know you cannot
follow all the rays from the source as you can actually shoot rays at
infinite angles,therefore my plan is to launch rays from the
trasmitter in all directions spaced eg. x degrees or something. This
is the logic I have used for a C program -

consider the source to be centre of the unit sphere.

0<=theta<=180(zenith)
0<=phi<=360 (azimuth)

Then run a for loop like this -

for( theta = 0 ; theta <=180; theta = theta + 5 ) /* taking some 5
degree difference or there will be infinite rays */
for( phi = 0; phi <=360; phi = phi + 5 )
{
/*Calculate the cartesian coordinates of a point p(a struct) on
sphere*/

Be aware that the distribution you get with this approach will not be
uniform. You will have a hot spot at 90 degrees zenith darkening as your
angle approaches 0 and 180 degrees.

I am not a graphics programmer, but I think to get a uniform distribution,
you should aim each vector at an equal-size portion of a sphere at a given
distance. You could do this, for each zenith angle, by going around a
circle on a unit sphere at equal spacing.
 
K

Keith Thompson

johnnash said:
In my project I need to shoot rays from the source.I know you cannot
follow all the rays from the source as you can actually shoot rays at
infinite angles,therefore my plan is to launch rays from the
trasmitter in all directions spaced eg. x degrees or something. This
is the logic I have used for a C program -

consider the source to be centre of the unit sphere.

0<=theta<=180(zenith)
0<=phi<=360 (azimuth)

Then run a for loop like this -

for( theta = 0 ; theta <=180; theta = theta + 5 ) /* taking some 5
degree difference or there will be infinite rays */
for( phi = 0; phi <=360; phi = phi + 5 )
{
[snip]

Your rays are spaced much more tightly near the poles than near the
equator. If your sphere were the surface of the Earth, then on the
equator you'd have one ray about every 550 kilometers. On the circle
5 degrees from either pole, your rays are less than 50 kilometers
apart. And at the pole itself, you have 72 rays at the same spot.

Computing N points on a sphere that are perfectly equally placed is
tricky, and likely impossible for most values of N. But you can vary
the number of points on each parallel of latitude should give you
decent results.
 
E

Ernie Wright

Thad said:
johnnash said:
In my project I need to shoot rays from the source. [...]

consider the source to be centre of the unit sphere.

0<=theta<=180(zenith)
0<=phi<=360 (azimuth)

Then run a for loop like this -

for( theta = 0 ; theta <=180; theta = theta + 5 ) /* taking some 5
degree difference or there will be infinite rays */
for( phi = 0; phi <=360; phi = phi + 5 )

Be aware that the distribution you get with this approach will not be
uniform. You will have a hot spot at 90 degrees zenith darkening as
your angle approaches 0 and 180 degrees.

I am not a graphics programmer, but I think to get a uniform
distribution, you should aim each vector at an equal-size portion of a
sphere at a given distance. You could do this, for each zenith angle,
by going around a circle on a unit sphere at equal spacing.

There are a number of ways to approach this. One would be to scale the
steps in phi by the sine of theta,

for ( phi = 0; phi < 360; phi += 5.0 / sin( theta )) ...

The poles, where theta = 0 or 180, are treated as a special case, since
there's no need to test different increments of phi.

A better way would be to use the vertex coordinates of a spherical
tessellation. The icosahedron is a roughly spherical shape made of 12
equally spaced vertices and 20 equilateral triangles. You can use the
3D cartesian coordinates of the vertices directly as a uniform sample of
the unit sphere. For a higher sampling rate, subdivide each triangle.

The OP desperately needs to acquaint himself with the fundamentals of
3D graphics. Basic raytracing in particular is well understood, well
documented, and thoroughly covered in any good first-semester college
course on 3D. The textbooks used in those courses would be a *much*
better source of information than c.l.c.

- Ernie http://home.comcast.net/~erniew
 
J

johnnash

Be aware that the distribution you get with this approach will not be
uniform. You will have a hot spot at 90 degrees zenith darkening as your
angle approaches 0 and 180 degrees.

I am not a graphics programmer, but I think to get a uniform distribution,
you should aim each vector at an equal-size portion of a sphere at a given
distance. You could do this, for each zenith angle, by going around a
circle on a unit sphere at equal spacing.

I thought what would actually happen over here is that I would get a
thicker density of rays near the poles as opposed to when zenith
becomes 90
 
J

johnnash

There are a number of ways to approach this. One would be to scale the
steps in phi by the sine of theta,

for ( phi = 0; phi < 360; phi += 5.0 / sin( theta )) ...

The poles, where theta = 0 or 180, are treated as a special case, since
there's no need to test different increments of phi.

why increment phi in steps of sin(theta) ?? if we do this, then when
zenith is 90, the rays will far apart whereas near the poles, they
would be bundled closely and there will be a very thick density.
 
E

Ernie Wright

johnnash said:
why increment phi in steps of sin(theta) ?? if we do this, then when
zenith is 90, the rays will far apart whereas near the poles, they
would be bundled closely and there will be a very thick density.

It depends on how you define your angles. If sine doesn't work, you can
use cosine (which is actually more common).

- Ernie http://home.comcast.net/~erniew
 
J

johnnash

It depends on how you define your angles. If sine doesn't work, you can
use cosine (which is actually more common).

- Ernie http://home.comcast.net/~erniew

ok i think i understood. may be what you are trying to say is that the
rays tend to bundled along the poles(i.e. theta = 0 and 180) so what
we do is we increment phi by greater values near pole. because when
theta is closer to zero or 180, the sine value will be very low
resulting in a very high value of 5 / sin(theta) ?? but at theta = 90
which represents the equatior, increment is only 5 degree..
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top