THURP

darkblu

Veteran
i'm bringing to your attention a spare-time project of mine. it could be of interest to two groups of readers of this forum:

  • if you ever wondered what a general IMR rasterizer looked from the inside, or
  • if you're of those guys who actually know the entrails of such a beast and would share your constructive comments and criticism. The idea is to keep the project in a good shape, suitable for both useful spawns, and good educational value.
But in both cases good knowledge of C is required :)

so in case you're curious, follow the link in my sig to get to the thing under consideration.
 
mboeller said:
I hope You don't mind, but I have seen another software-renderer at flipcode :
http://www.flipcode.com/cgi-bin/msg.cgi?showThread=11-12-2002&forum=iotd&id=-1

This renderer is able to render QuakeIII maps. Nice

i don't mind ;) actually i'm familiar with it, and it's the most sophisticated, performance-oriented sw rasterizer i've seen to date (it's truly impressive with its support for shader assembly code - even Mesa is not that good). THURP, being in its infancy, is not yet in that 'heavy' category, but believe me - it'll be able to render Q3 maps pretty soon, at dx7 hardware quality level (still wondering about aniso). point is, i've been very cautious to keep THURP as clean and comprehensive as i've been able to, so it could have a higher reference value, both as produced output, and as pipeline design & layout. what will eventually come out of this project is still early to forsee, but i, for one, believe in diversity of efforts (i.e. one cool sw raterizer is good, many is still better).

btw, before i make a q3 map reader i'll more likely have DOT3 and cube mapping into THURP 8)
 
Heh, THURP sounds a lot like a rasterizer that I've sort of been developing. The features are pretty similar. My rasterizer (and the test program for it) can 'just' render Quake 3 MD3 files. Since the program can't read the q3 shaders (yet...) the shaders need to be written in C/C++ code, so obviously it's hardly versatile. But none the less it still supports all the required blending functions.

One limitation with the rasterizer, is it's being designed purely for an Ortho matrix and (obviously) affine texture mapping. Perspetive Projection and Perspective Correct texturing are not a requirement for the engine that the rasterizer is being made for. That obviously speeds things up a bit. Additionally I'm writing it in as much fixed point code as possible with almost no subpixel precision so there are some accuracy problems in places. With what it's being designed for, that doesn't matter much.

I have no idea at all what my current fillrate is, and at this stage I'm not too interested either. Regardless, bilinear texture filtering hurts the fillrate quite a bit. :)

-Colourless
 
yay to software rasterizers! :)

Colourless said:
One limitation with the rasterizer, is it's being designed purely for an Ortho matrix and (obviously) affine texture mapping. Perspetive Projection and Perspective Correct texturing are not a requirement for the engine that the rasterizer is being made for. That obviously speeds things up a bit. Additionally I'm writing it in as much fixed point code as possible with almost no subpixel precision so there are some accuracy problems in places. With what it's being designed for, that doesn't matter much.

*nods*
avoiding divisions (i.e. being affine) usually makes the pipeline integer-friendy from a performance POV as integer divisions are Ops From Hell(tm). i recall cyrix coming up with a 3-clocks integer multiplication for their 686 series, but i'm yet to see an optimized implementation of integer division on a consumer CPU.

THURP, OTH, is completely FP, so divisions there are not so penalizing (not that they're not still among the heaviest ops), given the complier does its job right.

I have no idea at all what my current fillrate is, and at this stage I'm not too interested either. Regardless, bilinear texture filtering hurts the fillrate quite a bit. :)

heh, it surely does - in my test (under BeOS) it yields about double performance hit compared to nearest (point) sampling. but one day, just for the fun of it, i'll come up with a SIMD span scan-conversion routine for the bilinear case, and i wouldn't be too much surprised if it turned out being on par with the unoptimised point sampling performance-wise ;)

anyhow, talking about heavy tex. sampling modes, yesterday i scrapped yet another implementation of mipmapping for THURP, and i don't want to use OGL's version as i don't particularly like it. so still pondering on the best (mathematically) mipmapping.
 
THURP, OTH, is completely FP, so divisions there are not so penalizing (not that they're not still among the heaviest ops), given the complier does its job right.

Yeah, I noticed you were doing everything in FP. Using FP really simplifies things a lot. For me, however, that isn't really an option since I 'may' want to port the rasterizer to various PDAs and they don't have FPUs.

and i wouldn't be too much surprised if it turned out being on par with the unoptimised point sampling performance-wise

Reminds me of the time I wrote a point sampling upscaler that managed to be slower than a bilinear upscaler. A badly designed point sampler can be far slower than anticipated.

anyhow, talking about heavy tex. sampling modes, yesterday i scrapped yet another implementation of mipmapping for THURP, and i don't want to use OGL's version as i don't particularly like it. so still pondering on the best (mathematically) mipmapping.

Mipmapping is something that I don't know if I'll bother with. It would be neat to support it, but I just don't know if it's worth the trouble. The miplevel calcs are going to marginally slow things down so, for now, I'm not looking much into it.

Anyway, in case you were interested, here are 2 screenshots of some models from Quake 3.

First one is a rendering of the Quake 3 Hunter model with the Harpy skin holding a Railgun. It's got 2 texture layers (environment map and blended decal). It's rendered with Point Sampling.
http://www.users.on.net/triforce/hunter.png

The second one is of Slash with a skin (and shader) that I 'made', firing the Rocket Launcher. There are 3 texture layers (environment map, filter for envmap, and blended decal). I used Bilinear filtering for this shot.
http://www.users.on.net/triforce/slash.png

-Colourless
 
Colourless said:
Yeah, I noticed you were doing everything in FP. Using FP really simplifies things a lot. For me, however, that isn't really an option since I 'may' want to port the rasterizer to various PDAs and they don't have FPUs.

unfortunately they don't. apropos, performance considerations aside, fixed-point has the advantage of range uniformity over floating point, which could be usefuly even when it comes to reference rasterization - i, personally, would rather have 16.16 fixed point than 8e23 float in the pixel pipeline, but that's just me.

and i wouldn't be too much surprised if it turned out being on par with the unoptimised point sampling performance-wise

Reminds me of the time I wrote a point sampling upscaler that managed to be slower than a bilinear upscaler. A badly designed point sampler can be far slower than anticipated.

yes, of course, everything's relative :)

anyhow, talking about heavy tex. sampling modes, yesterday i scrapped yet another implementation of mipmapping for THURP, and i don't want to use OGL's version as i don't particularly like it. so still pondering on the best (mathematically) mipmapping.

Mipmapping is something that I don't know if I'll bother with. It would be neat to support it, but I just don't know if it's worth the trouble. The miplevel calcs are going to marginally slow things down so, for now, I'm not looking much into it.

well, there are some distance-to-cam fx techniques that rely on mipmapping. and when it comes to reference rasterization you just can't ommit mipmapping, no matter that performance-wise it could be a hog. but hey, nobody said CPU have reached their speed limits! ;) so there may always be some room left for little mipmapping, even on PDAs, just maybe not today :-?

Anyway, in case you were interested, here are 2 screenshots of some models from Quake 3.

First one is a rendering of the Quake 3 Hunter model with the Harpy skin holding a Railgun. It's got 2 texture layers (environment map and blended decal). It's rendered with Point Sampling.
http://www.users.on.net/triforce/hunter.png

nice screenshot. honeslty, the environment map and skin look perfectly adequate with point sampling. and since the model polies are small affine looks good either. i guess one could stick to using this setup when drawing similar env-mapped characters.

The second one is of Slash with a skin (and shader) that I 'made', firing the Rocket Launcher. There are 3 texture layers (environment map, filter for envmap, and blended decal). I used Bilinear filtering for this shot.
http://www.users.on.net/triforce/slash.png

beautiful. nicely-conveyed minor details. and the blending is flowless. affine does fine again. thank you for posting those screenshots, colourless!

apropos, i'm wondering whether you'd be willing to share your q3 maps/chars reader? i'd post some shots of THURP, too, but at this time it's all cubes and spheres - boring, nothing comparable to Slash and Hunter from Q3 ;)
 
THURP can do mipmapping now. currently only nearest LOD is taken into account, trilinear is yet to come. after some pondering i decided to stick with the OGL canon - implementation follows (more or less) the OGL minification rules for mipmapping.

there's something that bothers me in the mipmap selection code, LOD snapping/rounding , and i'd be grateful to anybody who can give an opinion on the matter to take a look and say if math is correctly layed out.
 
The only 'issue' with that MD3 info is they don't have the code to work out the normals. It's really quite simple.

The Vertices have this format:
short x;
short y;
short z;
char longitude;
char latitude;

To get the normal from the long and lat you do this:
Code:
	// Get the normal
	inline void GetNormal(float normal[3]) {
		float flat = latitude * M_PI/128;
		float flong = longitude * M_PI/128;
		normal[0] = cos(flat) * sin(flong);
		normal[1] = sin(flat) * sin(flong);
		normal[2] = cos(flong);
	}
 
Back
Top