0
\$\begingroup\$

I am using SharpDX, a C# wrapper over DirectX 11 to render terrain. While I am able to render terrain correctly, I noticed that moving around creates a lot of visual noise and makes the texture of the ground very grainy. I have attached a picture of how the texture looks on the terrain. (Make sure to make full screen for clarity)

The terrain looks very grainy

Here is the dirt texture I am using: dirt texture

Here is the dirt texture normal map: dirt texture normal

I thought I set up the mip maps appropriately in this code (note that filename is just the path to the terrain bitmap I showed above):

public bool Initialize(SharpDX.Direct3D11.Device device, string fileName)
{
  try
  {
    using (var texture = LoadFromFile(device, new SharpDX.WIC.ImagingFactory(), fileName))
    {
      ShaderResourceViewDescription srvDesc = new ShaderResourceViewDescription()
      {
        Format = texture.Description.Format,
        Dimension = SharpDX.Direct3D.ShaderResourceViewDimension.Texture2D,
      };
      srvDesc.Texture2D.MostDetailedMip = 0;
      srvDesc.Texture2D.MipLevels = -1;

      TextureResource = new ShaderResourceView(device, texture, srvDesc);
      device.ImmediateContext.GenerateMips(TextureResource);
    }
    // TextureResource = ShaderResourceView.FromFile(device, fileName);
    return true;
  }
  catch
  {
    return false;
  }
}

public Texture2D LoadFromFile(SharpDX.Direct3D11.Device device, ImagingFactory factory, string fileName)
{
  using (var bs = LoadBitmap(factory, fileName))
    return CreateTexture2DFromBitmapSource(device, bs);
}

public BitmapSource LoadBitmap(ImagingFactory factory, string filename)
{
  var bitmapDecoder = new SharpDX.WIC.BitmapDecoder(
      factory,
      filename,
      SharpDX.WIC.DecodeOptions.CacheOnDemand
      );

  var result = new SharpDX.WIC.FormatConverter(factory);

  result.Initialize(
      bitmapDecoder.GetFrame(0),
      SharpDX.WIC.PixelFormat.Format32bppPRGBA,
      SharpDX.WIC.BitmapDitherType.None,
      null,
      0.0,
      SharpDX.WIC.BitmapPaletteType.Custom);

  return result;
}

 public Texture2D CreateTexture2DFromBitmapSource(SharpDX.Direct3D11.Device device, BitmapSource bitmapSource)
{
  // Allocate DataStream to receive the WIC image pixels
  int stride = bitmapSource.Size.Width * 4;
  using (var buffer = new SharpDX.DataStream(bitmapSource.Size.Height * stride, true, true))
  {
    // Copy the content of the WIC to the buffer
    bitmapSource.CopyPixels(stride, buffer);
    return new SharpDX.Direct3D11.Texture2D(device, new SharpDX.Direct3D11.Texture2DDescription()
    {
      Width = bitmapSource.Size.Width,
      Height = bitmapSource.Size.Height,
      ArraySize = 1,
      BindFlags = SharpDX.Direct3D11.BindFlags.ShaderResource | BindFlags.RenderTarget,
      Usage = SharpDX.Direct3D11.ResourceUsage.Default,
      CpuAccessFlags = SharpDX.Direct3D11.CpuAccessFlags.None,
      Format = SharpDX.DXGI.Format.R8G8B8A8_UNorm,
      MipLevels = 1,
      OptionFlags = ResourceOptionFlags.GenerateMipMaps, // ResourceOptionFlags.GenerateMipMap
      SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0),
    }, new SharpDX.DataRectangle(buffer.DataPointer, stride));
  }
}

Here is my samplerstate code:

SamplerStateDescription samplerDesc = new SamplerStateDescription()
            {
                Filter = Filter.MinMagMipLinear,
                AddressU = TextureAddressMode.Clamp,
                AddressV = TextureAddressMode.Clamp,
                AddressW = TextureAddressMode.Clamp,
                MipLodBias = 0,
                MaximumAnisotropy = 1,
                ComparisonFunction = Comparison.Always,
                BorderColor = new Color4(0, 0, 0, 0),  // Black Border.
                MinimumLod = 0,
                MaximumLod = float.MaxValue
            };
            SamplerState = new SamplerState(device, samplerDesc);

Is there anything wrong here?

\$\endgroup\$
5
  • 1
    \$\begingroup\$ Hi. Have you set your sampling? Trilinear it ansiotropic filtering needs to be set on your sampler in your shader \$\endgroup\$
    – ErnieDingo
    May 23, 2018 at 2:44
  • \$\begingroup\$ What made you choose to use just one mip level? \$\endgroup\$
    – DMGregory
    May 23, 2018 at 12:43
  • \$\begingroup\$ @ErnieDingo i have added the sampler state code in the question, I believe I am using anisotropic filtering? \$\endgroup\$
    – adrotter
    May 23, 2018 at 20:35
  • \$\begingroup\$ @DMGregory I actually did not write the code, I am adopting code from somebody else. I have tried multiple values for MipLevels, but I get parameter is incorrect exception with any value except 1. \$\endgroup\$
    – adrotter
    May 23, 2018 at 20:37
  • \$\begingroup\$ Ok, I see your issue in your Texture Load, the Texture2D object is setting your mip level to 1.I believe this should be set to 0 to allow for maximum number of mip maps. You also have to call generate mipmaps call, but I will connfirm that. I will add my code as an answer for the correct loading of the texture. \$\endgroup\$
    – ErnieDingo
    May 23, 2018 at 21:38

1 Answer 1

0
\$\begingroup\$

This function will load in your texture in, but you need to set your Mipmap level on your texture description to 0. Sample description I use is:

              case TextureDescriptions.MIPMAPPED:
                desc.ArraySize = 1;
                desc.Usage = D3D11.ResourceUsage.Default;
                desc.CpuAccessFlags = D3D11.CpuAccessFlags.None;
                desc.Format = DXGI.Format.R8G8B8A8_UNorm;
                desc.MipLevels = 0;
                desc.OptionFlags = D3D11.ResourceOptionFlags.GenerateMipMaps;
                desc.SampleDescription.Count = 1;
                desc.SampleDescription.Quality = 0;
                desc.BindFlags = D3D11.BindFlags.RenderTarget | D3D11.BindFlags.ShaderResource;
                break;

Use this function to load your buitmap into a texture2D.

    public static D3D11.Texture2D1 CreateTex2DFromBitmap(SharpDX.WIC.BitmapSource bsource, D3D11.Device3 a_device, D3D11.DeviceContext3 a_context, D3D11.Texture2DDescription1 a_desc)
    {
        D3D11.Texture2D1 t2d = null;

        try
        {
            int stride = bsource.Size.Width * 4;
            var buffer = new DataStream(bsource.Size.Height * stride, true, true);

            if (a_desc.MipLevels != 0)
            {
                // if we arent doing mip maps, then load the resource directly
                DataRectangle rect = new DataRectangle(buffer.DataPointer, stride);
                bsource.CopyPixels(stride, buffer);
                t2d = new D3D11.Texture2D1(a_device, a_desc, rect); /// this creates a texture and populates it, we need to create a blank one then populate it.                
            }
            else
            {
                t2d = new D3D11.Texture2D1(a_device, a_desc); /// this creates a texture and populates it, we need to create a blank one then populate it.
                bsource.CopyPixels(stride, buffer);
                DataBox box = new DataBox(buffer.DataPointer, stride, 1);

                a_context.UpdateSubresource(box, t2d, D3D11.Resource.CalculateSubResourceIndex(0, 0, CountMips(bsource.Size.Width, bsource.Size.Height)));
            }
            buffer.Dispose();


        }
        catch (Exception ex)
        {
            ErrorHandler.DoErrorHandling(ex, ErrorHandler.GetCurrentMethod(ex), Environment.StackTrace);

        }
        return t2d;
    }

then finally, to create the mip map levels.

                    D3D11.ShaderResourceViewDescription1 srvDesc = new D3D11.ShaderResourceViewDescription1()
                {
                    Format = m_texture2D.Description.Format,
                    Dimension = SharpDX.Direct3D.ShaderResourceViewDimension.Texture2D
                };
                srvDesc.Texture2D.MostDetailedMip = 0;
                srvDesc.Texture2D.MipLevels = -1;

                srv = new D3D11.ShaderResourceView1(a_device, m_texture2D, srvDesc);
                a_context.GenerateMips(srv);
\$\endgroup\$
6
  • \$\begingroup\$ Thanks for the reply, still trying your method, can you also put the CountMips function in your code too? Thank you \$\endgroup\$
    – adrotter
    May 23, 2018 at 23:34
  • \$\begingroup\$ Also, do I have to use Device3 and Texture2D1? I tried with just Device and Texture2D but I get the same error as before, parameter is incorrect \$\endgroup\$
    – adrotter
    May 23, 2018 at 23:59
  • \$\begingroup\$ So I just got the log base 2 of the square of the area of the texture to get the mipcount, and I changed my device to Device3 and everything worked. Thank you! \$\endgroup\$
    – adrotter
    May 24, 2018 at 0:04
  • \$\begingroup\$ Also, device3 is not necessary, neither is texture2d1 or texture2ddescription1, i was getting parameter is incorrect because I was not setting the width and height, using your code \$\endgroup\$
    – adrotter
    May 24, 2018 at 0:20
  • \$\begingroup\$ Hi, the count mips was just a function that continually divided the dimensions in 2 and counted the number till I believe it reached a texture size of 32 or 64 pixel. The texture2d1 was just the updated version of texture2d, and is supported in later versions of dx 11. glad you got it working! \$\endgroup\$
    – ErnieDingo
    May 24, 2018 at 1:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .