Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,11 @@ public virtual void DrawSurfaceInputs(Material material)
public virtual void DrawAdvancedOptions(Material material)
{
materialEditor.EnableInstancingField();
DrawQueueOffsetField();
}

protected void DrawQueueOffsetField()
{
if (queueOffsetProp != null)
{
EditorGUI.BeginChangeCheck();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,11 @@ public static class Styles
public static string streamPositionText = "Position (POSITION.xyz)";
public static string streamNormalText = "Normal (NORMAL.xyz)";
public static string streamColorText = "Color (COLOR.xyzw)";
public static string streamColorInstancedText = "Color (INSTANCED0.xyzw)";
public static string streamUVText = "UV (TEXCOORD0.xy)";
public static string streamUV2Text = "UV2 (TEXCOORD0.zw)";
public static string streamAnimBlendText = "AnimBlend (TEXCOORD1.x)";
public static string streamAnimFrameText = "AnimFrame (INSTANCED1.x)";
public static string streamTangentText = "Tangent (TANGENT.xyzw)";

public static GUIContent streamApplyToAllSystemsText = new GUIContent("Fix Now",
Expand Down Expand Up @@ -253,6 +255,13 @@ public static void DoVertexStreamsArea(Material material, List<ParticleSystemRen
if(material.HasProperty("_BumpMap"))
useNormalMap = material.GetTexture("_BumpMap");

bool useGPUInstancing = ShaderUtil.HasProceduralInstancing(material.shader);
if (useGPUInstancing && renderers.Count > 0)
{
if (!renderers[0].enableGPUInstancing || renderers[0].renderMode != ParticleSystemRenderMode.Mesh)
useGPUInstancing = false;
}

// Build the list of expected vertex streams
List<ParticleSystemVertexStream> streams = new List<ParticleSystemVertexStream>();
List<string> streamList = new List<string>();
Expand All @@ -272,11 +281,18 @@ public static void DoVertexStreamsArea(Material material, List<ParticleSystemRen
}

streams.Add(ParticleSystemVertexStream.Color);
streamList.Add(Styles.streamColorText);
streamList.Add(useGPUInstancing ? Styles.streamColorInstancedText : Styles.streamColorText);
streams.Add(ParticleSystemVertexStream.UV);
streamList.Add(Styles.streamUVText);

if (useFlipbookBlending)
List<ParticleSystemVertexStream> instancedStreams = new List<ParticleSystemVertexStream>(streams);

if (useGPUInstancing)
{
instancedStreams.Add(ParticleSystemVertexStream.AnimFrame);
streamList.Add(Styles.streamAnimFrameText);
}
else if (useFlipbookBlending && !useGPUInstancing)
{
streams.Add(ParticleSystemVertexStream.UV2);
streamList.Add(Styles.streamUV2Text);
Expand All @@ -298,7 +314,14 @@ public static void DoVertexStreamsArea(Material material, List<ParticleSystemRen
foreach (ParticleSystemRenderer renderer in renderers)
{
renderer.GetActiveVertexStreams(rendererStreams);
if (!rendererStreams.SequenceEqual(streams))

bool streamsValid;
if (useGPUInstancing && renderer.renderMode == ParticleSystemRenderMode.Mesh && renderer.supportsMeshInstancing)
streamsValid = rendererStreams.SequenceEqual(instancedStreams);
else
streamsValid = rendererStreams.SequenceEqual(streams);

if (!streamsValid)
Warnings += "-" + renderer.name + "\n";
}

Expand All @@ -314,7 +337,10 @@ public static void DoVertexStreamsArea(Material material, List<ParticleSystemRen

foreach (ParticleSystemRenderer renderer in renderers)
{
renderer.SetActiveVertexStreams(streams);
if (useGPUInstancing && renderer.renderMode == ParticleSystemRenderMode.Mesh && renderer.supportsMeshInstancing)
renderer.SetActiveVertexStreams(instancedStreams);
else
renderer.SetActiveVertexStreams(streams);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ public override void DrawAdvancedOptions(Material material)
MaterialChanged(material);
}
}
base.DrawAdvancedOptions(material);

DrawQueueOffsetField();
}

public override void OnOpenGUI(Material material, MaterialEditor materialEditor)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ public override void DrawAdvancedOptions(Material material)
MaterialChanged(material);
}
}
base.DrawAdvancedOptions(material);

DrawQueueOffsetField();
}

public override void OnOpenGUI(Material material, MaterialEditor materialEditor)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ public override void DrawAdvancedOptions(Material material)
MaterialChanged(material);
}
}
base.DrawAdvancedOptions(material);

DrawQueueOffsetField();
}

public override void OnOpenGUI(Material material, MaterialEditor materialEditor)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ static void SetSupportedRenderingFeatures()
motionVectors = false,
receiveShadows = false,
reflectionProbes = true,
particleSystemInstancing = false
particleSystemInstancing = true
};
SceneViewDrawMode.SetupDrawMode();
#endif
Expand Down
69 changes: 69 additions & 0 deletions com.unity.render-pipelines.universal/ShaderLibrary/Particles.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Author

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 :)

#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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like a Y-flip. If that's the case, then it would be good to have a comment why it's done (and if the comment has a word flip in it then it's searchable if someone is tracking down a chain of flips :) )

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honest answer: I dunno - it's copied from the built-in instancing code which is coped from the built-in cpu code which is really old. Something about UV space, I suppose :)

Copy link
Contributor

@eh-unity eh-unity Jul 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a bit unfortunate. Maybe at least add a comment that it's from built-in as is and it looks like upside-down flip. It wouldn't hurt to mention the flip in the comment (for searchability).
Ideally all flip chains should be removed/minimized, but that probably isn't realistic at this point and certainly not in the scope of this PR.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done :)


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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is just rotation, would just transpose be enough? That's inverse for rotations, but scales can be problem.
In any case we should have a function for generic matrix inverse, but I couldn't find any. Maybe use this to make generic matrix inverses for mat4,3,2 etc. While it's slow, it's sometimes necessary and useful for debugging spaces too.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is just rotation, would just transpose be enough? That's inverse for rotations, but scales can be problem.
In any case we should have a function for generic matrix inverse, but I couldn't find any. Maybe use this to make generic matrix inverses for mat4,3,2 etc. While it's slow, it's sometimes necessary and useful for debugging spaces too.

It's not just rotation :)

I am super hesitant to add any code that is unused (as the mat4 and mat2 variants would be). It's best done at a time when they can be tested as being correct IMO. (i.e. when there is a use case)

If you would like me to move this code in a function called "invertMatrix" or similar, let me know the name and file you'd like, thanks :) (This is my first -and perhaps only- URP PR, so I don't know my way around your shader library)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. I can agree that adding those isn't in the scope of this PR.
Perhaps add a todo comment to replace with a library implementation if/when available, so the info is not lost.
Also if it's not just rotation then perhaps the variable name 'w2oRotation' could be more clear.

Copy link
Author

@ghost ghost Jul 13, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opted for worldToObject3x3

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.

Loading