hi,
until now i use typical vertexshader approach for skinning with a Constantbuffer containing the transform matrix for the bones and an the vertexbuffer containing bone index and bone weight.
Now i have implemented realtime environment probe cubemaping so i have to render my scene from many point of views and the time for skinning takes too long because it is recalculated for every side of the cubemap.
For Info i am working on Win7 an therefore use one Shadermodel 5.0 not 5.x that have more options, or is there a way to use 5.x in Win 7
My Graphic Card is Directx 12 compatible NVidia GTX 960
the member turanszkij has posted a good for me understandable compute shader. ( for Info: in his engine he uses an optimized version of it )
https://turanszkij.wordpress.com/2017/09/09/skinning-in-compute-shader/
Now my questions
is it possible to feed the compute shader with my orignial vertexbuffer or do i have to copy it in several ByteAdressBuffers as implemented in the following code ?
the same question is about the constant buffer of the matrixes
my more urgent question is how do i feed my normal pipeline with the result of the compute Shader which are 2 RWByteAddressBuffers that contain position an normal
for example i could use 2 vertexbuffer bindings
1 containing only the uv coordinates
2.containing position and normal
How do i copy from the RWByteAddressBuffers to the vertexbuffer ?
(Code from turanszkij )
Here is my shader implementation for skinning a mesh in a compute shader:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | struct Bone { float4x4 pose; }; StructuredBuffer<Bone> boneBuffer; ByteAddressBuffer vertexBuffer_POS; // T-Pose pos ByteAddressBuffer vertexBuffer_NOR; // T-Pose normal ByteAddressBuffer vertexBuffer_WEI; // bone weights ByteAddressBuffer vertexBuffer_BON; // bone indices RWByteAddressBuffer streamoutBuffer_POS; // skinned pos RWByteAddressBuffer streamoutBuffer_NOR; // skinned normal RWByteAddressBuffer streamoutBuffer_PRE; // previous frame skinned pos inline void Skinning(inout float4 pos, inout float4 nor, in float4 inBon, in float4 inWei) { float4 p = 0, pp = 0; float3 n = 0; float4x4 m; float3x3 m3; float weisum = 0; // force loop to reduce register pressure // though this way we can not interleave TEX - ALU operations [loop] for (uint i = 0; ((i < 4) && (weisum<1.0f)); ++i) { m = boneBuffer[(uint)inBon].pose; m3 = (float3x3)m; p += mul(float4(pos.xyz, 1), m)*inWei; n += mul(nor.xyz, m3)*inWei; weisum += inWei; } bool w = any(inWei); pos.xyz = w ? p.xyz : pos.xyz; nor.xyz = w ? n : nor.xyz; } [numthreads(1024, 1, 1)] void main( uint3 DTid : SV_DispatchThreadID ) { const uint fetchAddress = DTid.x * 16; // stride is 16 bytes for each vertex buffer now... uint4 pos_u = vertexBuffer_POS.Load4(fetchAddress); uint4 nor_u = vertexBuffer_NOR.Load4(fetchAddress); uint4 wei_u = vertexBuffer_WEI.Load4(fetchAddress); uint4 bon_u = vertexBuffer_BON.Load4(fetchAddress); float4 pos = asfloat(pos_u); float4 nor = asfloat(nor_u); float4 wei = asfloat(wei_u); float4 bon = asfloat(bon_u); Skinning(pos, nor, bon, wei); pos_u = asuint(pos); nor_u = asuint(nor); // copy prev frame current pos to current frame prev pos streamoutBuffer_PRE.Store4(fetchAddress, streamoutBuffer_POS.Load4(fetchAddress)); // write out skinned props: streamoutBuffer_POS.Store4(fetchAddress, pos_u); streamoutBuffer_NOR.Store4(fetchAddress, nor_u); } |