Forum archive
World vs. Sprite rendering
- Hello all!
Does Voxlap use a different method for rendering sprites than it does for rendering the world?
I may be wrong, but it looks as if Sprites were rendered using a splatting approach (If you get very close to the Sprites or even inside them, you can see the rectangles, that seem to be scaled very cleverly to reduce overdraw).
If so, why? I think that the sprites are much more versatile than the fixed size not deformable worldarray. Are they slower to render? Or are they even faster?
A game might want to use low resolution models for objects that the player gets never close to (or prodecurally generate detail if needed) ,like mountains, and use the resources for more important objects.
Also, in my opinion the board map is too small or too blocky (if you reduce the size of your models). I would rather use sprites for everything. Is this possible? Does Voxlap use a different method for rendering sprites than it does for rendering the world?
Yes. I use raycasting for the world and splatting for the sprites.If so, why?
If you're asking whether I've tried raycasting methods for sprites, the answer is I have not. My 6dof raycasting algorithm is awfully complex and I didn't feel like modifying it to work with sprites.sprites ... Are they slower to render? Or are they even faster?
The advantage of raycasting is hidden surface removal. This is a good choice for large worlds that are likely to have things occluded by mountains and walls. This is not true for my sprite algorithm. Sprites are small in nature, so when you see a sprite, usually all of it is in view. My sprite algorithm draws all surface voxels whether they're visible or not - I use the Z-buffer for hidden surface removal.A game might want to use low resolution models for objects that the player gets never close to (or prodecurally generate detail if needed) ,like mountains, and use the resources for more important objects.
Voxlap supports mip-mapping for both world and sprites. This means far objects are rendered at lower resolution.I would rather use sprites for everything. Is this possible?
That would be a fine idea if you were making a 3D asteroids type game and had no background other than a sky perhaps. If you intend to build a Voxlap-style landscape out of sprites, your frame rate will drop to hell. Also, you'll lose the benefits of hidden surface removal and my functions for managing dynamic terrain.If you're asking whether I've tried raycasting methods for sprites, the answer is I have not. My 6dof raycasting algorithm is awfully complex and I didn't feel like modifying it to work with sprites. [...] The advantage of raycasting is hidden surface removal. This is a good choice for large worlds that are likely to have things occluded by mountains and walls. This is not true for my sprite algorithm. Sprites are small in nature, so when you see a sprite, usually all of it is in view. [...] I use the Z-buffer for hidden surface removal.
So it would actually be faster to use raycasting for everything? Is it really that hard to make it work for sprites? Would you have to include more than a z-check (I assume you don't do z-checks for world rendering, because raycasting does this already), arbitrary (or say power-of-two) size, and camera-out-of-dataset rendering (ok, that's lots of different cases, but not too hard)?
BTW, Voxlap treats the up-down-direction (z) differently than the horizontal direction (x,y)? (I think that it does runlength-encoding in z?) Could that be a problem for sprites that have weird shapes (make the raycasting slow)?Voxlap supports mip-mapping for both world and sprites. This means far objects are rendered at lower resolution.
What I meant was that one might want to save the storage space and not only render at a lower resolution but also save parts of the world (e.g. mountains) at lower resolution.
Also it would be cool if you could do "Tiling" of the world like in outcast (mentioned in another thread), or even have not-axis-aligned tiles.
I'm asking all this because I wonder what the optimal method for displaying 3D-objects in a game is. I don't think that polygons are very good, because if you raise the polygon count to a level where you can't see the edges anymore, texture mapping becomes pointless (you would only see 2 or 3 texels on one triangle), and furthermore the data is plainly unmanageable (ever tried to write a automatic LOD algorithm for triangles?). But I'm not sure if voxels are a better method, because they don't deal with surfaces but rather with volumes, need lots of storage, and so on.
At the moment I think that 6DOF Heightmaps that are used like displacement-mapped polygons would give the best out of both worlds (any comments on that encouraged :wink: )
I'm currently working on that heightmap renderer, but I'm not yet sure what algorithm is the fastest, and maybe voxels are better after all.So it would actually be faster to use raycasting for everything?
It depends on the size and shape of your sprites. If they're really huge then maybe. For things in my demo (64^3 to 128^3 range), I think my current algorithm which draws everything is just fine.Is it really that hard to make it work for sprites?
Yes. A brute-force approach is doable if you like measuring speed in seconds per frame.Voxlap treats the up-down-direction (z) differently than the horizontal direction (x,y)? (I think that it does runlength-encoding in z?) Could that be a problem for sprites that have weird shapes (make the raycasting slow)?
Correct. It's always best to make the longest dimension the height (z direction).At the moment I think that 6DOF Heightmaps that are used like displacement-mapped polygons would give the best out of both worlds (any comments on that encouraged )
I tried that once... it's a cool idea. Unfortunately, I got distracted before getting too far. The main problem I remember (besides speed) is that you must have strict control of texture scaling. If you shrink a texture, it impacts the frame rate in a huge way. This means mip-mapping is absolutely essential. I never tried this, but it could be nice to use normal/bump mapping for far surfaces that are not being viewed at a sharp angle - and render it as a standard flat surface.Correct. It's always best to make the longest dimension the height (z direction).
Why is it best to make z the *longest* direction? Isn't the 256 in 1024*1024*256 the z? And why is it then slower to look down in Voxlap?A brute-force approach is doable if you like measuring speed in seconds per frame.
I didn't speak about a brute-force approach... but then probably I don't know enough about the workings of your algorithm. I was under the impression that the idea of the algorithm is to take a (more or less) normal outcast-render and then transform the picture (plus having strange boundaries for the rays, and tweaking their distribution, ...). Of course I have no idea how you can deal efficiently with room-over-room if the z-direction is RLE'd (so I think that you would have to traverse all of the RLE-data to find your ray-position), especially because you said that the z-direction should be the longest...
BTW, sorry for asking so much about your algorithm :wink: You don't have to answer.
Maybe if I find the time (would have to be lots of time) I will dig into the source-code and see for myself if its possible to write a general raycaster...The main problem I remember (besides speed) is that you must have strict control of texture scaling. If you shrink a texture, it impacts the frame rate in a huge way. This means mip-mapping is absolutely essential.
Yes, mip-mapping is necessary. But I think that the algorithm should still be maybe only 2-5 times (I hope more like 2-3 times, but not sure) slower than a normal texture-mapper.Why is it best to make z the *longest* direction? Isn't the 256 in 1024*1024*256 the z? And why is it then slower to look down in Voxlap?
I squeeze the z coordinate in a byte - that's why the height is limited to 256. Tall things like telephone poles not only compress better with my RLE compression, but they render faster because there are fewer vertical "slabs" in the object to consider. When you look down, the frame rate drops because there are more raycasts / vertical planes being scanned.Tall things like telephone poles not only compress better with my RLE compression, but they render faster because there are fewer vertical "slabs" in the object to consider.
Ah, that makes sense...
So lots of "room over room"-things could kill the framerate, and I should use sprites for complex "fuzzy" things like trees? So now I can see why you don't use raycasting for everything...- Sprites are mainly for things that move on every frame, such as players, monsters, bullets, and rotating pick-ups. Before I implemented sprites, I tried doing all animation in the raycasted world map - I had to backup, modify, and restore all objects for every frame!. As you can imagine, this way too slow.
You could use sprites for static decoration, but you should really use them sparingly. If you want to render a few special objects as sprites to get higher resolution, that's ok. Rendering 100 static trees as sprites is a bad idea. Voxlap renders all sprites that intersect your viewing pyramid - whether they are hidden or not. I have no mechanism in place to skip sprites that are fully behind walls. I use mip-mapping for far sprites to keep the frame rate reasonable. - I think that it would really improve the usefulness of Voxels for games if it would be easier to use the sprite/world-rendering functions inside higher-level algorithms in unexpected and creative ways that may do e.g. culling, LOD, animation, allow for transparent objects, mirrors, and so on, much like you use standart texture mapped triangles inside high-level-engines to achive something that only z-buffered triangles could never do.
I believe that it is possible and not too hard, because even with the existing engine one could for example draw a object in one corner of the board, render this to an offscreen buffer and after rendering the world copy it onto the framebuffer using z-compare. Of course it would be a little hard to set the camera FOV and direction and so on appropriately, and also it would be a problem if you wanted to render the object from the other side (maybe a copy in the opposite corner of the board would solve this :) ). Maybe one could also have two boards (as I understand it, Voxlap holds the pointer to the board and you can't change it easily, but theoretically), one with all the sprites divided by black walls and the other with the world.
This would be a (very hacky) sprite-raysurfer. In pretty much the same way you could have transparent sprites, tiled worlds, etc.
Don't know if it would work in practice, probably the camera setup kills it all. But I don't think that you will have to measure speed in seconds per frame. :wink:
BTW, is there any way except digging through all the assembly to find out how exactly (or conceptually) your algorithm works? - Well, all assembler code of the core opticast algorythm is part of the hrend and vrend functions (with or without fog and for the different cpu types) and ken was kind enough to put c functions of them into his code. But they absolutely kill the speed. I used modified versions of hrend and vrend to draw the voxels in Direct3D, to make combined voxel and polygon rendering possible. It works, but it only runs on 1 FPS and that is not very useful.
But to understand the algorythm they'll surely be very helpful. draw a object in one corner of the board, render this to an offscreen buffer and after rendering the world copy it onto the framebuffer using z-compare.
That's an interesting hack, but I don't think it would compete with my existing sprite rendering algorithm in terms of speed. If I ever choose to implement it, I would do it the right way.is there any way except digging through all the assembly to find out how exactly (or conceptually) your algorithm works?
There is a C version of my raycast loop located the end of gline(). Unfortunately, it's not much easier to understand than the assembler code. BTW, the hrend() and vrend() functions are only for the second pass. They copy the raycasted data to the screen with the correct projection.- Oh yes, sorry, i've overlooked that there are more assembler functions in opticast. It makes sense that the raycast algorithm is written in assembler, too. Stupid me. :)