DDS Textures becoms Darker/Redder when converted to TextureModel {WPF/SharpDX.Core/Net8}
Hi, sorry to bother you again but i have this problem when loading a dds file to texture model it becoms very dark or redder as i will show below.
this image was compressed as BC7_srgp with photoshop's intel texture works plugin and displayed as a plane diffuse material
the same image convertet to ImageSource using Pfim and displayed in image control
also this was compressed as BC4_linear_grayscale
the converted ImageSource
but BC7_linear doesn't seem to have this effect
i haven't tried any outher compression.
I load the dds either from a byte array
public static TextureModel ToTextureModel(this byte[] data)
{
return new TextureModel(new MemoryStream(data), true);
}
or from the disk
else if (!string.IsNullOrEmpty(ImagePath) && File.Exists(ImagePath))
{
return new TextureModel(ImagePath);
}
either way i get the same effect
and thats how i disply the texture on a plane with diffuse material
public void CreateView(TextureModel texture)
{
var b2 = new MeshBuilder();
b2.AddBox(
new Vector3((float)(XFactor / 2), (float)(YFactor / 2), 0),
1 * XFactor,
1 * YFactor,
0,
BoxFaces.PositiveZ
);
this.Plane = b2.ToMeshGeometry3D();
this.PlaneMaterial = new HelixToolkit.Wpf.SharpDX.DiffuseMaterial()
{
DiffuseMap = texture
};
}
thank you !
I can say that I had similar issues with some DDS files, where Luminance-type DDS files (I think that's similar to your BC4_linear_grayscale) which should have the luminance in the alpha channel ended up having it in the red channel. I'm not sure if it's an ambiguity of the DDS format, or the parser not interpreting all header fields properly (especially the R/G/B/A bit mask fields), but in any case the culprit is probably in the code from SharpDX's DDS utilities, which HelixToolkit just uses for DDS reading. I ended up changing the shader to user a different channel, but you may be easier off if you can get your exporter to save the DDS in a compatible format...
That's looks about right, maybe it's sharpdx. But modifying the shader is not in my capabilities and I can't change the Dds format since they are needed like this somewhere else, I could do a work around so that instead of loading the Dds to texture model I could convert it to color4[] first, then use it for the texture model but this would increase the time needed for rendering the image and my conversion creates a memory overhead {from 800mb to 2GB in 15-30s}
public static TextureModel DDsToTextureModel(string filepath)
{
using (var image = Pfimage.FromFile(filepath))
{
if (image.Compressed)
image.Decompress();
var carray = ConvertIImageToColor4Array(image);
return new TextureModel(carray, image.Width, image.Height);
}
}
public static Color4[] ConvertIImageToColor4Array(IImage image)
{
byte[] imageData = image.Data;
int width = image.Width;
int height = image.Height;
// Number of pixels
int pixelCount = width * height;
Color4[] colors = new Color4[pixelCount];
for (int i = 0; i < pixelCount; i++)
{
// Calculate pixel byte offset in imageData
int row = i / width;
int col = i % width;
int offset = row * image.Stride + col * (image.BitsPerPixel / 8);
// Extract Color4 based on image format
colors[i] = ExtractColorFromPixel(imageData, offset, image.Format);
}
return colors;
}
private static Color4 ExtractColorFromPixel(byte[] imageData, int offset, ImageFormat format)
{
Color4 color = new Color4();
switch (format)
{
case ImageFormat.Rgb8:
// Assuming it might be grayscale where R=G=B with 8 bits.
byte gray = imageData[offset];
color.Red = color.Green = color.Blue = gray / 255f;
color.Alpha = 1f;
break;
case ImageFormat.R5g5b5:
// Assuming data is little-endian; adjust if big-endian.
ushort pixelValue = BitConverter.ToUInt16(imageData, offset);
color.Red = ((pixelValue >> 10) & 0x1F) / 31f;
color.Green = ((pixelValue >> 5) & 0x1F) / 31f;
color.Blue = (pixelValue & 0x1F) / 31f;
color.Alpha = 1f;
break;
case ImageFormat.R5g6b5:
pixelValue = BitConverter.ToUInt16(imageData, offset);
color.Red = ((pixelValue >> 11) & 0x1F) / 31f;
color.Green = ((pixelValue >> 5) & 0x3F) / 63f;
color.Blue = (pixelValue & 0x1F) / 31f;
color.Alpha = 1f;
break;
case ImageFormat.R5g5b5a1:
pixelValue = BitConverter.ToUInt16(imageData, offset);
color.Red = ((pixelValue >> 11) & 0x1F) / 31f;
color.Green = ((pixelValue >> 6) & 0x1F) / 31f;
color.Blue = ((pixelValue >> 1) & 0x1F) / 31f;
color.Alpha = (pixelValue & 0x1) != 0 ? 1f : 0f;
break;
case ImageFormat.Rgba16:
// 4 bits for each channel
ushort rgbaValue = BitConverter.ToUInt16(imageData, offset);
color.Red = ((rgbaValue >> 12) & 0xF) / 15f;
color.Green = ((rgbaValue >> 8) & 0xF) / 15f;
color.Blue = ((rgbaValue >> 4) & 0xF) / 15f;
color.Alpha = (rgbaValue & 0xF) / 15f;
break;
case ImageFormat.Rgb24:
color.Red = imageData[offset + 2] / 255f;
color.Green = imageData[offset + 1] / 255f;
color.Blue = imageData[offset] / 255f;
color.Alpha = 1f;
break;
case ImageFormat.Rgba32:
color.Red = imageData[offset + 2] / 255f;
color.Green = imageData[offset + 1] / 255f;
color.Blue = imageData[offset + 0] / 255f;
color.Alpha = imageData[offset + 3] / 255f;
break;
default:
throw new ArgumentOutOfRangeException(nameof(format), "Unsupported image format.");
}
return color;
}
If you are interested in debugging the issue, the source is in https://github.com/helix-toolkit/helix-toolkit/blob/develop/Source/HelixToolkit.SharpDX.Shared/SharpDX.Toolkit/Graphics/DDSHelper.cs