Normals on CPU or shader?

Started by
7 comments, last by Hiyar 14 years, 8 months ago
Hello, I am working on a heightmap based terrain editor and thus my vertex heights are dynamic/editable. Currently I recalculate the vertex normals on the CPU, if the user rises (or lowers) terrain vertices. Thus the normals are only recomputed if the vertex height changes. When the user finished editing the terrain the terrain is basically static (because all vertex normals are already computed). Now I wonder if it would be better to compute the normals every frame in the vertex shader (with a texture lookup in the heightmap texture?). The Pros would be: + the GPU is likely faster at such operations + Destructable terrain is possible The Cons: - I have to rewrite my code - I have to recompute ALL normals every frame My terrain vertex grid/heightmap typically has sizes of about 513^2 vertices. What do you think is better?
Advertisement
Quote:- I have to rewrite my code
- I have to recompute ALL normals every frame

Rewriting code to make it better should never be avoided. No excuse. [SMILE]

However, you're working on an editor and (I assume) you'll want to save the normals to file. You can ensure what you save is what you see by using the same code to calculate the normals as what is rendered, i.e., in the CPU. If you use a shader calc and you want to change the code for calculating the normals, you have to revise both the "save" code and the shader.

A consideration for using the shader calc, however, may be any slowdown in the interface to the user when you're calc'ing new normals. That seems a bit unlikely if you're only recalcing normals for 3 vertices at a time, though, even with locking a buffer (if that's where the normals are stored), revising the normals and unlocking.

Testing will help you decide.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

Like Buckeye, rewritting your code isn't an excuse.

As for recalculating all the normals every frame depends on the terrain's complexity.

If your terrain has 1.000.000 normals, it's better to do it offline. While if it has less than i.e. 50.000, you woouldn't notice a difference.

If you're in DX10, you can consider the possibility of using stream out to compute the normals in the GPU only once, then get the results.
Otherwise, I'd go for the do-it-on-the-cpu unless it becomes very tedious or you come with a LOD algorithm that allows you to only compute the normals (every frame) of the parts of the terrain you're actually seeing.

Cheers
Dark Sylinc
Quote:- I have to recompute ALL normals every frame


Why?

Compute a normal map at startup (or precompute if the heightmap will always start the same).

Then, as part of the method that edits the heightmap for changing height, tell it to produce a new normal map.

You'll be producing a new normalmap every frame whilst the terrain is changing, but then you don't have to produce one at any other time.

Then again, generating a normal map every frame is a really minor overhead anyway.
Quote:Original post by adt7
Quote:- I have to recompute ALL normals every frame

Why?


I believe he's saying that if he puts it into his shaders he'll have to do it each frame, as opposed to his CPU method.
Quote:Original post by SymLinked
Quote:Original post by adt7
Quote:- I have to recompute ALL normals every frame

Why?
I believe he's saying that if he puts it into his shaders he'll have to do it each frame, as opposed to his CPU method.
And adt7 is saying that you can use a shader to generate a normal map from the heightmap, and then cache that normal map until the next update...

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Agreed. When the heights change run a pixel shader that computers the normal map.
Quote:Original post by Buckeye
A consideration for using the shader calc, however, may be any slowdown in the interface to the user when you're calc'ing new normals. That seems a bit unlikely if you're only recalcing normals for 3 vertices at a time, though, even with locking a buffer (if that's where the normals are stored), revising the normals and unlocking.

Now I feel terrible stumbling across you again [grin] but doing the normals calculation in a thread does not stall the GUI in any way. But you should not microlock the vertex buffer for a bunch of three vertices to be updated. Kick off a thread that recalculates the whole concerned patches of terrain. Once this thread is finished lock and load ... and unlock. There should be no stall whatsoever.

@original poster
There is no general answer to that. You cannot point your finger at this and that and tell that it will be the bottleneck of your application. Doing the normal calculation on the shader should only be done if you do not have other hefty shaders which are really required to be runtime calculations. Using the CPU for precalculating data is okay, especially for an editor that saves this information then in its custom export format.

The only real advantage I see in using shaders for normal calculations are indeed an ever-changing geometry. If you are just looking at local modifications of terrain patches it will be okay to use a CPU thread to recalculate the normals and upload a changed vertex buffer when such a change in terrain occurs.

You could also use the GPU with a shader to calculate the normals and output them to a texture you access when rendering your terrain (read: normal map). But keep in mind the memory consumption of such an approach. In todays 3D applications you are already bound to have several render targets for things like HDR, deferred shading, SSAO, and things like that. Adding more load to the GPU for terrain normals does not sound necessary for me.

I would try and go with the local vertex buffer modification for a changed terrain patch. If this is too slow for your purposes start analyzing your app for real bottlenecks to see if using shaders would be of any help. But (which I guess is more likely) if you find no bottleneck with the CPU approach stick with that.
------------------------------------I always enjoy being rated up by you ...
I'm doing the terrain normal calculation in the shader at runtime.
The main reason for that is reducing memory usage and destructable terrain.

If your terrain is just 513*513 you can use precomputed terrain normals. Don't need to do it in the shader.
While editing the terrain, you just update the normals in the modified area.

This topic is closed to new replies.

Advertisement