-
Notifications
You must be signed in to change notification settings - Fork 862
Add support for GPU instancing of mesh particle systems #904
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
17b7a66
bfa1e14
9539d39
890cc25
7a2d6ca
0c451f7
d0d7cd6
c5c7fca
d95b98a
97e0af3
16b8491
634efec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ | |
| #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceInput.hlsl" | ||
| #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl" | ||
| #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareOpaqueTexture.hlsl" | ||
| #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ParticlesInstancing.hlsl" | ||
|
|
||
| // Pre-multiplied alpha helper | ||
| #if defined(_ALPHAPREMULTIPLY_ON) | ||
|
|
@@ -110,4 +111,72 @@ half3 SampleNormalTS(float2 uv, float3 blendUv, TEXTURE2D_PARAM(bumpMap, sampler | |
| #endif | ||
| } | ||
|
|
||
| half4 GetParticleColor(half4 color) | ||
| { | ||
| #if defined(UNITY_PARTICLE_INSTANCING_ENABLED) | ||
| #if !defined(UNITY_PARTICLE_INSTANCE_DATA_NO_COLOR) | ||
| UNITY_PARTICLE_INSTANCE_DATA data = unity_ParticleInstanceData[unity_InstanceID]; | ||
| color = lerp(half4(1.0, 1.0, 1.0, 1.0), color, unity_ParticleUseMeshColors); | ||
| color *= float4(data.color & 255, (data.color >> 8) & 255, (data.color >> 16) & 255, (data.color >> 24) & 255) * (1.0 / 255); | ||
| #endif | ||
| #endif | ||
| return color; | ||
| } | ||
|
|
||
| void GetParticleTexcoords(out float2 outputTexcoord, out float3 outputTexcoord2AndBlend, in float4 inputTexcoords, in float inputBlend) | ||
| { | ||
| #if defined(UNITY_PARTICLE_INSTANCING_ENABLED) | ||
| if (unity_ParticleUVShiftData.x != 0.0) | ||
| { | ||
| UNITY_PARTICLE_INSTANCE_DATA data = unity_ParticleInstanceData[unity_InstanceID]; | ||
|
|
||
| float numTilesX = unity_ParticleUVShiftData.y; | ||
| float2 animScale = unity_ParticleUVShiftData.zw; | ||
| #ifdef UNITY_PARTICLE_INSTANCE_DATA_NO_ANIM_FRAME | ||
| float sheetIndex = 0.0; | ||
| #else | ||
| float sheetIndex = data.animFrame; | ||
| #endif | ||
|
|
||
| float index0 = floor(sheetIndex); | ||
| float vIdx0 = floor(index0 / numTilesX); | ||
| float uIdx0 = floor(index0 - vIdx0 * numTilesX); | ||
| float2 offset0 = float2(uIdx0 * animScale.x, (1.0 - animScale.y) - vIdx0 * animScale.y); | ||
|
||
|
|
||
| outputTexcoord = inputTexcoords.xy * animScale.xy + offset0.xy; | ||
|
|
||
| #ifdef _FLIPBOOK_BLENDING | ||
| float index1 = floor(sheetIndex + 1.0); | ||
| float vIdx1 = floor(index1 / numTilesX); | ||
| float uIdx1 = floor(index1 - vIdx1 * numTilesX); | ||
| float2 offset1 = float2(uIdx1 * animScale.x, (1.0 - animScale.y) - vIdx1 * animScale.y); | ||
|
|
||
| outputTexcoord2AndBlend.xy = inputTexcoords.xy * animScale.xy + offset1.xy; | ||
| outputTexcoord2AndBlend.z = frac(sheetIndex); | ||
| #endif | ||
| } | ||
| else | ||
| #endif | ||
| { | ||
| outputTexcoord = inputTexcoords.xy; | ||
| #ifdef _FLIPBOOKBLENDING_ON | ||
| outputTexcoord2AndBlend.xy = inputTexcoords.xy; | ||
| outputTexcoord2AndBlend.z = inputBlend; | ||
| #endif | ||
| } | ||
|
|
||
| #ifndef _FLIPBOOK_BLENDING | ||
| outputTexcoord2AndBlend.xy = outputTexcoord; | ||
| outputTexcoord2AndBlend.z = 0.0; | ||
| #endif | ||
| } | ||
|
|
||
| #ifndef _FLIPBOOKBLENDING_ON | ||
| void GetParticleTexcoords(out float2 outputTexcoord, in float2 inputTexcoord) | ||
| { | ||
| float3 dummyTexcoord2AndBlend = 0.0; | ||
| GetParticleTexcoords(outputTexcoord, dummyTexcoord2AndBlend, inputTexcoord.xyxy, 0.0); | ||
| } | ||
| #endif | ||
|
|
||
| #endif // UNIVERSAL_PARTICLES_INCLUDED | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| #ifndef UNIVERSAL_PARTICLESINSTANCING_INCLUDED | ||
| #define UNIVERSAL_PARTICLESINSTANCING_INCLUDED | ||
|
|
||
| #if defined(UNITY_PROCEDURAL_INSTANCING_ENABLED) && !defined(SHADER_TARGET_SURFACE_ANALYSIS) | ||
| #define UNITY_PARTICLE_INSTANCING_ENABLED | ||
| #endif | ||
|
|
||
| #if defined(UNITY_PARTICLE_INSTANCING_ENABLED) | ||
|
|
||
| #ifndef UNITY_PARTICLE_INSTANCE_DATA | ||
| #define UNITY_PARTICLE_INSTANCE_DATA DefaultParticleInstanceData | ||
| #endif | ||
|
|
||
| struct DefaultParticleInstanceData | ||
| { | ||
| float3x4 transform; | ||
| uint color; | ||
| float animFrame; | ||
| }; | ||
|
|
||
| StructuredBuffer<UNITY_PARTICLE_INSTANCE_DATA> unity_ParticleInstanceData; | ||
| float4 unity_ParticleUVShiftData; | ||
| float unity_ParticleUseMeshColors; | ||
|
|
||
| void ParticleInstancingMatrices(out float4x4 objectToWorld, out float4x4 worldToObject) | ||
| { | ||
| UNITY_PARTICLE_INSTANCE_DATA data = unity_ParticleInstanceData[unity_InstanceID]; | ||
|
|
||
| // transform matrix | ||
| objectToWorld._11_21_31_41 = float4(data.transform._11_21_31, 0.0f); | ||
| objectToWorld._12_22_32_42 = float4(data.transform._12_22_32, 0.0f); | ||
| objectToWorld._13_23_33_43 = float4(data.transform._13_23_33, 0.0f); | ||
| objectToWorld._14_24_34_44 = float4(data.transform._14_24_34, 1.0f); | ||
|
|
||
| // inverse transform matrix | ||
| float3x3 w2oRotation; | ||
| w2oRotation[0] = objectToWorld[1].yzx * objectToWorld[2].zxy - objectToWorld[1].zxy * objectToWorld[2].yzx; | ||
|
||
| w2oRotation[1] = objectToWorld[0].zxy * objectToWorld[2].yzx - objectToWorld[0].yzx * objectToWorld[2].zxy; | ||
| w2oRotation[2] = objectToWorld[0].yzx * objectToWorld[1].zxy - objectToWorld[0].zxy * objectToWorld[1].yzx; | ||
|
|
||
| float det = dot(objectToWorld[0].xyz, w2oRotation[0]); | ||
|
|
||
| w2oRotation = transpose(w2oRotation); | ||
|
|
||
| w2oRotation *= rcp(det); | ||
|
|
||
| float3 w2oPosition = mul(w2oRotation, -objectToWorld._14_24_34); | ||
|
|
||
| worldToObject._11_21_31_41 = float4(w2oRotation._11_21_31, 0.0f); | ||
| worldToObject._12_22_32_42 = float4(w2oRotation._12_22_32, 0.0f); | ||
| worldToObject._13_23_33_43 = float4(w2oRotation._13_23_33, 0.0f); | ||
| worldToObject._14_24_34_44 = float4(w2oPosition, 1.0f); | ||
| } | ||
|
|
||
| void ParticleInstancingSetup() | ||
| { | ||
| ParticleInstancingMatrices(unity_ObjectToWorld, unity_WorldToObject); | ||
| } | ||
|
|
||
| #else | ||
|
|
||
| void ParticleInstancingSetup() {} | ||
|
|
||
| #endif | ||
|
|
||
| #endif // UNIVERSAL_PARTICLESINSTANCING_INCLUDED | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| #ifndef UNIVERSAL_PARTICLES_EDITOR_PASS_INCLUDED | ||
| #define UNIVERSAL_PARTICLES_EDITOR_PASS_INCLUDED | ||
|
|
||
| #ifdef _ALPHATEST_ON | ||
| half _Cutoff; | ||
| #endif | ||
|
|
||
| float _ObjectId; | ||
| float _PassValue; | ||
| float4 _SelectionID; | ||
|
|
||
| struct AttributesParticle | ||
| { | ||
| float4 vertex : POSITION; | ||
| half4 color : COLOR; | ||
| #if defined(_FLIPBOOKBLENDING_ON) && !defined(UNITY_PARTICLE_INSTANCING_ENABLED) | ||
| float4 texcoords : TEXCOORD0; | ||
| float texcoordBlend : TEXCOORD1; | ||
| #else | ||
| float2 texcoords : TEXCOORD0; | ||
| #endif | ||
| UNITY_VERTEX_INPUT_INSTANCE_ID | ||
| }; | ||
|
|
||
| struct VaryingsParticle | ||
| { | ||
| float4 clipPos : SV_POSITION; | ||
| float2 texcoord : TEXCOORD0; | ||
| #ifdef _FLIPBOOKBLENDING_ON | ||
| float3 texcoord2AndBlend : TEXCOORD1; | ||
| #endif | ||
| half4 color : TEXCOORD2; | ||
| UNITY_VERTEX_INPUT_INSTANCE_ID | ||
| UNITY_VERTEX_OUTPUT_STEREO | ||
| }; | ||
|
|
||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // Vertex and Fragment functions // | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| VaryingsParticle vertParticleEditor(AttributesParticle input) | ||
| { | ||
| VaryingsParticle output = (VaryingsParticle)0; | ||
|
|
||
| UNITY_SETUP_INSTANCE_ID(input); | ||
| UNITY_TRANSFER_INSTANCE_ID(input, output); | ||
| UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); | ||
|
|
||
| VertexPositionInputs vertexInput = GetVertexPositionInputs(input.vertex.xyz); | ||
|
|
||
| output.clipPos = vertexInput.positionCS; | ||
| output.color = GetParticleColor(input.color); | ||
|
|
||
| #if defined(_FLIPBOOKBLENDING_ON) && !defined(UNITY_PARTICLE_INSTANCING_ENABLED) | ||
| GetParticleTexcoords(output.texcoord, output.texcoord2AndBlend, input.texcoords, input.texcoordBlend); | ||
| #else | ||
| GetParticleTexcoords(output.texcoord, input.texcoords.xy); | ||
| #endif | ||
|
|
||
| return output; | ||
| } | ||
|
|
||
| void fragParticleSceneClip(VaryingsParticle input) | ||
| { | ||
| UNITY_SETUP_INSTANCE_ID(input); | ||
| UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); | ||
|
|
||
| float2 uv = input.texcoord; | ||
| float3 blendUv = float3(0, 0, 0); | ||
| #if defined(_FLIPBOOKBLENDING_ON) | ||
| blendUv = input.texcoord2AndBlend; | ||
| #endif | ||
|
|
||
| float4 projectedPosition = float4(0, 0, 0, 0); | ||
|
|
||
| half4 albedo = SampleAlbedo(uv, blendUv, _BaseColor, input.color, projectedPosition, TEXTURE2D_ARGS(_BaseMap, sampler_BaseMap)); | ||
| half alpha = albedo.a; | ||
|
|
||
| #ifdef _ALPHATEST_ON | ||
| clip(alpha - _Cutoff); | ||
| #endif | ||
| } | ||
|
|
||
| half4 fragParticleSceneHighlight(VaryingsParticle input) : SV_Target | ||
| { | ||
| fragParticleSceneClip(input); | ||
| return float4(_ObjectId, _PassValue, 1, 1); | ||
| } | ||
|
|
||
| half4 fragParticleScenePicking(VaryingsParticle input) : SV_Target | ||
| { | ||
| fragParticleSceneClip(input); | ||
| return _SelectionID; | ||
| } | ||
|
|
||
| #endif // UNIVERSAL_PARTICLES_EDITOR_PASS_INCLUDED |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably should and int/float4 packing/unpacking functions. In core/ShaderLibarary/Packing.hlsl there are similar functions (e.g. UnpackFromR11G11B10f). Consider adding pack/unpack for this case too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose this is the same case as the matrix invert. I think it would be good to add a comment/TODO to replace with library implementation when available.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, i missed this comment when i read over the PR feedback, sorry. i think this one is actually more clear-cut than the matrix one - i don't see a reason why i cant move it to the Packing file. I'll sort that out :)