-
Notifications
You must be signed in to change notification settings - Fork 840
[Feature] Compute Deformation Node #166
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 all commits
1fdc616
52dc535
ad6e50d
64c2b28
77068bc
fea2f6d
886311e
fde6b2c
ee378ae
f3eb6fd
8eea6cc
d783334
91ae952
dc5e924
f27c5db
f94e60c
9cee664
0602112
443fb31
3804528
20724cd
71aa8c4
601fd24
a90ab12
8e9099b
67b6805
4cadeee
c32ecaa
94d1fc1
bc0b8bc
07a2e04
ab77a3e
5a37915
b4089d2
bc7b6f4
75972ad
ede321b
3afee37
cfb9a28
f55325a
4c76690
b42c201
38f0bfb
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 |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# Compute Deformation Node | ||
|
||
## Description | ||
|
||
This node lets you pass compute deformed vertex data to a vertex shader, and only works with the [DOTS Hybrid Renderer](https://docs.unity3d.com/Packages/com.unity.rendering.hybrid@latest/). You must provide `DeformedVertexData` in the `_DeformedMeshData` buffer. The node uses the `_ComputeMeshIndex` property to calculate where the `DeformedVertexData` associated with the current mesh are located in the `_DeformedMeshData` buffer. To output data, you must either install both the DOTS Hybrid Renderer and DOTS Animation packages, or use a custom solution. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there anything specific inside of the DOTS Hyrbid or Animation packages that goes in depth on how to use the Deformed Mesh Data buffer, or in what case this node would be useful? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes we do :) It can be found here. Please let us know if you think there is anything missing from the docs. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That page looks good, can you make a note to add a link to it once it's public to users? I see it's in a private repo, but I would like the pages for skinning to have something along the lines of |
||
|
||
## Ports | ||
| Name | Direction | Type | Stage | Description | | ||
|:--------- |:-----------|:--------|:-------|:------------| | ||
| Position | Output | Vector3 | Vertex | Outputs the deformed vertex position. | | ||
| Normal | Output | Vector3 | Vertex | Outputs the deformed vertex normal. | | ||
| Tangent | Output | Vector3 | Vertex | Outputs the deformed vertex tangent. | |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Linear Blend Skinning Node | ||
|
||
## Description | ||
|
||
This node lets you apply Linear Blend Vertex Skinning, and only works with the [DOTS Hybrid Renderer](https://docs.unity3d.com/Packages/com.unity.rendering.hybrid@latest/). You must provide skinned matrices in the `_SkinMatrices` buffer. The node uses the `_SkinMatrixIndex` property to calculate where the matrices associated with the current mesh are located in the `_SkinMatrices` buffer. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just going to echo what I noted for the Compute Deformation Node, if there's any specific external documentation for DOTS Hybrid that provides more context for this data and the use cases, that would be good to add here. |
||
|
||
## Ports | ||
| Name | Direction | Type | Stage | Description | | ||
|:--------- |:-----------|:--------|:-------|:------------| | ||
| Position | Input | Vector3 | Vertex | Position of the vertex in object space. | | ||
| Normal | Input | Vector3 | Vertex | Normal of the vertex in object space. | | ||
| Tangent | Input | Vector3 | Vertex | Tangent of the vertex in object space. | | ||
| Position | Output | Vector3 | Vertex | Outputs the skinned vertex position. | | ||
| Normal | Output | Vector3 | Vertex | Outputs the skinned vertex normal. | | ||
| Tangent | Output | Vector3 | Vertex | Outputs the skinned vertex tangent. | |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using UnityEditor.Graphing; | ||
|
||
namespace UnityEditor.ShaderGraph | ||
{ | ||
interface IMayRequireVertexID | ||
{ | ||
bool RequiresVertexID(ShaderStageCapability stageCapability = ShaderStageCapability.All); | ||
} | ||
|
||
static class MayRequireVertexIDExtensions | ||
{ | ||
public static bool RequiresVertexID(this MaterialSlot slot) | ||
{ | ||
var mayRequireVertexID = slot as IMayRequireVertexID; | ||
return mayRequireVertexID != null && mayRequireVertexID.RequiresVertexID(); | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
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,155 @@ | ||
using UnityEngine; | ||
using UnityEditor.Graphing; | ||
using UnityEditor.ShaderGraph.Internal; | ||
|
||
namespace UnityEditor.ShaderGraph | ||
{ | ||
[Title("Mesh Deformation", "Compute Deformation")] | ||
class ComputeDeformNode : AbstractMaterialNode, IGeneratesBodyCode, IGeneratesFunction, IMayRequirePosition, IMayRequireNormal, IMayRequireTangent, IMayRequireVertexID | ||
{ | ||
public const int kPositionOutputSlotId = 0; | ||
public const int kNormalOutputSlotId = 1; | ||
public const int kTangentOutputSlotId = 2; | ||
|
||
public const string kOutputSlotPositionName = "Deformed Position"; | ||
public const string kOutputSlotNormalName = "Deformed Normal"; | ||
public const string kOutputSlotTangentName = "Deformed Tangent"; | ||
|
||
public ComputeDeformNode() | ||
{ | ||
name = "Compute Deformation"; | ||
UpdateNodeAfterDeserialization(); | ||
} | ||
|
||
public sealed override void UpdateNodeAfterDeserialization() | ||
{ | ||
AddSlot(new Vector3MaterialSlot(kPositionOutputSlotId, kOutputSlotPositionName, kOutputSlotPositionName, SlotType.Output, Vector3.zero, ShaderStageCapability.Vertex)); | ||
AddSlot(new Vector3MaterialSlot(kNormalOutputSlotId, kOutputSlotNormalName, kOutputSlotNormalName, SlotType.Output, Vector3.zero, ShaderStageCapability.Vertex)); | ||
AddSlot(new Vector3MaterialSlot(kTangentOutputSlotId, kOutputSlotTangentName, kOutputSlotTangentName, SlotType.Output, Vector3.zero, ShaderStageCapability.Vertex)); | ||
RemoveSlotsNameNotMatching(new[] { kPositionOutputSlotId, kNormalOutputSlotId, kTangentOutputSlotId }); | ||
} | ||
|
||
protected override void CalculateNodeHasError() | ||
{ | ||
#if !HYBRID_RENDERER_0_6_0_OR_NEWER | ||
owner.AddSetupError(objectId, "Could not find version 0.6.0 or newer of the Hybrid Renderer package installed in the project."); | ||
hasError = true; | ||
#endif | ||
#if !ENABLE_COMPUTE_DEFORMATIONS | ||
owner.AddSetupError(objectId, "For the Compute Deformation node to work, you must go to Project Settings>Player>Other Settings and add the ENABLE_COMPUTE_DEFORMATIONS define to Scripting Define Symbols."); | ||
hasError = true; | ||
#endif | ||
} | ||
|
||
public bool RequiresVertexID(ShaderStageCapability stageCapability = ShaderStageCapability.All) | ||
{ | ||
return true; | ||
} | ||
|
||
public NeededCoordinateSpace RequiresPosition(ShaderStageCapability stageCapability = ShaderStageCapability.All) | ||
{ | ||
if (stageCapability == ShaderStageCapability.Vertex || stageCapability == ShaderStageCapability.All) | ||
return NeededCoordinateSpace.Object; | ||
else | ||
return NeededCoordinateSpace.None; | ||
} | ||
|
||
public NeededCoordinateSpace RequiresNormal(ShaderStageCapability stageCapability = ShaderStageCapability.All) | ||
{ | ||
if (stageCapability == ShaderStageCapability.Vertex || stageCapability == ShaderStageCapability.All) | ||
return NeededCoordinateSpace.Object; | ||
else | ||
return NeededCoordinateSpace.None; | ||
} | ||
|
||
public NeededCoordinateSpace RequiresTangent(ShaderStageCapability stageCapability = ShaderStageCapability.All) | ||
{ | ||
if (stageCapability == ShaderStageCapability.Vertex || stageCapability == ShaderStageCapability.All) | ||
return NeededCoordinateSpace.Object; | ||
else | ||
return NeededCoordinateSpace.None; | ||
} | ||
|
||
public override void CollectShaderProperties(PropertyCollector properties, GenerationMode generationMode) | ||
{ | ||
properties.AddShaderProperty(new Vector1ShaderProperty() | ||
{ | ||
displayName = "Compute Mesh Buffer Index Offset", | ||
overrideReferenceName = "_ComputeMeshIndex", | ||
gpuInstanced = true, | ||
#if ENABLE_HYBRID_RENDERER_V2 | ||
hidden = true, | ||
#endif | ||
value = 0 | ||
}); | ||
|
||
base.CollectShaderProperties(properties, generationMode); | ||
} | ||
|
||
public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode) | ||
{ | ||
#if ENABLE_HYBRID_RENDERER_V2 | ||
sb.AppendLine("#if defined(UNITY_DOTS_INSTANCING_ENABLED)"); | ||
#endif | ||
sb.AppendLine("$precision3 {0} = 0;", GetVariableNameForSlot(kPositionOutputSlotId)); | ||
sb.AppendLine("$precision3 {0} = 0;", GetVariableNameForSlot(kNormalOutputSlotId)); | ||
sb.AppendLine("$precision3 {0} = 0;", GetVariableNameForSlot(kTangentOutputSlotId)); | ||
if (generationMode == GenerationMode.ForReals) | ||
{ | ||
sb.AppendLine($"{GetFunctionName()}(" + | ||
$"IN.VertexID, " + | ||
$"{GetVariableNameForSlot(kPositionOutputSlotId)}, " + | ||
$"{GetVariableNameForSlot(kNormalOutputSlotId)}, " + | ||
$"{GetVariableNameForSlot(kTangentOutputSlotId)});"); | ||
} | ||
#if ENABLE_HYBRID_RENDERER_V2 | ||
sb.AppendLine("#else"); | ||
sb.AppendLine("$precision3 {0} = IN.ObjectSpacePosition;", GetVariableNameForSlot(kPositionOutputSlotId)); | ||
sb.AppendLine("$precision3 {0} = IN.ObjectSpaceNormal;", GetVariableNameForSlot(kNormalOutputSlotId)); | ||
sb.AppendLine("$precision3 {0} = IN.ObjectSpaceTangent;", GetVariableNameForSlot(kTangentOutputSlotId)); | ||
sb.AppendLine("#endif"); | ||
#endif | ||
} | ||
|
||
public void GenerateNodeFunction(FunctionRegistry registry, GenerationMode generationMode) | ||
{ | ||
registry.ProvideFunction("DeformedMeshData", sb => | ||
{ | ||
sb.AppendLine("struct DeformedVertexData"); | ||
sb.AppendLine("{"); | ||
using (sb.IndentScope()) | ||
{ | ||
sb.AppendLine("float3 Position;"); | ||
sb.AppendLine("float3 Normal;"); | ||
sb.AppendLine("float3 Tangent;"); | ||
} | ||
sb.AppendLine("};"); | ||
sb.AppendLine("uniform StructuredBuffer<DeformedVertexData> _DeformedMeshData : register(t1);"); | ||
}); | ||
|
||
registry.ProvideFunction(GetFunctionName(), sb => | ||
{ | ||
sb.AppendLine($"void {GetFunctionName()}(" + | ||
"uint vertexID, " + | ||
"out $precision3 positionOut, " + | ||
"out $precision3 normalOut, " + | ||
"out $precision3 tangentOut)"); | ||
|
||
sb.AppendLine("{"); | ||
using (sb.IndentScope()) | ||
{ | ||
sb.AppendLine("const DeformedVertexData vertexData = _DeformedMeshData[asuint(_ComputeMeshIndex) + vertexID];"); | ||
sb.AppendLine("positionOut = vertexData.Position;"); | ||
sb.AppendLine("normalOut = vertexData.Normal;"); | ||
sb.AppendLine("tangentOut = vertexData.Tangent;"); | ||
} | ||
sb.AppendLine("}"); | ||
}); | ||
} | ||
|
||
string GetFunctionName() | ||
{ | ||
return $"Unity_ComputeDeformedVertex_{concretePrecision.ToShaderString()}"; | ||
} | ||
} | ||
} |
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.
Ideally we would not have these be part of surface descriptions? However, they are required to have the nodes work in subgraphs...