Jump to content
The Dark Mod Forums

Convert normal maps to RGTC?


duzenko
 Share

Recommended Posts

I know I'm probably stating the obvious. But to convert so many textures in a row, a batch script is surely going to be needed, which loops through all files in subdirectories and converts them. Like there's ffmpeg for video, imagemagick is probably going to be what we want to look at here. Can't seem to find the exact command for this with a quick search unfortunately. Hopefully the team has the conversion process figured out already, if not let me know and I'll see if I can keep digging and find one.

Also feel free to share a normal map in this format somewhere. I'm curious if Gimp can open it for me on Manjaro.

Link to comment
Share on other sites

11 hours ago, OrbWeaver said:

Sure, I'll see if I can dig out the normal map. I'm sure it's something I'm doing wrong, like not using the right compression format or using an out-of-date or broken DLL version.

Well it seems there was something problematic with my installation, because I updated to the latest SVN, exported the normal map from GIMP in BC5 format, and it works fine in game. I'm not sure what the problem was before — perhaps I was just testing with a game DLL which didn't have the latest changes.

BC4 definitely doesn't work but according to the description here, this is a 1-channel format so it wouldn't be expected to. I'm pretty sure I tested all of the GIMP formats the first time, but maybe I was just being dumb and tested BC4 multiple times but never tried BC5 🤷‍♂️

@duzenko I've uploaded the images here if you want to confirm that the formats are correct. The diffuse is DXT1 and the normal is BC5, although in this particular case I would probably keep the normal map as PNG since this is less than 10% of the size of the DDS (because it's a smooth gradient normal map which compresses well with PNG).

@MirceaKitsune Feel free to download the linked archive and see if you can open the _local map. I'm 99% sure you will be able to because I can read and write it fine on Ubuntu using GIMP.

  • Like 1
Link to comment
Share on other sites

Well I found the downside to BC5 compression: DarkRadiant doesn't currently support it. On the plus side, this does at least confirm that I exported the image in the correct format (it complains that "ATI2" format is not recognised).

https://bugs.thedarkmod.com/view.php?id=5686

Hopefully it is very easy to fix, since we just need to pass the compressed data through in the correct OpenGL format.

Link to comment
Share on other sites

11 hours ago, OrbWeaver said:

Hopefully it is very easy to fix, since we just need to pass the compressed data through in the correct OpenGL format.

Turns out it's not quite as simple as I hoped. RGTC isn't just another RGB format which can be sent to the existing renderer as-is, it's a two-channel normal map which needs the blue channel to be reconstructed by the shader. But first, I have to be sure I'm actually loading it correctly.

@duzenko I'm a little confused by the game code (which I'm hoping to use as a guide).

In idImage::SelectInternalFormat(), there is a check for image_useNormalCompression which then results in the image being compressed into GL_COMPRESSED_RG_RGTC2 format:

// catch normal maps first
if ( minimumDepth == TD_BUMP ) {
	if ( allowCompress && globalImages->image_useNormalCompression.GetBool() ) {
		return GL_COMPRESSED_RG_RGTC2;
	}
	return GL_RG8;
}

But in idImage::UploadPrecompressedImage(), a different format is chosen if "ATI2" is the FOURCC:

case DDS_MAKEFOURCC( 'A', 'T', 'I', '2' ):
	internalFormat = GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT;
	break;

So I'm not quite sure which is the right OpenGL format to use. Surely the chosen format should be the same regardless of whether a precompressed image is loaded or if the image is dynamically compressed at runtime? Or are these two GL formats actually identical?

Link to comment
Share on other sites

On 7/27/2021 at 10:05 PM, nbohr1more said:

WOO!!!

@Dragofer can you test BC5 normal maps again?

I've:

  • Updated my SVN for assets and source code, compiled the latest source code
  • Removed the normalmap from my SVN install for one of those textures
  • Exported that normalmap as a BC5 .dds with mipmaps in GIMP
  • Placed that .dds normalmap in the corresponding dds/ folder
  • Loaded OGDA's demomap

The console tells me that TDM failed to get a bindless texture handle on that normalmap 😕 There's no normalmap effect visible ingame.

Link to comment
Share on other sites

GL_COMPRESSED_RG_RGTC2 is the right format.

We don't have precompressed RGTC textures yet, maybe precompressed upload is broken.
Although I recall that someone tried it and said it was OK...

Unfortunately, you won't be able to pass RGTC texture "as is" to renderer.
It only contains X and Y components, so Z component must be computed in shader (maybe also X and Y normalized).

Link to comment
Share on other sites

13 minutes ago, stgatilov said:

GL_COMPRESSED_RG_RGTC2 is the right format.

Thanks, that's useful.

13 minutes ago, stgatilov said:

We don't have precompressed RGTC textures yet, maybe precompressed upload is broken.
Although I recall that someone tried it and said it was OK...

Now I'm even more confused, because it did seem to work (with precompressed DDS) last night, but didn't when I tried it last week, and it sounds like not working is actually the "correct" behaviour based on the code...

I wonder if it's a graphics driver quirk or something. Maybe it happens to work occasionally but isn't working reliably due to mismatched formats.

13 minutes ago, stgatilov said:

Unfortunately, you won't be able to pass RGTC texture "as is" to renderer.
It only contains X and Y components, so Z component must be computed in shader (maybe also X and Y normalized).

Right, hopefully I can take that calculation more or less verbatim from the TDM shader code. But I might hold off on implementing this for now; if the game doesn't yet support precompressed RGTC and nobody is using them, it is not so critical if DR can't correctly preview these normal maps.

Link to comment
Share on other sites

15 hours ago, OrbWeaver said:

@duzenko I'm a little confused by the game code (which I'm hoping to use as a guide).

In idImage::SelectInternalFormat(), there is a check for image_useNormalCompression which then results in the image being compressed into GL_COMPRESSED_RG_RGTC2 format:

// catch normal maps first
if ( minimumDepth == TD_BUMP ) {
	if ( allowCompress && globalImages->image_useNormalCompression.GetBool() ) {
		return GL_COMPRESSED_RG_RGTC2;
	}
	return GL_RG8;
}

But in idImage::UploadPrecompressedImage(), a different format is chosen if "ATI2" is the FOURCC:

case DDS_MAKEFOURCC( 'A', 'T', 'I', '2' ):
	internalFormat = GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT;
	break;

So I'm not quite sure which is the right OpenGL format to use. Surely the chosen format should be the same regardless of whether a precompressed image is loaded or if the image is dynamically compressed at runtime? Or are these two GL formats actually identical?

Congratulations, you have been the first one to discover this secret area! :)

I'm pretty sure the shaders expect GL_COMPRESSED_RG_RGTC2 while GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT is something we'd want to drop but I don't know if we already have any ATI2 assets to convert first

4 hours ago, Dragofer said:

I've:

  • Updated my SVN for assets and source code, compiled the latest source code
  • Removed the normalmap from my SVN install for one of those textures
  • Exported that normalmap as a BC5 .dds with mipmaps in GIMP
  • Placed that .dds normalmap in the corresponding dds/ folder
  • Loaded OGDA's demomap

The console tells me that TDM failed to get a bindless texture handle on that normalmap 😕 There's no normalmap effect visible ingame.

Disable bindless textures and enable the normal compression cvar?

2 hours ago, stgatilov said:

Unfortunately, you won't be able to pass RGTC texture "as is" to renderer.

It only contains X and Y components, so Z component must be computed in shader (maybe also X and Y normalized).

What do you mean? Our on-the-fly normal compression does just that - it uploads textures in RGTC2 and the shaders do reconstruct the Z component

Link to comment
Share on other sites

2 hours ago, duzenko said:

Congratulations, you have been the first one to discover this secret area! :)

I'm pretty sure the shaders expect GL_COMPRESSED_RG_RGTC2 while GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT is something we'd want to drop but I don't know if we already have any ATI2 assets to convert first

I think the only precompressed asset so far is the test texture on my hard disk (which I uploaded a few posts ago). It appears I was jumping the gun and assuming that this was already supported and maybe even used by the main mod, whereas it hasn't yet been implemented for on-disk DDS files.

2 hours ago, duzenko said:

What do you mean? Our on-the-fly normal compression does just that - it uploads textures in RGTC2 and the shaders do reconstruct the Z component

This was referring to the shaders in DarkRadiant, which don't yet support reconstructing the Z component from RG textures. But I only need to worry about this once there are precompressed textures involved, since DarkRadiant doesn't do any on-the-fly compression at all.

Link to comment
Share on other sites

On 7/27/2021 at 10:07 PM, OrbWeaver said:

@duzenko I've uploaded the images here if you want to confirm that the formats are correct. The diffuse is DXT1 and the normal is BC5, although in this particular case I would probably keep the normal map as PNG since this is less than 10% of the size of the DDS (because it's a smooth gradient normal map which compresses well with PNG).

And how did you test these files? Is there a core material that will use them?

Link to comment
Share on other sites

3 hours ago, duzenko said:

And how did you test these files? Is there a core material that will use them?

No, I just put them into the dds tree and created a material for them, i.e.

textures/orbweaver/tiles/rounded_slate
{
    diffusemap textures/orbweaver/tiles/rectblocks_d
    bumpmap textures/orbweaver/tiles/rectblocks_local
}

But it turns out I was wrong about the normal map working. I just hadn't deleted the PNG original from the textures directory, and this seemed to be used instead. With just the DDS normal map present, I get missing/flat normals.

However, I can get it to work with the following source patch:

Index: renderer/Image_load.cpp
===================================================================
--- renderer/Image_load.cpp	(revision 9519)
+++ renderer/Image_load.cpp	(working copy)
@@ -28,7 +28,7 @@
 PROBLEM: compressed textures may break the zero clamp rule!
 */
 static bool FormatIsDXT( int internalFormat ) {
-	if ( internalFormat < GL_COMPRESSED_RGB_S3TC_DXT1_EXT || internalFormat > GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT ) {
+	if ( internalFormat < GL_COMPRESSED_RGB_S3TC_DXT1_EXT || internalFormat > GL_COMPRESSED_RG_RGTC2 ) {
 		return false;
 	}
 	return true;
@@ -1145,7 +1145,7 @@
 			internalFormat = GL_COMPRESSED_LUMINANCE_LATC1_EXT;
 			break;
 		case DDS_MAKEFOURCC( 'A', 'T', 'I', '2' ):
-			internalFormat = GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT;
+			internalFormat = GL_COMPRESSED_RG_RGTC2;
 			break;
 		default:
 			common->Warning( "Invalid compressed internal format: %s", imgName.c_str() );

The logic in FormatIsDXT() seems very fragile to me (making assumptions about the numeric values of all supported compression formats), but with this change I am seeing the expected normal maps with the ATI2 local image.

Link to comment
Share on other sites

Sure, I'm happy to commit it.

One thing I didn't confirm however is whether the shader can correctly identify which normal maps need Z component reconstruction and which don't. If there are a mixture of precompressed RGTC files and uncompressed TGA or PNG normal maps, the shader presumably needs to know which are which (or does it just always reconstruct the Z component, regardless of whether Z information is present in the input image?)

Link to comment
Share on other sites

4 hours ago, OrbWeaver said:

Sure, I'm happy to commit it.

One thing I didn't confirm however is whether the shader can correctly identify which normal maps need Z component reconstruction and which don't. If there are a mixture of precompressed RGTC files and uncompressed TGA or PNG normal maps, the shader presumably needs to know which are which (or does it just always reconstruct the Z component, regardless of whether Z information is present in the input image?)

I think ATM you need to manually set the image normal compression cvar for this to work

Link to comment
Share on other sites

I believe that the current design works like:

image_useNormalmapCompression 0

Image is loaded uncompressed, environmental variable is passed to glprogs, GLSL standard branch renders shader

image_useNormalmapCompression 1 ( default )

Image is compress on load, environmental variable is passed to glprogs, GLSL RGTC branch renders the shader

 

The open question is:

What happens if the cvar is set to 1 and the texture is already compressed?

If the detection code bypasses the attempt to compress the image or the compressor recognizes the image as matching the desired destination format the the shader should do it's job since the correct branch is activated

Please visit TDM's IndieDB site and help promote the mod:

 

http://www.indiedb.com/mods/the-dark-mod

 

(Yeah, shameless promotion... but traffic is traffic folks...)

Link to comment
Share on other sites

Nope. There is no shader branch since 2.09. All shaders expect red-green-encoded input, normal map texture format is either GL_COMPRESSED_RG_RGTC2 or GL_RG8, depending on image_useNormalCompression.

So presumably RGB normal maps would have to be converted upon load, though I'm not sure if/where that happens in code.

In either case, precompressed textures should be uploaded as they are and not be affected by image_use(Normal)Compression.

Edit: actually, no conversion should be needed as long as the RGB textures were normalized, I guess. They just get their B channel cut off, which is then recalculated in the shader.

Link to comment
Share on other sites

4 hours ago, nbohr1more said:

What happens if the cvar is set to 1 and the texture is already compressed?

I looked at this a couple of weeks ago because I was confused about the interaction with image_use[Normal]Compression and precompressed textures.

It turns out that if image_usePrecompressedTextures is on (which it must be otherwise the mod will have mostly black textures), the precompressed images are used automatically and exclusively (if present), and the values of image_use[Normal]Compression have no effect whatsoever. The latter cvars only affect what happens to uncompressed textures: are they compressed on the fly or used as-is?

4 hours ago, cabalistic said:

Nope. There is no shader branch since 2.09. All shaders expect red-green-encoded input, normal map texture format is either GL_COMPRESSED_RG_RGTC2 or GL_RG8, depending on image_useNormalCompression.

That should certainly simplify things. The shader won't care whether the original image was compressed or not, since all it receives is RG colour information regardless of the source format.

4 hours ago, cabalistic said:

In either case, precompressed textures should be uploaded as they are and not be affected by image_use(Normal)Compression.

Correct, that matches my interpretation of the code flow.

4 hours ago, cabalistic said:

Edit: actually, no conversion should be needed as long as the RGB textures were normalized, I guess. They just get their B channel cut off, which is then recalculated in the shader.

Right, so they is some very slight inefficiency in recalculating the B channel where it might not strictly be necessary, but this is probably negligible on modern hardware and provides the massive advantage of not needing to change the shader behaviour based on the particular normal map source format.

Link to comment
Share on other sites

On 7/29/2021 at 3:45 AM, Dragofer said:

I've:

  • Updated my SVN for assets and source code, compiled the latest source code
  • Removed the normalmap from my SVN install for one of those textures
  • Exported that normalmap as a BC5 .dds with mipmaps in GIMP
  • Placed that .dds normalmap in the corresponding dds/ folder
  • Loaded OGDA's demomap

The console tells me that TDM failed to get a bindless texture handle on that normalmap 😕 There's no normalmap effect visible ingame.

Can you try the latest SVN? Orbweaver commited a fixed BC5 loader

Please visit TDM's IndieDB site and help promote the mod:

 

http://www.indiedb.com/mods/the-dark-mod

 

(Yeah, shameless promotion... but traffic is traffic folks...)

Link to comment
Share on other sites

3 hours ago, cabalistic said:

Hm, if the format is signed, that would require a different path in the shaders. That's not a straightforward fix.

Ouch. Yeah, probably not worth it for whatever quality uptick you supposedly get.

Please visit TDM's IndieDB site and help promote the mod:

 

http://www.indiedb.com/mods/the-dark-mod

 

(Yeah, shameless promotion... but traffic is traffic folks...)

Link to comment
Share on other sites

Please visit TDM's IndieDB site and help promote the mod:

 

http://www.indiedb.com/mods/the-dark-mod

 

(Yeah, shameless promotion... but traffic is traffic folks...)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share


  • Recent Status Updates

    • STiFU

      We are taking our son on his very first holiday trip to see the sea for the first time. 🙂 Will be back in a week.
      · 0 replies
    • Gilkar

      When I was a young man my father was so ignorant I could hardly stand to have him around. As I grew older I was amazed at how much the old man had learned in such a short time.
      · 1 reply
    • jaxa

      RTX 3090 Super, RTX 3070 Ti 16 GB, RTX 2060 12 GB
      https://wccftech.com/nvidia-launching-rtx-3090-super-rtx-3070-ti-16gb-and-rtx-2060-12gb-by-january-2022/
      · 0 replies
    • duzenko

      CPU benchmark time - compiling DarkRadiant (2nd run)
      i5 8600K 6C/6T@4.4GHz DDR4 2x2133MHz 9MB cache
      Parallel builds: 1. 3:57 Parallel builds: 6 (default). 2:28 r5 1600AF 6C/12T@3.3GHz DDR4 1x2666MHz 16 MB cache, temp folder on HDD
      Parallel builds: 1. 5:05 Parallel builds: 4. 2:47 Parallel builds: 6. 2:55 Parallel builds: 12 (default). 2:57
      · 6 replies
    • nbohr1more

      Status updates are back so it is also a good time to return to contests!
      https://forums.thedarkmod.com/index.php?/topic/21095-christmas-connections-contest-2021
       
      · 0 replies
×
×
  • Create New...