smourier / DirectN

Direct interop Code for .NET Framework, .NET Core and .NET 5+ : DXGI, WIC, DirectX 9 to 12, Direct2D, Direct Write, Direct Composition, Media Foundation, WASAPI, CodecAPI, GDI, Spatial Audio, DVD, Windows Media Player, UWP DXInterop, WinUI3, etc.
MIT License
311 stars 28 forks source link

Are there any example for using geometry shader? #35

Closed vmx17 closed 1 year ago

vmx17 commented 1 year ago

Are there any good sample using geometry shader? There seems no device.CreateGeometryShader(), I made *.cso in dummy C++ project, then read it with device.Object.CreateGeometryShader() like below. There seems something bad (around second variables?) returns null in geometryShader. How can I read it as shader? Is using device.Object right way? Also I'm seeking CreateGeometryShaderWithStreamOutput usage because to make fat line (line to narrow triangles).

var path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Shaders\\GeometryShader.cso");
using (StreamReader reader = new StreamReader(new FileStream(path, FileMode.Open)))
{
    var buffer = reader.ReadToEnd();
    var sz = buffer.Length;
    var ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buffer.ToArray(), 0);   // ToArray() - costly
    _ = m_device.Object.CreateGeometryShader( ptr, (IntPtr)sz, null, out var geometryShader);  // out is null
    // and/or
    //_ = m_device.Object.CreateGeometryShaderWithStreamOutput(buffer, (IntPtr)buffer.Length, null,0,0,...);
}
smourier commented 1 year ago

Hi, indeed there are extensions methods created on the most used interfaces and methods to ease .NET programming, but I've not added them on all interfaces and all methods (it would be a huge task).

But they are always optional, it means that you can always use the .Object property of IComObject<T> to access raw method.

If you misses some, I can add them on request (or you can also propose code).

So, I've added CreateGeometryShaderextensions methods you can now call m_device.CreateGeometryShader(...) see here: https://github.com/smourier/DirectN/commit/560658c2f55deb49e730621e4e18f30868e69da2

Now, in the shader loading specific case, it's today common to compile them on the fly, like shown here https://github.com/smourier/DirectN/blob/master/DirectN/DirectN.MinimalD3D11/Main.cs#L114:

var blob = D3D11Functions.D3DCompileFromFile("shaders.hlsl", "vs_main", "vs_5_0");
shader = device.CreateVertexShader(blob);

And using D3D blobs is easier than manipulating pointers, especially with .NET.

But you can still load from a file using the D3DReadFileToBlobhttps://learn.microsoft.com/en-us/windows/win32/api/d3dcompiler/nf-d3dcompiler-d3dreadfiletoblob method:

var blob  = D3D11Functions.D3DReadFileToBlob("whatever.file");
var shader = device.CreateGeometryShader(blob);

which is a shortcut for (I've also added the function in D3D11Functions utility class)

Functions.D3DReadFileToBlob("whatever.file", out var obj).ThrowOnError();
var blob = new ComObject<ID3D10Blob>(obj);
var shader = device.CreateGeometryShader(blob);

PS: when accessing raw methods, you want to always check errors (HRESULT)

vmx17 commented 1 year ago

Hi! Thank you so much. I've made the nuget package and tried CreateGeometryShader. I've seen something output was made. Now I'm trying to see the triangle strip made in the G.shader. As you shown, I could get geometry shader as below;

var gsBlob = D3D11Functions.D3DCompileFromFile(path, "gs_main", "gs_5_0");
m_geometryShader = m_device.CreateGeometryShader(gsBlob);

and the G.shader's header is something like as;

[maxvertexcount(6)]
void gs_main(line gs_in input[2], inout TriangleStream<ps_in> output)
{
    for (uint i = 0; i < 2; i++)
    {
        float offset = input[i].thick / 2.0f;    // added thickness to the line-vertex data
        // making two triangles as strip from two input vertices using the value "offset".