# Generating eye rays

This topic is 5086 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hello, I'm trying to code a ray tracer but I got stuck on generating eye rays (sorry if I'm just too n00b). I rewrote it 3 times but it's always missing some rays at the end. If the rays must be perfectly simmetrical, the first ray is supposed to have 0.5 as X component and the last ray must have -0.5 as X component. But the last ray has -0.44. I can't really "see" the solution so I'd like to ask for some help. I'd like to know what kind of fast method is there for generating the eye rays. (I chose rotation method because the sine and cosine can be precomputed with a single instruction and what's left is about 4 multiplications, 1 addition and 1 subtraction (without counting floating-point stack register movement instructions). If it helps, I'll post my asm code on request, but it's 123 lines long). Thank you, JVFF

##### Share on other sites

int delta = fov/rays;
int angle;
for(angle = startangle; angle<=endangle; angle+=delta) {
// stuff
}

It's often better to do something like

int delta = fov/rays;
int angle;
for(i=0; i<rays; angle=(delta*i++)+startangle) {
// stuff
}

##### Share on other sites
The above post is a guess, but if you're iterating to get your rays, you could be suffering from precision errors. /Or/ your calculation of delta is wrong. (The one in my post probably is).

##### Share on other sites
In my code: For each pixel on a line rotate a predefined angle (fov / width). Then when that line is finished a rotate the same angle down and loop again. Is this pure stupidity? I've heard people generating rays by addition, is there such method? My solution was so I could get rid of normailzation (too much clocks wasted) and more precision. If I'm wrong, what is the most efficient method?

JVFF

##### Share on other sites
Basically my point was that you may have accuracy problems, if you just add to or subtract an angle for each ray. Instead, generate the ray by multiplying your change value by the number of the ray and add any starting angle.

(Accuracy problems like these are very visible with fixed point rasterisers.)

Generating rays by simple addition would probably be a case of linear interpolation of each of the three component vectors, for both across and down the set of rays. It's not very accurate, and the rays do not remain normalised, but it's fast and should work.

##### Share on other sites
Thanks again for your reply. Although it might be precision error, I still don't know why the last rays are "missing". I think I might be mistaken by my precomputation. Here's the method I coded:

Start with an initial ray pointing from the middle of the screen forward. I then rotate this ray half fov to the left. I calculate the amount to rotate vertically by multiplying fov by height and dividing it by width (fov/width = vfov/height). Then I rotate it by that angle. Then I divide the fov by the width to get a single ray angle, calculate sine and cosine then iterate rotating the ray to generate a new ray, rotate the new ray to generate another ray, etc.

Here's the code (although it only generates rays for the 1st line):

generate_eye_rays:									; Generate eye rays function	; Transform field of view into radians	mov			ebx,			TempRay				; Load address of temporary ray into ebx		mov			[TempRay],		dword		FOV			; Load field of view into X of temporary ray	mov			[TempRay+4],	dword		ANGLE_180		; Load 180 into Y of temporary ray		fld			dword			[ebx]					; Push field of view into fpu	fldpi											; Push PI into fpu	fmulp			st1,			st0					; Multiply field of view by pi and pop		fld			dword			[ebx+4]				; Push 180 into fpu	fdivp			st1,			st0					; Divide field of view * pi by 180 and pop		; Calculate sine and cosine of half horizontal frustrum angle	mov			ecx,			BiVector				; Load address of bi-unit vector into ecx		fld			dword			[ecx]					; Push 2.0 into fpu	fdivp			st1,			st0					; Divide field of view by 2 and pop		fst			st1								; Save half field of view to calculate half vertical frustrum angle		fsincos										; Calculate sine and cosine		; Generate initial ray rotated around Y axis (counter clockwise)	fldz											; Create initial ray Y	fxch			st1								; Swap new Y and new Z		; Calculate sine and cosine of half vertical frustrum angle	mov			[TempRay+4],	dword		WIDTH			; Load width into Y of temporary ray	mov			[TempRay+8],	dword		HEIGHT		; Load height into Z of temporary ray		fild			dword			[ebx+8]				; Push height into fpu	fmul			st0,			st4					; Multiply height by half field of view		fild			dword			[ebx+4]				; Push width into fpu	fdivp			st1,			st0					; Divide height * half field of view by width		fsincos										; Calculate sine and cosine		; Rotate initial ray about X axis	fxch			st1								; Swap cosine * Z and sine	fmul			st0,			st2					; Multiply sine by Z	fchs											; Invert	fstp			st3								; Save new Y and pop		fmulp			st1,			st0					; Multiply Z by cosine and pop		; Save initial ray	fst			dword			[ebx+8]				; Save Z value of initial ray	fincstp										; Rotate upwards	fst			dword			[ebx+4]				; Save Y value of initial ray	fincstp										; Rotate upwards	fst			dword			[ebx]					; Save X value of initial ray	fdecstp										; Rotate downwards	fdecstp										; Rotate downwards		; Calculate sine and cosine of ray angle	mov			[TempRay+12],	dword		HALF_W		; Load half width into W of temporary ray	fild			dword			[ebx+12]				; Push half width into fpu		fdivr			st0,			st4					; Divide half field of view by half width	ffree			st4								; Free half field of view		fchs											; Invert angle	fsincos										; Calculate sine and cosine		; Ray generation loop	mov			edx,			HEIGHT				; Loop for every line	mov			eax,			EyeRayBuffer			; Load address of eye ray buffer into eax		generate_line_of_rays:								; Generate a line of rays		mov		ecx,			WIDTH					; Loop for every pixel on a line				generate_ray:								; Generate a single ray			fincstp								; Rotate upwards			fincstp								; Rotate upwards						fst	dword			[eax+8]				; Save Z value			fincstp								; Rotate upwards			fst	dword			[eax+4]				; Save Y value			fincstp								; Rotate upwards			fst	dword			[eax]					; Save X value						fst	st1								; Create copy of X value			fmul	st0,			st4					; Multiply X by cosine						fdecstp								; Rotate downwards			fdecstp								; Rotate downwards						fst	st4								; Create copy of Z value			fmul	st0,			st7					; Multiply Z by sine			fadd	st2,			st0					; Add X*cosine and Z*sine to form new X									fdecstp								; Rotate downwards			fmul	st4,			st0					; Multiply copy of X by sine						fdecstp								; Rotate downwards			fmul	st6,			st0					; Multiply copy of Z by cosine						fxch	st5								; Swap X*sine and cosine			fsubr	st0,			st6					; Subtract X*sine from Z*cosine to form new Z			fstp	st2								; Store new Z and pop						fld	st4								; Push cosine into fpu			ffree	st5								; Free used register			ffree	st6								; Free used register						add	eax,			12					; Get next ray's address			sub	ecx,			1					; Decrement ecx			jnz	generate_ray						; Execute loop				fincstp									; Rotate upwards		fincstp									; Rotate upwards				ffree		st0								; Free Z		ffree		st1								; Free Y		ffree		st2								; Free X		ret											; Return

Thank you again,

JVFF

##### Share on other sites
I can't read x86 assembly very well (never learnt it). This code seems quite straight forward though. (Although I can read ARM, 68k, PIC micro etc.,)

Three points:

Are you generating the correct number of rays? (You seem to be counting them so probably not a problem)

Is your value for delta correct? (angle between rays)

Are you suffering from precision errors?

If (delta*number_of_rays) gives a noticably different (within 3 dp)
to int val; for(int i=0; i<number_of_rays; i++) val+=delta; then you probably have issues.

Basically, there's a slight accuracy error when you do a floating point operation. The more you do on the same thing the more accuracy it looses. If you return to the original vector each time accuracy is greater.

int main() {    int i = 0;    float val = 0;    float delta = 320.0f/60.0f;    for(i = 0; i < 320; i++)        val+=delta;    printf("Interpolate: %f\n", val);    printf("Direct: %f\n", delta*320.0f);}

Basically, your program is using the interpolate method. I've been suggesting trying the direct method (which is also rather useful for adaptive multisampling)

My results:
Interpolate: 1706.670288
Direct: 1706.666718

If delta is 60/320 then both give the correct answer, as 60/320 has a perfect floating point representation.

##### Share on other sites
i did mine my using the vertex shader.

//u can precompute the texcoords for the quad
half dx = pixelLocation.x / g_Display.viewport.z - 1.0;
half dy = pixelLocation.y / g_Display.viewport.w - 1.0;
half4 ray_start_view = half4(dx, dy, 1.0, 1.0);
half3 ray_start_world = mul(ray_start_view, g_WorldViewProjectionInverse).xyz;

cheers!
Edwinz

1. 1
2. 2
3. 3
4. 4
frob
15
5. 5

• 12
• 12
• 20
• 12
• 13
• ### Forum Statistics

• Total Topics
632149
• Total Posts
3004453

×