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\$
  • 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 '18 at 2:44
  • \$\begingroup\$ What made you choose to use just one mip level? \$\endgroup\$ – DMGregory May 23 '18 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 '18 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 '18 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 '18 at 21:38
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\$
  • \$\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 '18 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 '18 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 '18 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 '18 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 '18 at 1:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.