Repository: godotengine/godot (language: cpp)

Issue:
Signed BC6 Compresses values less than -1.0 to -65504.0
### Tested versions

- Reproducible in 4.4.stable
- I believe it existed since the BC6 signed mode added in (#96377)

### System information

Godot v4.4.stable - Ubuntu 24.04.2 LTS 24.04 on X11 - X11 display driver, Multi-window, 2 monitors - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 2070 SUPER (nvidia; 550.120) - AMD Ryzen 7 3700X 8-Core Processor (16 threads)

### Issue description

When compressing a texture that contain a negative rgb value that is more than -1 it gets clamp to the maximum negative value allowed by half floats. 

![Image](https://github.com/user-attachments/assets/987f73d1-38ea-47b9-833e-0c5a79759642)

### Steps to reproduce

1. Compress a texture that has negative values larger than -1.
2. Import the texture using the VRAM Compressed mode
3. Since normally -1.0 and -65504.0 would display the same apply a shader to the texture so that -1.0 would render as -0.5. 

### Minimal reproduction project (MRP)

[signed-bc6h.zip](https://github.com/user-attachments/files/19521379/signed-bc6h.zip)


Discussion / hints:
cc @BlueCube3310 

Fix patch:
diff --git a/modules/betsy/bc6h.glsl b/modules/betsy/bc6h.glsl
index 73540876aa80..d00bbafbd222 100644
--- a/modules/betsy/bc6h.glsl
+++ b/modules/betsy/bc6h.glsl
@@ -89,12 +89,36 @@ float CalcMSLE(float3 a, float3 b) {
 
 	return result;
 }
+
+// Adapt the log function to make sense when a < 0
+float3 customLog2(float3 a) {
+	return float3(
+			a.x >= 0 ? log2(a.x + 1.0f) : -log2(-a.x + 1.0f),
+			a.y >= 0 ? log2(a.y + 1.0f) : -log2(-a.y + 1.0f),
+			a.z >= 0 ? log2(a.z + 1.0f) : -log2(-a.z + 1.0f));
+}
+
+// Inverse of customLog2()
+float3 customExp2(float3 a) {
+	return float3(
+			a.x >= 0 ? exp2(a.x) - 1.0f : -(exp2(-a.x) - 1.0f),
+			a.y >= 0 ? exp2(a.y) - 1.0f : -(exp2(-a.y) - 1.0f),
+			a.z >= 0 ? exp2(a.z) - 1.0f : -(exp2(-a.z) - 1.0f));
+}
 #else
 float CalcMSLE(float3 a, float3 b) {
 	float3 err = log2((b + 1.0f) / (a + 1.0f));
 	err = err * err;
 	return err.x + err.y + err.z;
 }
+
+float3 customLog2(float3 a) {
+	return log2(a + 1.0f);
+}
+
+float3 customExp2(float3 a) {
+	return exp2(a) - 1.0f;
+}
 #endif
 
 uint PatternFixupID(uint i) {
@@ -272,15 +296,15 @@ void EncodeP1(inout uint4 block, inout float blockMSLE, float3 texels[16]) {
 		refinedBlockMax = max(refinedBlockMax, texels[i] == blockMax ? refinedBlockMax : texels[i]);
 	}
 
-	float3 logBlockMax = log2(blockMax + 1.0f);
-	float3 logBlockMin = log2(blockMin + 1.0f);
-	float3 logRefinedBlockMax = log2(refinedBlockMax + 1.0f);
-	float3 logRefinedBlockMin = log2(refinedBlockMin + 1.0f);
+	float3 logBlockMax = customLog2(blockMax);
+	float3 logBlockMin = customLog2(blockMin);
+	float3 logRefinedBlockMax = customLog2(refinedBlockMax);
+	float3 logRefinedBlockMin = customLog2(refinedBlockMin);
 	float3 logBlockMaxExt = (logBlockMax - logBlockMin) * (1.0f / 32.0f);
 	logBlockMin += min(logRefinedBlockMin - logBlockMin, logBlockMaxExt);
 	logBlockMax -= min(logBlockMax - logRefinedBlockMax, logBlockMaxExt);
-	blockMin = exp2(logBlockMin) - 1.0f;
-	blockMax = exp2(logBlockMax) - 1.0f;
+	blockMin = customExp2(logBlockMin);
+	blockMax = customExp2(logBlockMax);
 
 	float3 blockDir = blockMax - blockMin;
 	blockDir = blockDir / (blockDir.x + blockDir.y + blockDir.z);


Test patch: