I found struct NvHair_PixelShaderInput, which would be the output of a geometry shader, if one exists. In its description it says: […]input to this pixel shader (output from eariler geometry/vertex stages)[…], so this inidcates there could be already a geometry shader.
In “Dx11ApiInstance::preRender” in NvHairDx11ApiInstance.cpp I found context->GSSetShaderResources and a call to context->SOSetTargetswith “positionSoBuffer” which I want as result.
positionSoBuffer = nextTessellatedMasterStrandBuffer();
seems to set this butter to produce then the tesselated positions through the SO, right? So when I use staging with the “positionSoBuffer” from the “preRender”, do I get the full hair positions? So does the “preRender” function do already what I want?
Or are these only the master strands, which later then again get tesselated?
How do I get the fully tesselated vertices ?
Is there an indication where the strands start/end ?
EDIT:
I found \src\Nv\HairWorks\Internal\Shader\Geometry\NvHairSplineGeometry.hlsl
which seems to be the Geometry Shader I was searching for, its producing vertex, tangent normal outputs.
And I found NvHairInterpolateGeometry.hlsl, which outputs NvHair_PixelShaderInput: this seems to be for the full hair rendering.
I found numVertsPerSegments and numMasterSegments in Dx11ApiInstance::_prepareTesselateConstantBuffer,
and I obtained these from the “HairWorks::Asset” class:
auto numGuideHairs = asset->m_rootIndices.getSize();
auto numVertices = asset->m_masterStrandControlVertices.getSize();
auto numGuideHairsControlVertexOffsets = asset->m_masterStrandControlVertexOffsets.getSize();
so it seems that gives me the topology of all hair strands
It turned out that: numTessellatedPoints = strandPointCounts * numGuideHairs
Thank you !
My System: HairWorks 1.3
DirectX 11
Windows10PRO 64bit (21H1)
Turned out, that Dx11ApiInstance::preRender gave me the guide hairs only; I was able to obtain all the vertex and normal data through Strean Out (SO) and passed it to my pathtracer module.
So next I need to also export all the final hairs with a derivative of NvHairInterpolateGeometry.hlsl struct DSOut seems to give me all the required data.
nice to see what you can still get out of this tool and thank you for sharing!
It is a legacy SDK without any support, so you might be on your own on this one. I just wonder where you found version 1.3 of the SDK? Even I am not able to find that anymore on our servers…
thank you for your answer.
I downloaded it in 2017 and (the README.md file has timestamp June 7th 2017, so
it seems that I unzipped it on that day).
At that time I had this version information:
NVIDIA HairWorks v1.3.1 Jul 24 2017
NVIDIA HairWorks v1.3 Feb 27 2017
NVIDIA HairWorks v1.2.1 Nov 29 2016
NVIDIA HairWorks v1.2 June 17 2016
NVIDIA HairWorks v1.1.1 Dec 06 2015
From my notes I had a problem with v1.4 beta (GitHub):
“FurViewer cannot read its previous projects/APX files (unverified)”
So I did never upgrade to 1.4
Were there later versions?
I cannot find any repo of HairWorks on Github anymore in https://github.com/NVIDIAGameWorks,
although Flex, Flow and WaveWorks are still there.
Is there any newer replacement API for HairWorks from NVIDIA?
No, there were no newer versions anymore, Hairworks was discontinued.
There is also no dedicated replacement since there are now all kinds of other third-party tools available for hair and fur. For example Houdini Groom or MetaHuman with UnrealEngine.
The closest you get in terms of NVIDIA SDKs is still Omniverse and PhysX. But I don’t think that will allow you to use SO render targets.
So I will continue. Maybe someone else here on the forums still is using this SDK.
However, I think I already got, what I needed to know.
From the numFaces * 64 (batch instance size) = instances I get number of final tesellated hairs.
#define NHAIRS_PER_PATCH 64 // in NvHairInternalShaderCommon.h
const unsigned int numFaces = (unsigned int)apiInst->m_numFaces;
auto strandPointCounts = inst->getStrandPointCount();
const unsigned int numSegmentVertex_ids = strandPointCounts - 1; // = "numSegments" in HS
context->Draw(apiInst->m_numFaces, 0); // HS, DS, GS => SO
On the example I used (the 2nd post in this thread) here:
strandPointCounts=9 => numSegmentVertex_ids=8
330 faces
168960 primitives generated (found through D3D11_QUERY_DATA_SO_STATISTICS.PrimitivesStorageNeeded)
168960 = 330 * 8 * 64
330 faces * (8 vertices per hair instance) * (64 batch instance size)
330 faces * 64 (batch instance size) = 21120 instances => 21120 final hairs
each final hair has up to 8 vertices