Well while developing my free realtime raytracer i reached the point of UV mapping a sphere.
I choosed to use a 2048x1024 JPEG from NASA showing Earth... i thought that this code will do:


;-- -----------------------------
; Calculate U,V mapping
;-------------------------------
fld [hit_x]
fsub [edi.object_x]
fstp [hit_dx]

fld [hit_y]
fsub [edi.object_y]
fstp [hit_dy]

fld [hit_z]
fsub [edi.object_z]
fstp [hit_dz]

fld [hit_dx]
fld [hit_dz]
fabs
fpatan
fldpi
fdiv

fmul [texture_xscale]
fistp [hit_uv_x]

fld [hit_dy]
fld [hit_dz]
fabs
fpatan
fldpi
fdiv

fmul [texture_yscale]
fistp [hit_uv_y]

;---------------------------------
; read texture pixel
;---------------------------------
mov ebx,[lp_texture_pixels]
mov eax,[hit_uv_y]

add eax,512
.IF SIGN?
mov eax,0
.ENDIF

.IF eax>1024
mov eax,1024
.ENDIF
and eax,03ffh ;overkill protection
mov edx,eax

shl eax,(11+2) ;*2048*4
add ebx,eax

mov eax,[hit_uv_x]

add eax,1024
.IF SIGN?
mov eax,0
.ENDIF
.IF eax>2048
mov eax,2048
.ENDIF
and eax,07ffh ;overkill protection
mov ecx,eax

shl eax,2 ;*4
add ebx,eax
;------------------------------------
; here we have got the texel
;------------------------------------
mov eax,[ebx]



This "almost" works ... it looks well from front view

but i have a problem at x=-1024 and x=1024 all texture colapse down to a single run point

i basically use :
--------------------------------
texture_x=arctan(dx/dz)
texture_y=arctan(dy/dz)

I must be doing something wrong....
But what?
Posted on 2003-01-05 19:42:12 by BogdanOntanu
Without analyzing in too great detail, I see two similar instructions which may not do what you wanted and could be the source of the problem.

.IF eax>1024
mov eax,1024
.ENDIF
and eax,03ffh ;overkill protection

ANDing 1024 (i.e. 400h) with 03ffh will yield 0. So whenever the value in EAX would exceed 1024, the instructions convert it to a zero instead of your "intended" 1024 as indicated in the .IF block.

The other one is similar.

.IF eax>2048
mov eax,2048
.ENDIF
and eax,07ffh ;overkill protection

2048 (i.e. 800f) ANDed with 07ffh = 0

You may thus want to AND with 07ffh and 0fffh respectively to retain your intended max values.

Raymond
Posted on 2003-01-05 21:01:47 by Raymond
Yeah indeed thank you...

But anyway that was just the result of some form of paranoia in the early testing .... when when texture coords went beyond limits way too offten.

However this is not the problem here as it whould affect just ONE pixel/texel...

My UV mapping start to go down on Y (in texture space) as soon as x angle reaches +/- pi/2 i guess actually i think it is going down as soon as dX in sphere is greater than zero (ie right at the beginning)

I must be understanding this UV stuff somehow twisted wrong ... or the fpatan is wrong
the problem looks like inside the arctan() formulae...

Strange is that texture_X coords work OK it seems that just texture_Y is affected
Posted on 2003-01-05 21:33:00 by BogdanOntanu
Morning BogdanOntanu.

I am impressed by your work!
Here is how I went about it during the 16 bit era..

;Calculate the UV texel of a Ray defined using a vector...
;We first convert the vector into 2 angles in 2D, being XY and XZ.
;We could have chosen any 2 of the 3 possible component pairs.
;Mathematically speaking, it does not matter in this instance.
;We simply wish to have XYZ expressed as a PAIR of angles.
;Now we can view the UV map in terms of XY,XZ positions,
;by rationalizing 360,360 and Xmax,Ymax of the desired texture.

Basically I assumed the texture was mapped as angles, so any pixel in the texture could be thought of in terms of a pair of angles. I guess a more modern version would map in radians instead of angles, but what do you think anyway?

I've always been more of a hacker than a programmer I guess... don't be put off by the simplicity of my solution, it just occurs to me that you are solving this when it doesn't need to be solved in order to produce the exact same output.
Posted on 2003-01-06 13:10:50 by Homer
Hi,

Resolved it this morning just to let you all know, It was a simple error...
The right formulae is:

texture_y=arctan(dy/sqrt(dx*dx+dz*dz))
texture_x=arctan(dz/dx)

I use X axis pointing right,Y axis pointing upwards and Z axis pointing away.

Please notice the resemblence of the texture_x with my (wrong) first try ... so this explains why i thought it was working. I was drawing things on paper from the wrong "angles" and this was stopping me from seeing the truth :)

EvilHomer2k:
------------------
Are you saying that i can avoid the arctangent calculations?

Could be in cylindrical projections but i use "web standard" 2:1 (2048:1024) textures for Earth's spherical mapping...

I mean converting from carthezian X,Y,Z coordonates of the point of incidence of the ray on sphere to alpha,beta angles (well theta and phi for english school) requires arctangent() or equivalent arcsin/arccos but

FPU has arctangent (wisely) implemented ....

BTW most of the C/C++ tutorials i have read on this matter insist on using arcsin(DotProduct()) or even more complicated formulaes... althought correct... they must be much slower because FPU has ONLY arctangent() implemented

Besides this is the natural/simple solution to this problem ... hehe

PS. my "realtime" (20 fps) simple (naive asm) raytracer will be ready for you guys to download in a few days now (with sourcecode) ... and will also include the OLE JPEG loading routine (Ernie's i guess) i have promissed before
Posted on 2003-01-06 18:11:16 by BogdanOntanu
Yep, that's what I was saying, u don't "have" to use arctan to calculate texels, there is a cheaper method which produces accurate results without the heavy math (for sphere, ellipsoid and other shapes besides cylinders), but that was in the days before FPU existed, and the optimized FPU version is probably faster these days, even with the added overhead of trig functions. I was merely pointing out that the UV texel expressed as floats is applicable to any texture size, and that my algo produced them by using only sine and cosine functions, which in those days, I used a lookup table. It would have taken much longer to calculate using arctan without the aid of extended FPU instructions, and I found a cheap way to do just that.
As gamecoders, and especially as ASM gamecoders, should we not always seek the cheapest result in terms of cycles? The obvious solution is not always the only solution, and in our terms, may not always be the cheapest, and at the end of the day, what matters is the output of the function, not what form the math takes within that function. I'm a terrible FPU coder, but I'm an excellent problem-solver.
Posted on 2003-01-07 03:05:38 by Homer
Well i am indeed very interested in faster mapping and/or faster ray intersection tests.
AFAI Intend to use this tests in two directions:

1)game: i hope i will be able to optimize it until i will be able to trace a simple scene for the intro screens, i doubt i will be able to make the first raytraced game arround but i will sure try.

However i am using naive FPU code with no optimizations and i am only getting about 20 fps for 2 spheres at 256x256...not enough.

So i am interested in hacks to speed it up while retaining most of the features... otherwise i whould just use hardware accelerated scanline algorithms

2) making an accurate raytracer but make it as fast as it ca be (by using ASM)

Of course for this developement direction i will avoid any hacks that will make it innacurate

So tell me : how do you think i could avoid arctangent()? and still get well looking texture mapping of earth surface as anybody will recognize wrong image here...will they?

... besides using lookup tables...i will try that anyway
Posted on 2003-01-07 04:53:42 by BogdanOntanu
Heya.
I'll rewrite my old RayToUV function for MASM/DX tonight for u so u see what I mean.
It converts a ray defined by a vector from absolute zero (3 floats)
into a set of UV texel coordinates (2 floats)
which you can then convert into a pixel offset and look up the color.

It does so by first converting the XYZ vector into a pair of 2D component angles,
and then calculates the UV floats by assuming that the source texture pixels map a complete sphere.
It does this by rationalizing ("ratio") between <(0,0),(1,1)> and <(-pi,-pi),(+pi,+pi)>
Why not <(0,0),(2pi,2pi)> ?? Because we also must offset the centre of rotation.
That means that when UV is (0.5,0.5) (texture centre), then the rotation component angles = (0,0)
This clear as mud? :) I'm not very good at explaining myself to humans :p I do know what I mean though :grin:
Posted on 2003-01-07 07:24:29 by Homer
It looks clear to me ...
Besides i also offset relative to texture center :)

But i wonder how is your uv mapping looking on a sphere...

As you can see in my formulae Texture_y depends on Y,X,Z in a rather complex manner; so i wonder IF simple linear interpolation will do here...without visible artefacts.

Well texture mapping gives a big slowdown to my render from 35 to 21 fps but from 70fps down to 35 is because of intersection calculations (Earth sphere going bigger on screen) and diffuse+specular shading+shadows
Posted on 2003-01-07 15:54:27 by BogdanOntanu
Heya..
sorry I haven't had much time to translate my old 68k code to masm yet.
I did rework the algorithm however.
Here is the formulae... note my choice of planes is arbitrary.
.
.
.


Phase 1: calculating the XY and XZ component angles...
I will outline three possible methods...
Methods B and C require calculation of the planar Hypotenuses....
Hxy=SQRT(x^2+y^2)
Hxz=SQRT(x^2+z^2)

Method A) Inverse Tangent
@XY = 'tan y/x
@XZ = 'tan z/x

Method B) Inverse Sine
@XY = 'sin y/Hxy
@XZ = 'sin z/Hxz

Method C) Inverse Cosine
@XY = 'cos x/Hxy
@XZ = 'cos x/Hxz

;--------------------------------------------
Phase 2: calculating the UV floats from the planar anglular components
U=@XY/2pi
V=@XZ/2pi

;----------------------------------------------
Phase 3: offset the mapping to the texture centre
U=U+0.5
V=V+0.5 (or simply divide by pi instead of 2pi at phase2)

;------------------------------------------------
Phase 4: calculating the pixel XY from the UV floats
X=U*Xmax
Y=V*Ymax
where Xmax and Ymax are the dimensions of the source texture.

;--------------------------------------------------


Have a nice day :)
Posted on 2003-01-08 03:10:57 by Homer
Well thank you

but your methods look like more complicated than my own :)

ie for methods B and C you calculate 2 SQRTs while i only take one
and you also take "inverse sine function" (i guess that is arcsinus()? ) ... however FPU can not do such a function (without breaking it into other aka arctangent() functions).

Method A looks pretty much like my first try ;)

But i have noticed that with a bigger Field of View or skewing the camera left/right one can clearely see that it is not ok, only a small area of the sphere is mapped... looks aparently ok seen from the front of the sphere in a narrow angle.
Posted on 2003-01-08 14:34:30 by BogdanOntanu
Heya.
Let's transpose the function to reduce the math...
We'll also use the /pi method to eliminate the +.50 offsetting step...
For future reference, inverse functions are simply 1/Fn ...
Let's look at a case:
U=('tan y/x)/pi

We can see 'tan y/x as 1/(tan y/x)
Note that rather than calculating tan y/x and then inverting it, we can perform the inversion at the start...

therefore U=(x/tan y) /pi

Anytime we have 1/A/B we can invert to produce B/A.
So my formula for Method A becomes:
U=(x/tan y) / pi
V=(x/tan z) / pi

That looks much nicer, doesn't it? :)
Posted on 2003-01-08 22:31:12 by Homer
Yes much more nicer ;)

i did not know that 'tan(x) == 1/tan(x)

I will check out how it looks
Posted on 2003-01-09 04:30:52 by BogdanOntanu
Heya.
Just spent a week with the dolphins at the fabulous Monkey Mia resort in Australia.
Was wondering if you'd tried out that lil trig hack, and if so, how did it compare speedwise?
Posted on 2003-01-16 07:02:49 by Homer
Sorry i have not reached that testing phase...since i have fixed my own i used that...
But i will ... :P

Anyway the source code will be available for you to test your own optimizations soon
I just have to arrange it a little (it is a mess)
Posted on 2003-01-17 10:14:39 by BogdanOntanu