Jump to content

  • Log In with Google      Sign In   
  • Create Account

MJP

Member Since 29 Mar 2007
Offline Last Active Today, 07:47 PM

#5171964 Cubemap texture as depth buffer (shadowmapping)

Posted by MJP on 06 August 2014 - 05:04 PM

Argh! I had a whole bunch of explanatory text following the code, but it looks like the editor ate it. Sorry about that. sad.png

 

The typeless format is definitely the trickiest part of this. Basically D3D will make the distinction between depth and color formats, so if you want to alias a texture using both types then you need to use a TYPELESS format when creating the underlying texture resource. Then you use the "D" format when creating  the depth stencil view, and the "R" format when creating the shader resource view. This way the depth stencil view interprets the data as a depth buffer, and the shader resource view interprets it as a color texture.

 

The code I posted doesn't actually handle cubemaps, it just handles texture arrays. However cubemaps are really just a special case of texture arrays with an array size of 6. You'll definitely want to continue using D3D11_RESOURCE_MISC_TEXTURECUBE flag if you're creating a cubemap. To render to each face individually, you'll want to do something similar to what I'm doing in the code I pasted where you create 6 separate depth stencil views. When you create the DSV, you can essentially bind it to a single slice of a texture array. So you can use that to effectively target a single face. Then just bind the appropriate DSV to your context when rendering. Also note that if you're using a cubemap, you'll want to use D3D11_SRV_DIMENSION_TEXTURECUBE (along with the corresponding TextureCube member of the SRV desc structure) instead of Texture2D or Texture2DArray.

 

The read-only DSV is just something I've used in a few special cases, you probably won't need it. Normally D3D doesn't let you bind a depth buffer to the context if you also have it simultaneously bound as a shader resource view. This is to prevent read-write ordering conflicts. However if you create a read-only DSV, then you can have it bound as both a depth buffer and an SRV simultaneously since it's read-only in both cases. However you of course can only do depth testing like this, and can't enable depth writes.




#5171775 Creating readable mipmaps in D3D11

Posted by MJP on 05 August 2014 - 08:22 PM

You need to use the RowPitch member of D3D11_MAPPED_SUBRESOURCE when reading your mapped staging texture. Staging textures can have their width padded in order to accommodate hardware requirements, so you need to take it into account in your code. Typically what you'll do is read the data one row at a time in a loop. For each iteration you'll memcpy a single row of unpadded texture data, and then increment your source pointer by the pitch size.




#5171771 Cubemap texture as depth buffer (shadowmapping)

Posted by MJP on 05 August 2014 - 08:11 PM

This is actually a little tricky to get right in D3D11, so I don't blame you for having trouble. Here's some code from my sample framework should help you:

 

void DepthStencilBuffer::Initialize(ID3D11Device* device,
                                    uint32 width,
                                    uint32 height,
                                    DXGI_FORMAT format,
                                    bool32 useAsShaderResource,
                                    uint32 multiSamples,
                                    uint32 msQuality,
                                    uint32 arraySize)
{
    uint32 bindFlags = D3D11_BIND_DEPTH_STENCIL;
    if (useAsShaderResource)
        bindFlags |= D3D11_BIND_SHADER_RESOURCE;
 
    DXGI_FORMAT dsTexFormat;
    if (!useAsShaderResource)
        dsTexFormat = format;
    else if (format == DXGI_FORMAT_D16_UNORM)
        dsTexFormat = DXGI_FORMAT_R16_TYPELESS;
    else if(format == DXGI_FORMAT_D24_UNORM_S8_UINT)
        dsTexFormat = DXGI_FORMAT_R24G8_TYPELESS;
    else
        dsTexFormat = DXGI_FORMAT_R32_TYPELESS;
 
    D3D11_TEXTURE2D_DESC desc;
    desc.Width = width;
    desc.Height = height;
    desc.ArraySize = arraySize;
    desc.BindFlags = bindFlags;
    desc.CPUAccessFlags = 0;
    desc.Format = dsTexFormat;
    desc.MipLevels = 1;
    desc.MiscFlags = 0;
    desc.SampleDesc.Count = multiSamples;
    desc.SampleDesc.Quality = msQuality;
    desc.Usage = D3D11_USAGE_DEFAULT;
    DXCall(device->CreateTexture2D(&desc, nullptr, &Texture));
 
    ArraySlices.clear();
    for (uint32 i = 0; i < arraySize; ++i)
    {
        D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
        ID3D11DepthStencilViewPtr dsView;
        dsvDesc.Format = format;
 
        if (arraySize == 1)
        {
            dsvDesc.ViewDimension = multiSamples > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D;
            dsvDesc.Texture2D.MipSlice = 0;
        }
        else
        {
            if(multiSamples > 1)
            {
                dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY;
                dsvDesc.Texture2DMSArray.ArraySize = 1;
                dsvDesc.Texture2DMSArray.FirstArraySlice = i;
            }
            else
            {
                dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
                dsvDesc.Texture2DArray.ArraySize = 1;
                dsvDesc.Texture2DArray.FirstArraySlice = i;
                dsvDesc.Texture2DArray.MipSlice = 0;
            }
        }
 
        dsvDesc.Flags = 0;
        DXCall(device->CreateDepthStencilView(Texture, &dsvDesc, &dsView));
        ArraySlices.push_back(dsView);
 
        if (i == 0)
        {
            // Also create a read-only DSV
            dsvDesc.Flags = D3D11_DSV_READ_ONLY_DEPTH;
            if (format == DXGI_FORMAT_D24_UNORM_S8_UINT || format == DXGI_FORMAT_D32_FLOAT_S8X24_UINT)
                dsvDesc.Flags |= D3D11_DSV_READ_ONLY_STENCIL;
            DXCall(device->CreateDepthStencilView(Texture, &dsvDesc, &ReadOnlyDSView));
            dsvDesc.Flags = 0;
        }
    }
 
    DSView = ArraySlices[0];
 
    if (useAsShaderResource)
    {
        DXGI_FORMAT dsSRVFormat;
        if (format == DXGI_FORMAT_D16_UNORM)
            dsSRVFormat = DXGI_FORMAT_R16_UNORM;
        else if(format == DXGI_FORMAT_D24_UNORM_S8_UINT)
            dsSRVFormat = DXGI_FORMAT_R24_UNORM_X8_TYPELESS ;
        else
            dsSRVFormat = DXGI_FORMAT_R32_FLOAT;
 
        D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
        srvDesc.Format = dsSRVFormat;
 
        if (arraySize == 1)
        {
            srvDesc.ViewDimension = multiSamples > 1 ? D3D11_SRV_DIMENSION_TEXTURE2DMS : D3D11_SRV_DIMENSION_TEXTURE2D;
            srvDesc.Texture2D.MipLevels = 1;
            srvDesc.Texture2D.MostDetailedMip = 0;
        }
        else
        {
            srvDesc.ViewDimension = multiSamples > 1 ? D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY : D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
            srvDesc.Texture2DArray.ArraySize = arraySize;
            srvDesc.Texture2DArray.FirstArraySlice = 0;
            srvDesc.Texture2DArray.MipLevels = 1;
            srvDesc.Texture2DArray.MostDetailedMip = 0;
        }
 
        DXCall(device->CreateShaderResourceView(Texture, &srvDesc, &SRView));
    }
    else
        SRView = nullptr;
 
    Width = width;
    Height = height;
    MultiSamples = multiSamples;
    Format = format;
    ArraySize = arraySize;
}



#5171760 High cpu usage

Posted by MJP on 05 August 2014 - 07:24 PM

Your  app is set up to render as quickly as it can, with no sleeping. For such a simple scene, you're probably updating and rendering 100's of frames per second. This will naturally result in your main thread saturating a core of your CPU. There's 3 easy things you can do to fix this:

 

  1. Use VSYNC. This is done by passing "1" as the first parameter of IDXGISwapChain::Present. Doing this will cause the CPU and GPU to wait for the next sync interval, which will essentially prevent your app from running faster than the refresh rate of your display (typically 60Hz). If you're not doing very much in a frame, then your thread will spend a lot of time just waiting which will keep your CPU usage low. However if you start do a lot of CPU work for each frame, then you will see your CPU usage increase.
  2. Do lots of work on the GPU. If your GPU is take a long time per frame to render, the CPU will have to wait for it which will give it some idle time. 
  3. Call Sleep(). For games this is usually not a good idea, since you want your game to achieve as high a framerate as possible. However if you're not making a game and framerate is not a concern, then it's the best way to guarantee that your thread doesn't saturate a CPU core.



#5170453 Orthographic-like billboards in perspective projection?

Posted by MJP on 30 July 2014 - 04:30 PM

You can certainly still use an orthographic projection and achieve your goal of using instancing + shaders. You just need a custom vertex shader that does the following:

 

1. Take the 3D center point of the billboard that comes from your per-instance data, and project it into 2D space

2. Offset the 2D center point by the current vertex position

3. Transform the resulting vertex position by your orthographic projection




#5170177 MSAA in Deferred shading

Posted by MJP on 29 July 2014 - 03:23 PM

You may want to take a look at this presentation, although it's a little older and some of the advice is out-of-date for the most recent GPU's. This one also talks about MSAA + deferred rendering. This presentation and sample code demonstrates a more "modern" way of handing deferred rendering and MSAA using a compute shader, so you should definitely have a look at that as well.




#5170176 MSAA custom sampling pattern

Posted by MJP on 29 July 2014 - 03:13 PM

There's no way to specify custom sample patterns in D3D11. There's no public documentation yet for D3D12, and the conference presentations didn't mention any such functionality.




#5168947 SamplerState in code or HLSL?

Posted by MJP on 24 July 2014 - 01:03 PM

At the grazing angles the undersampling is going to be very extreme, and even 16 samples won't be enough. So you'll get either aliasing artifacts, or blurring due to the hardware using a lower-resolution mip level. You'll also get issues from the hardware using various approximations and "optimizations". Usually you can turn these off in the driver control panel. Typically they'll have some sort of "quality" slider that you can turn up to get better filtering results at the cost of additional performance.




#5168512 SamplerState in code or HLSL?

Posted by MJP on 22 July 2014 - 05:16 PM

You're calculating your pitch incorrectly. You're using a R8G8B8A8 format, so the size of each texel should be textureWidth * sizeof(uint8_t) * 4. You can also pass a value of 0 for "SrcDepthPitch", since you're not using a 3D texture.

 




#5168446 could use some help with this error

Posted by MJP on 22 July 2014 - 01:36 PM

This forum is for technical discussion regarding DirectX programming and game development, not general Windows tech support.




#5168031 [Depth buffer] From linear -> non-linear depth values

Posted by MJP on 20 July 2014 - 04:58 PM

You can also just apply your original projection matrix and then divide the result by w




#5167879 SamplerState in code or HLSL?

Posted by MJP on 19 July 2014 - 06:21 PM

1. At a base level, D3D11 only supports creating sampler states on the application side using D3D API calls. Any HLSL code you've seen for defining sampler states was using the effects framework, which is a higher-level library that sits on top of core D3D. The effects framework actually reflects the sampler data from the compiled code, and uses that reflected data to create and bind sampler states behind the scenes. I really wouldn't recommend using the effects framework (it's old and no longer updated), so you should just create and bind sampler states manually. If necessary, you can always write your own layer for reflecting data from your shader and using that to control binding of samplers and textures.

 

2. D3D supports what's called "automatic mipmap generation", and it uses the GPU to generate the lower-resolution mip levels using the highest-resolution mip (level 0) as the source data. It's generally intended for generating mips for textures that are generated by the GPU during a frame, and not so much for generating mips for static textures created at load time. However you can use it that way, if you wish. To do it you need to create your texture using D3D11_USAGE_DEFAULT as the Usage, and D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET as the BindFlags. You also need to specify D3D11_RESOURCE_MISC_GENERATE_MIPS for MiscFlags. Make sure you also specify the correct number for MipLevels, or alternately specify 0 to get the full mip chain. When you call CreateTexture2D you can pass NULL for pInitialData, and after you've created it you can use UpdateSubresource to fill the texture with data for the first mip level. Once you've done that, you can create your shader resource view call ID3D11DeviceContext::GenerateMips to fill in the rest of the mip levels.

If you don't want to write this yourself and you're loading textures from a standard image format, you can grab WICTextureLoader.h/.cpp from DirectXTex and use that to load your textures. You can also just look at the code if you want an example of how to do what I described above.




#5167687 Dx11 math and matrices

Posted by MJP on 18 July 2014 - 05:21 PM

You have to construct the projection matrix differently to accommodate the difference in coordinate spaces. I think you'll just want to write your own function for creating a DX-style projection. It should be fairly trivial: if you look at the old D3DX docs they show the math for how the matrices are constructed (you'll just have to transpose if you want column-major ordering).

 

You should be aware that the D3DX functions create a perspective matrix that essentially negates the Z coordinate. This is so that you can work in a right-handed coordinate space such that Z- is the area directly in front of the camera in view space, and then those coordinates get mapped to the positive [0, 1] space in NCD space. If this is not how you set up your view space, then you'll need to adjust things accordingly.




#5167521 Does your game company do game jams and do they have to rebuild the code base?

Posted by MJP on 17 July 2014 - 11:19 PM

We've never done a formal "game jam" at my studio. However we have a tradition for now programmer hires where we have them do anything they want as a first week project. We've had a few cool things come out of that. One of my coworkers once made a skateboarding game with Kratos.




#5166668 Irradiance Filtering with SH

Posted by MJP on 13 July 2014 - 11:56 PM

Your irradiance calculation is a convolution with a cosine kernel over an entire hemisphere, and it essentially acts a low-pass filtering. So it's not unusual to "blur away" a lot of your details. With an HDR source it's possibly to have portions that are many many times brighter than other parts of the cubemap, which allows for certain features to come through more strongly in the filtered result. You should definitely try with an HDR source and see if you get results more inline with what you expect. 






PARTNERS