-
-
Notifications
You must be signed in to change notification settings - Fork 97
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Compress Vertex Normal/Tangent Vectors Using Octahedral Mapping #2395
Comments
Related to #2350. |
Related https://aras-p.info/texts/CompactNormalStorage.html#method03spherical Similar optimization is possible for normal maps as well. |
Yes definitely! That article was a great resource for me :) could also be used in deferred rendering with gbuffers as described in that article haha The reason I used spherical coordinates and not something like quaternions was because in Godot there is the option of having only the normals stored (so no tangents/normal maps) and with spherical coordinates you can store just the normal vector using 2 bytes which is convenient Also quaternions do not support skew tangent spaces for normal mapping if artists use that (I don't have a lot of experience in this area but using the spherical coordinates basically keeps support for everything Godot already supports normal wise haha) |
Cool technique. @clayjohn don't we already reduce normalmaps by leaving out one axis? Only there we do a simple |
@BastiaanOlij take a look at the article i linked above. Our current method is the fastest (but only by a small margin) and has much worse quality than the proposed method. |
@clayjohn sorry missed you article, cool read :) |
After doing a bit of experimentation, I thought that it would be good to add an option for developers between oct16 and oct32 compression (oct = octahedral map). In most scenarios the oct16 looks perfect, but in the extreme scenarios (a high poly sphere with highly specular, mirror-like material) the compression artifacts do start to show up Oct32 however is indistinguishable from the ground truth (float32x3) and takes up the same space as the existing normal compression (snorm8x4) I have attached some examples I created showing off the differences (float32x3) Ground Truth in stable 3.2 (snorm8x4) Current Compression in stable 3.2 (oct16) Currently Implemented in the proposal's PR, and would be the "super compress normal" option (oct32) Proposed addition, not currently implemented, and would be the new "compress normal" option I haven't updated the implementing CL (godotengine/godot#46800) yet as the change to add compression depends on the change in godotengine/godot#46574 which makes it easier to pass around the mesh compression flags, but wanted to bring this up for discussion! |
@The-O-King Given your results, is it even worthwhile to expose ground truth? Maybe compressed should use oct16 while "uncompressed" uses oct32. |
That's a valid question for sure, I personally think that getting rid of ground truth makes sense, and might have additional positives because it will also reduce the number of shader permutations that we have to generate, since the vertex attributes will be the same format across compressed (oct16) vs uncompressed (oct32) So yea I'm not sure what value there would be keeping around ground truth float32x3 |
Implemented by godotengine/godot#46800. |
Describe the project you are working on
Godot Renderer
Describe the problem or limitation you are having in your project
Applications with large amounts of vertex data can be bottlenecked by memory bandwidth, especially on mobile devices; and applications with lower amounts of vertex data still throw away a lot of power/time/cache performance
Describe the feature / enhancement and how it helps to overcome the problem or limitation
A potential area of improvement is reducing vertex size, specifically compressing vertex normals and tangents, saving 4 bytes/vertex
Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams
Currently normal and tangent compression is done by using 8-bit UNORM vec4 for the normal and tangent vectors each
Using spherical coordinates this can be reduced further down to 8-bit UNORM vec2 for the normal and tangent vectors each; since the radius of these normal vectors is always assumed to be 1 only phi and theta are neededThe decompression done in the shaders is a little more expensive (requiring sin/cos to get back cartesian coordinates) but from my tests it has not negatively affected performance on mobile and desktop devices - the memory bandwidth savings outweigh these costs; and visually there isn't any regression that I could seeUsing Sphere Mapping, we can map a unit sphere down to a 2D plane, meaning we can represent any normal or tangent vector using two digits. This means we can use 8-bit SNORM vec2 for both the normal and tangent vector. The decompression in the vertex shader only needs some add/mul and a single sqrt, so it's cheaper to do then the spherical coordinates mentioned above and has better visual quality too! See this link for some detailsI currently have an implementation for Godot 3.2 under GLES 3 ready - GLES2 is mostly complete but is stuck as currently I am using macros to define whether the normal or tangent vector is compressed (I define two new macros, one for normal and the other for tangents) and it seems I have hit the 32-bit limit of the bitmask used to enable/disable conditionals for the shader generator function, any tips on how to solve this (or if there is a better approach without using more conditionals) are welcome :)Using Octahedral Mapping, we can map a unit sphere to an octahedron, which then can be mapped down to a 2D plane and be represented as "texture coordinates" into this plane. This is an improvement over sphere mapping as it has higher quality, avoids some of the singularities that sphere mapping can suffer from, and is at least as cheap to decode in the vertex shader. For more details, see this paper
If this enhancement will not be used often, can it be worked around with a few lines of script?
N/A
Is there a reason why this should be core and not an add-on in the asset library?
This is a low level change to the way that vertex data management is done in the renderer
Android Games DevTech Team @ Google
The text was updated successfully, but these errors were encountered: