• Register

ScrumbleShip is the most accurate space combat simulation devised to date. Gather resources, construct a capital ship out of individual blocks, then pilot it with AI or human help against other players.

Post news Report RSS Shaders so sharp you'll cut yourself

We increased the number of polygons on screen by a factor of 10. Here's how.

Posted by on

The Difference

September 10th September 20th

Go ahead, click both of those images so they show up full size. Don't worry, they'll pop up in new tabs.

Ten days ago, my game looked like the image on the left. Today, it looks like the image on the right.

Wow! Looks a lot better, doesn't it? But every graphical improvement has a price... So how much slower does the game run now?

Well, all of these graphical improvements come at the cost of a huge performance improvement.

Wait, what?

But first, the news.


Before we start, let's stop for a moment and talk about voxels, just so everyone's on the same page.

No 3D object in ScrumbleShip is textured.

ScrumbleShip renders its world using voxels, which are the 3D equivalent of your monitor's 2D pixels. In ScrumbleShip, these are shown as small, untextured cubes. We also have "blocks", which are collections of voxels 16 long, 16 thick, and 16 tall. So every block we put on the screen is composed of 16*16*16, or 4096 tiny cubes. This allows for some cool tricks, one of which we'll talk about today.

Now on to the improvements!

Order and Chaos. Well, ordering. Lots of ordering.


The most obvious improvement between the two images is the view distance, which has at least quadrupled. Hundreds of blocks that used to be rendered as featureless blanks suddenly pop into full view.

The big thing that allowed me to do this was changing the order in which I hand voxels to the graphics card. Nearly every opengl tutorial I've seen makes at least passing mention of drawing the scene from front to back, but I had always discarded this as a potential minor optimization - Nice for some day, but not really vital for now.

I was very, very wrong.

It turns out that modern graphics cards are remarkably efficient when scenes are drawn front-to-back. For the average ScrumbleShip scene, they're over ten times as efficient. So where we used to struggle along at 20-30fps with 100,000 voxels, now we can see a million voxels at 30-40fps.

End result? Wonderful scenes like these, rendered at playable speeds:

Expanded

VSync? More like VSunk.


When I originally re-ordered the voxels, I had some very interesting results. My render times instantly went "Non-linear". In other words, I could suddenly render 1 million voxels at the same frame rate as 100,000 voxels.... And that frame rate was 22 frames per second.

22FPS is... not awesome.

So what was going on? If I could render a million voxels slowly, why couldn't I render 100,000 voxels quickly?

The answer turned out to be in the vsync features of ScrumbleShip. Before the graphical update, more than 30fps was basically wasted effort, so I'd told one of our libraries to "sync" the image with every other frame your monitor displayed. Well, due to the particular sub-millisecond timings of these events, the best the engine could do was sync with a small handful of these events.

In short, turn off the vsync, and the framerate soars to 30-60fps.

Using a shader to shade things


Another large graphical improvement comes in the from of an absolutely tiny effect - I vary the color of each side of each voxel by 10%. This simulates some of the effects of diffuse lighting in the real world, and suddenly the 3D nature of objects "pops", and the tiny cubes actually look like tiny cubes.

Here's an example using some heavy damage on some factory blocks:

Voxel Damage Improved

I do use a little trickery here - I color the "top" of the voxel a little brighter than the "bottom". This poorly simulates the way light in space would work, but it correctly simulates our everyday experiences walking around with the sun overhead, so it ends up looking more natural to the human eye.

This process is done entirely in something called the "Fragment shader" of the graphics card. This fragment shader is designed to manipulate hundreds of megabytes of textures across the entire screen. Since ScrumbleShip doesn't deal with textures, we've been badly under-utilizing the fragment shader. It's basically like having Vincent Van Gogh paint your house.

Since this lightening/darkening process is done within an under-utilized portion of the graphics card, it cost us 0fps - A free improvement!

The wizard of LOD


Before EightCache EightCache

Another change I made is the introduction of a Level-Of-Detail system. Previously in ScrumbleShip, any individual block was either "High Resolution" (16x16x16 voxels), or "Block Resolution" (1 big voxel). This created a somewhat jarring effect when trying to look at things in the distance. Because, well, you couldn't.

The big breakthrough was when I realized that people couldn't really see 16x16x16 blocks in the distance. Stuff got all blurry and it looks more like a lower resolution block, like maybe 8x8x8... Hey. Why not average some of the voxels and *actually* display an 8x8x8 instead of the 16x16x16 block? And after that, maybe a 4x4x4 block!

You can see the results of this system in the link above. The two images contain the same blocks, but the one with level of detail is miles ahead of the one without. The level-of-detailed blocks just end up looking slightly blurry.

What's next?


Well, there are still optimizations to make, that's for sure. I doubt I'll find another 10x improvement... But then, if you'd told me I would find a 10x improvement two weeks ago, I would have laughed at you.

All these changes are in the latest "bleeding edge" release, and will be making their way into the full, released version in another week or two.

The most obvious improvement to make is to send less redundant data to the video card. Because of the amount and frequency of the voxel data we send, there's a tiny hiccup every 5 frames or so, causing that frame to show up on the screen for 1-2ms longer than it normally would. Not a huge difference, but it might be worth a few FPS to fix.

Other than that, I really think it's time to focus on features other than the graphics. With these changes, I've finally gotten the graphics to a point where they truly look and perform well. Maybe I should focus on combat? Atmospheric simulation? Ship stress simulation? Tell me your thoughts in the comments, please!



Cheers,
-Dirk

Post comment Comments
Guest
Guest

Wow. That's really awesome! Thanks for writing down what you learned. Those are some good lessons.

I noticed that you mention the speed up in FPS several places. It turns out to be easier to think about speedups if you measure things in the millisecond cost of the thing. The advantage is that if you have a target for FPS then you can calculate how many total ms you have for rendering and then divide those ms between each task.

When something takes 2ms and something else takes 3ms, that takes 5ms out of your budget. Try to do the math that simply using FPS. You can't. Instead, you end up having to convert the FPS to something else in order to be able to calculate the total performance hit.

This article explains it better than me: renderingpipeline.com/2013/02/fps-vs-msecframe/

Reply Good karma Bad karma+3 votes
dirkson Author
dirkson

Yup! I'm actually familiar with this. My user-facing metric is FPS, and my me-facing metric is a combination of millisecond timings and profiling using apitrace. (Only learned about apitrace the other day. Amazing stuff!)

It's also worth noting that there's a difference between the cpu time taken by commands the the gpu time taken. I haven't entirely sussed out the relationship(s), but apitrace is helping.

I just figure users and general readers are more familiar with FPS, so I went with that for the article.

Cheers,
-Dirk

Reply Good karma+2 votes
Guest
Guest

I would love to see more ship simulation get added. This game looks great and I cannot wait to be able to fully simulate a ship's functions.

Reply Good karma Bad karma+4 votes
zellman86
zellman86

I second this. 3D ship movement would be super cool!

Reply Good karma Bad karma+1 vote
Lulloser
Lulloser

Nice one Dirk!
Now I am 100% pleased with the graphics on distance :D

I think the next step should be flying our ships and maybe add the function to fire weapons so we can actually try our ships :P

Reply Good karma Bad karma+3 votes
BurningPet
BurningPet

Impressive work mate.

The main thing that is still bothering me is the UI, it is in a completely different style with the game graphics.

I took the liberty in demonstrating how a more fitting UI might look like:
Dl.dropboxusercontent.com

If you like it, i can send you the open PSD file so you could extract the elements.

Reply Good karma Bad karma+3 votes
Insolent.
Insolent.

I actually quite like that UI! I'm sure Dirk will accept it as a mod - maybe even a togglable option in-game?

Reply Good karma Bad karma+1 vote
dirkson Author
dirkson

That actually... doesn't look too bad!

I *have* been wanting an alternative - For every UI compliment, I get one UI complaint. If you create block-ized versions of the rest of the gui options, I'd love to stick 'em in the game as an option.

Do you have a copy of the game yet? You should say hi: Scrumbleship.com

Cheers,
-Dirk

Reply Good karma+1 vote
Guest
Guest

I really like that UI concept. Much more fitting with the voxel theme. Perhaps also have a shader to distort the view to look more like you're staring out of a helmet of a spacesuit.

The UI should definitely be a priority though.

Reply Good karma Bad karma+3 votes
Insolent.
Insolent.

This was a triumph.
I'm making a note here: huge success.
It's hard to overstate my satisfaction.

Seriously, well done. I think you're right - the graphics and LOD systems are now at Tue point where you can focus on gameplay features. But which ones? Thinking of the way the game currently plays, I think atmospheric simulation and electricity would be a fin next step that would also help set the game apart. If you make players need air, then you'll turn the existing multiplayer play space into a survival game in which players need to build spaceworthy ships and asteroid bases to survive. :D

Of course, you'd want to implement electricity simulation either before atmosphere, or immediately after air pressure. Otherwise, where would the fresh air be coming from?

So yeah, air and power are my two cents for what to do next. It'll really highlight ScrumbleShip's physics-centric simulation, and be fun.

After those are in place, I think player models and player damage simulation is in order.

Reply Good karma Bad karma+3 votes
micromil
micromil

The improvements look awesome and improved functionality - even better!

The next step would be a difficult choice, as it all needs to come together eventually.

If ship movement could be done and then the realism (power, fuel, structural stress, etc) filled in behind with minimal issue I know a heap of people would like that.

A close second would be Insolents Ideas of space worthiness testing.

Reply Good karma Bad karma+3 votes
Jacob843
Jacob843

Awesome! This really shows ScrumbleShip's beauty!

Personally, I would really like atmospheric simulation. Mostly because I know it will be complex, and complex things are fun! But I doubt that would happen in the next release, so full ship movements sounds good too!

Reply Good karma Bad karma+1 vote
Omyki
Omyki

yo,
i think you should begin to focus on some core gameplay features, to begin making the game experience evolve.

As to the order of these features i think you should begin, not with the ones that depend on others to work, but to the most basic ones, and then onto the more advanced ones. For instance, i would not recommend ship movement yet, since it depends on electricity, so as for a start, why not begin to insert electrical ability, generators. Then moving on to use this electricity somehow (displays, switches, stuff) and after that mabe some oxygen generators, and then the ability so suffocate, gaz physics, like if your ship is broken, the air would escape. Etc...

Keep on the good work, i've been following you for more than a year now

Reply Good karma Bad karma+3 votes
Jacob843
Jacob843

Now that I think about it, this does make more sense. Implementing a backbone of resources into the game will make future features easier to make.

Reply Good karma Bad karma+1 vote
nadanova
nadanova

Some fantastic explanations here, I may just have to send some of my money your way in the near future for a copy ^^

Reply Good karma Bad karma+2 votes
BlackMoons
BlackMoons

Yes I am amazed how well 'early Z' depth culling works (What you get when you render front to back) 10~30% performance improvement in my game for most scenes for just rendering the nearest terrain 'first' to depth buffer only and then rendering the rest in random order.

Although I must note, Using alpha test/discard() disables early z optimizations. Avoid it for most rendering if you can!

Reply Good karma Bad karma+1 vote
Guest
Guest

Atmospherics ftw!!!! :)

Reply Good karma Bad karma+1 vote
Post a comment

Your comment will be anonymous unless you join the community. Or sign in with your social account: