diff --git a/com.unity.sg2/Documentation~/Imposter-Sample-Node.md b/com.unity.sg2/Documentation~/Imposter-Sample-Node.md
new file mode 100644
index 00000000000..7430b1e0f47
--- /dev/null
+++ b/com.unity.sg2/Documentation~/Imposter-Sample-Node.md
@@ -0,0 +1,69 @@
+# Imposter Sample Node
+
+## Description
+
+Uses the UV coordinates generated by the Imposter UV node to sample an specific imposter texture.
+This creates the illusion of a 3D object on a billboard object because the imposter texture's frame changes based on the camera direction and angle.
+If the imposter object has more than one texture to sample (e.g. color, normal, mask, occlusion, etc,), multiple Imposter Sample nodes can be used.
+## Ports
+
+| Name | Direction | Type | Description |
+|:------------ |:-------------|:-----|:---|
+| Texture | Input | Texture2D | The texture asset to sample |
+| Sampler | Input | Sampler State | The texture sampler to use for sampling the texture |
+| UV0 | Input | Vector2 | The virtual UV for the base frame |
+| UV1 | Input | Vector2 | The virtual UV for the second frame |
+| UV2 | Input | Vector2 | The virtual UV for the third frame |
+| Grid | Input | Vector4 | The current UV grid, which is used to find the corresponding sample frames |
+| Weights | Input | Vector4 | The blending values in between the slected three frames|
+| RGBA | Output | Vector4 | A vector4 from the sampled texture |
+| RGB | Output | Vector3 | A vector3 from the sampled texture |
+| R | Output | Float | The r channel of the sampled texture |
+| G | Output | Float | The g channel of the sampled texture |
+| B | Output | Float | The b channel of the sampled texture |
+| A | Output | Float | The a channel of the sampled texture |
+
+## Controls
+
+The Imposter Sample Node [!include[nodes-controls](./snippets/nodes-controls.md)]
+
+
+
+
+Name |
+Sample Type |
+Description |
+
+
+
+
+Type |
+Dropdown |
+Select whether to sample three frames or one frame. |
+
+
+Three Frames |
+Blends between three frames to get the smoothest result. |
+
+
+One Frame |
+Calculates only one frame for better performance. UV1, UV2 and Weights inputs won't be shown. |
+
+
+
+
+## Generated code example
+
+[!include[nodes-generated-code](./snippets/nodes-generated-code.md)], based on the selected Mode on the Imposter Sample Node node:
+
+### ThreeFrames
+
+```
+ImposterSample( Texture.tex, TexelSize, Weights, Grid, UV0, UV1, UV2, Sampler.samplerstate, RGBA);
+```
+
+### OneFrame
+
+```
+ImposterSample_oneFrame( Texture.tex, TexelSize, Weights, Grid, UV0, UV1, UV2, Sampler.samplerstate, RGBA);
+```
diff --git a/com.unity.sg2/Documentation~/Imposter-UV-Node.md b/com.unity.sg2/Documentation~/Imposter-UV-Node.md
new file mode 100644
index 00000000000..7482977f3af
--- /dev/null
+++ b/com.unity.sg2/Documentation~/Imposter-UV-Node.md
@@ -0,0 +1,73 @@
+# Imposter UV Node
+
+## Description
+
+The Imposter UV Node calculates the billboard position and the UV coordinates needed by the Imposter Sample node.
+## Ports
+
+| Name | Direction | Type | Description |
+|:------------ |:-------------|:-----|:---|
+| In Position | Input | Vector3 | The postion in Object space |
+| In UV | Input | Vector2 | The UV coordinates of the mesh |
+| Frames | Input | Int | The number of the imposter frames in each axis|
+| Size | Input | Float | The size of the imposter |
+| Offset | Input | Vector3 | The offset value from the pivot |
+| Frame Clipping Threshold | Input | Float | The clamping value for the neighboring frames most useful when parallax mapping is enabled |
+| Texture Size | Input | Int | The resolution of the texture. |
+| Hemisphere | Input | Boolean | If it's true, calculates the imposter grid and UVs base on hemisphere type.This is Useful if the imposter object will only be seen from above |
+| Parallax | Input | Float | Parallax strength, if it equals to 0 than he parallax related control won't affect the outputs.|
+| Height map | Input | Texture2D | The height map texture to sample |
+| Heightmap Sampler | Input | Sampler State | The texture sampler to use for sampling the texture |
+| Heightmap Smaple Channel | Input | Int | The channel of the height map to sample for parallax mapping, if any|
+| Out Positon | Output | Vector3 | The output billboard position |
+| UV0 | Output | Vector2 | The virtual UV for the base frame |
+| UV1 | Output | Vector2 | The virtual UV for the second frame |
+| UV2 | Output | Vector2 | The virtual UV for the third frame |
+| Grid | Output | Vector4 | The current UV grid, which is used to find the corresponding sample frames |
+| Weights | Output | Vector4 | he blending values in between the slected three frames |
+
+
+## Controls
+
+The Imposter UV Node [!include[nodes-controls](./snippets/nodes-controls.md)]
+
+
+
+
+Name |
+Sample Type |
+Description |
+
+
+
+
+Type |
+Dropdown |
+Select whether to sample three frames or one frame. |
+
+
+Three Frames |
+Blends between three frames to get the smoothest result. |
+
+
+One Frame |
+Calculates only one frame for better performance. UV1, UV2 and Weights outputs won't be shown. |
+
+
+
+
+## Generated code example
+
+[!include[nodes-generated-code](./snippets/nodes-generated-code.md)], based on the selected Mode on the Imposter Sample Node node:
+
+### ThreeFrames
+
+```
+ImposterUV(Pos, inUV, Frames, Offset, Size, imposterFrameClip, HemiSphere, Parallax, HeightMapChannel, ss, HeightMap, TextureSize, OutPos, Weights, Grid, UV0, UV1, UV2)
+```
+
+### OneFrame
+
+```
+ImposterUV_oneFrame(Pos, inUV, Frames, Offset, Size, imposterFrameClip, HemiSphere, Parallax, HeightMapChannel, ss, HeightMap, TextureSize, OutPos, Grid, UV0);
+```
diff --git a/com.unity.sg2/Documentation~/previews/ImposterSample.md b/com.unity.sg2/Documentation~/previews/ImposterSample.md
new file mode 100644
index 00000000000..244f4de87f2
--- /dev/null
+++ b/com.unity.sg2/Documentation~/previews/ImposterSample.md
@@ -0,0 +1,23 @@
+## Description
+Uses the UV coordinates generated by the Imposter UV node to sample an specific imposter texture.
+This creates the illusion of a 3D object on a billboard object because the imposter texture's frame changes based on the camera direction and angle.
+
+## Inputs
+**Texture** - The texture asset to sample.
+**Sampler** - The texture sampler to use for sampling the texture.
+**UV0** - The virtual UV for the base frame.
+**UV1** - The virtual UV for the second frame.
+**UV2** - The virtual UV for the third frame.
+**Grid** - The current UV grid, which is used to find the corresponding sample frames.
+**Weights** - The blending values in between the slected three frames.
+
+## Output
+**RGBA** - A vector4 from the sampled texture.
+**RGB** - A vector3 from the sampled texture.
+**R** - The r channel of the sampled texture.
+**G** - The g channel of the sampled texture.
+**B** - The b channel of the sampled texture.
+**A** - The a channel of the sampled texture.
+
+## Controls
+**Sample Type** - Select whether to sample three frames or one frame, three frames for smoother result, one frame for better performance.
diff --git a/com.unity.sg2/Documentation~/previews/ImposterUV.md b/com.unity.sg2/Documentation~/previews/ImposterUV.md
new file mode 100644
index 00000000000..6b52e9a33d7
--- /dev/null
+++ b/com.unity.sg2/Documentation~/previews/ImposterUV.md
@@ -0,0 +1,26 @@
+## Description
+Calculates the billboard positon and the virtual UVs for sampling.
+
+## Inputs
+**InPosition** - The postion in Object space.
+**In UV** - The UV coordinates of the mesh.
+**Frames** - The number of the imposter frames in each axis.
+**Size** - The size of the imposter.
+**Offset** - The offset value from the pivot.
+**Frame Clipping Threshold** - The clamping value for the neighboring frames most useful when parallax mapping is enabled.
+**Texture Size** - The texture resolution.
+**Heightmap** - The height map texture to sample.
+**Heightmap Sampler** - The texture sampler to use for sampling the texture.
+**Parallax** - Parallax strength.
+**Heightmap Sample Channel** - The channle of the height map to sample for parallax mapping, if any.
+**HemiSphere** - If it's true, calculates the imposter grid and UVs base on hemisphere type. Useful if the object is only seen from above.
+
+## Output
+**OutPosition** - The output billboard position.
+**UV0** - The virtual UV for the base frame.
+**UV1** - The virtual UV for the second frame.
+**UV2** - The virtual UV for the third frame.
+**Grid** - The current UV grid using to find the sample frames.
+
+## Controls
+**Sample Type** - Select whether to sample three frames or one frame, three frames for smoother result, one frame for better performance.
diff --git a/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/BillboardNode.cs b/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Input/MeshDeformation/BillboardNode.cs
similarity index 100%
rename from com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/BillboardNode.cs
rename to com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Input/MeshDeformation/BillboardNode.cs
diff --git a/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/BillboardNode.cs.meta b/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Input/MeshDeformation/BillboardNode.cs.meta
similarity index 100%
rename from com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/BillboardNode.cs.meta
rename to com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Input/MeshDeformation/BillboardNode.cs.meta
diff --git a/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/Imposter.hlsl b/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/Imposter.hlsl
new file mode 100644
index 00000000000..40113ae6fdc
--- /dev/null
+++ b/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/Imposter.hlsl
@@ -0,0 +1,373 @@
+#ifndef SHADERGRAPHIMPOSTER
+#define SHADERGRAPHIMPOSTER
+
+#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Sampling/Sampling.hlsl"
+#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ParallaxMapping.hlsl"
+
+struct Ray
+{
+ float3 Origin;
+ float3 Direction;
+};
+
+float3 CoordToHemi(float2 coord)
+{
+ coord = float2(coord.x + coord.y, coord.x - coord.y) * 0.5;
+ float3 dir = float3(coord.x, 1 - dot(float2(1, 1), abs(coord.xy)), coord.y);
+ return dir;
+}
+
+float3 CoordToOcta(float2 coord)
+{
+ float3 dir = float3(coord.x, 1 - dot(1, abs(coord)), coord.y);
+ if (dir.y < 0)
+ {
+ float2 flip = dir.xz >= 0 ? float2(1, 1) : float2(-1, -1);
+ dir.xz = (1 - abs(dir.zx)) * flip;
+ }
+ return dir;
+}
+
+float3 GridToVector(float2 coord, bool IsHemi)
+{
+ float3 dir;
+ if (IsHemi)
+ {
+ dir = CoordToHemi(coord);
+ }
+ else
+ {
+ dir = CoordToOcta(coord);
+ }
+ return dir;
+}
+
+//for hemisphere
+float2 VectorToHemi(float3 dir)
+{
+ dir.xz /= dot(1.0, abs(dir));
+ return float2(dir.x + dir.z, dir.x - dir.z);
+}
+
+float2 VectorToOcta(float3 dir)
+{
+ dir.xz /= dot(1, abs(dir));
+ if (dir.y <= 0)
+ {
+ dir.xz = (1 - abs(dir.zx)) * (dir.xz >= 0 ? 1.0 : -1.0);
+ }
+ return dir.xz;
+}
+
+float4 CalculateWeights(float2 uv)
+{
+ uv = frac(uv);
+
+ float2 oneMinusUV = 1 - uv.xy;
+
+ float4 weights;
+ //frame 0
+ weights.x = min(oneMinusUV.x, oneMinusUV.y);
+ //frame 1
+ weights.y = abs(dot(uv, float2(1.0, -1.0)));
+ //frame 2
+ weights.z = min(uv.x, uv.y);
+ //mask
+ weights.w = saturate(ceil(uv.x - uv.y));
+
+ return weights;
+}
+
+float3 FrameTransformLocal(float3 BillboardPosToCam, float3 normal, out float3 worldX, out float3 worldZ)
+{
+ float3 upVector = float3 (0, 1, 0);
+ worldX = normalize(cross(upVector, normal));
+ worldZ = normalize(cross(worldX, normal));
+
+ BillboardPosToCam *= -1.0;
+
+ float3x3 worldToLocal = float3x3(worldX, worldZ, normal);
+ float3 localRay = normalize(mul(worldToLocal, BillboardPosToCam));
+ return localRay;
+}
+
+float2 PlaneIntersectionUV(float3 planeNormal, float3 planeX, float3 planeZ, float3 center, float2 UVscale, Ray ray)
+{
+ float normalDotOrigin = dot(planeNormal, -ray.Origin);//(p0 - l0) . n
+ float normalDotRay = dot(planeNormal, ray.Direction);//l.n
+ float planeDistance = normalDotOrigin / normalDotRay;//distance >0 then intersecting
+
+ //intersect = rayDir * distance + rayPos
+ float3 intersection = ((ray.Direction * planeDistance) + ray.Origin) - center;
+
+ float dx = dot(planeX, intersection);
+ float dz = dot(planeZ, intersection);
+
+ float2 uv = float2(0, 0);
+
+ if (planeDistance > 0)
+ uv = -float2(dx, dz);
+
+ uv /= UVscale;
+ uv += 0.5;
+ return uv;
+}
+
+
+
+float3 CalculateBillboardProjection(float3 objectSpaceCameraDir, float2 uv)
+{
+ float3 x = normalize(cross(objectSpaceCameraDir, float3(0.0, 1.0, 0.0)));
+ float3 z = normalize(cross(x, objectSpaceCameraDir));
+
+ uv = uv * 2.0 - 1.0;
+
+ float3 newX = x * uv.x;
+ float3 newZ = z * uv.y;
+
+ float3 result = newX + newZ;
+ return result;
+}
+
+//Calculate Vertex postion and UVs
+void ImposterUV(in float3 inPos, in float2 inUV, in int imposterFrames, in float3 imposterOffset, in float imposterSize, in float imposterFrameClip,
+ in bool isHemi, in float parallax, in int heightMapChannel, in SamplerState ss, in Texture2D heightMap, in int TextureSize,
+ out float3 outPos, out float4 outWeights, out float2 outUV0, out float2 outUV1, out float2 outUV2, out float4 outUVGrid)
+{
+ float framesMinusOne = imposterFrames - 1;
+
+ //camera pos in object space
+ float3 objectSpaceCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos.xyz, 1)).xyz - imposterOffset;
+ float3 objectSpaceCameraDir = normalize(objectSpaceCameraPos.xyz);
+
+ //get uv in a single frame
+ float2 UVscaled = inUV * (1.0 / imposterFrames);
+ float2 size = imposterSize.xx * 1.33;
+
+ float3 BillboardPos = CalculateBillboardProjection(objectSpaceCameraDir, inUV);
+ BillboardPos *= 0.67;
+
+ //camera to projection vector
+ float3 rayDirLocal = BillboardPos - objectSpaceCameraPos;
+
+ //BillboardPos position to camera ray
+ float3 BillboardPosToCam = normalize(objectSpaceCameraPos - BillboardPos);
+
+ Ray ray;
+ ray.Origin = objectSpaceCameraPos;
+ ray.Direction = rayDirLocal;
+
+ //set up virtual grid
+ float2 grid;
+ if (isHemi) {
+ objectSpaceCameraDir.y = max(0.001, objectSpaceCameraDir.y);
+ grid = VectorToHemi(objectSpaceCameraDir);
+ }
+ else {
+ grid = VectorToOcta(objectSpaceCameraDir);
+ }
+
+ grid = saturate(grid * 0.5 + 0.5); //scale to 0 to 1
+ grid *= framesMinusOne;//multiply framesMinusOne to cover the texture
+
+ float2 gridFrac = frac(grid);
+ float2 gridFloor = floor(grid);
+
+ float4 weights = CalculateWeights(gridFrac);
+
+ //set up for octahedron:
+ //1.find the nearest 3 frames
+ //2.base on the grid find the direction intersect with the octahedron
+ //3.construct the face/plane for that direction
+ //4.base on the plane and find the virtual uv coord
+
+ //get the 3 nearest frames
+ float2 frame0 = gridFloor;
+ float2 frame1 = gridFloor + lerp(float2(0, 1), float2(1, 0), weights.w);
+ float2 frame2 = gridFloor + float2(1, 1);
+
+ //convert frame coord to octahedron ray
+ float3 frame0ray = normalize(GridToVector(float2(frame0 / framesMinusOne * 2 - 1), isHemi));
+ float3 frame1ray = normalize(GridToVector(float2(frame1 / framesMinusOne * 2 - 1), isHemi));
+ float3 frame2ray = normalize(GridToVector(float2(frame2 / framesMinusOne * 2 - 1), isHemi));
+
+ float3 center = float3(0, 0, 0);
+
+ float3 plane0x;
+ float3 plane0normal = frame0ray;
+ float3 plane0z;
+ float3 frame0local = FrameTransformLocal(BillboardPosToCam, frame0ray, plane0x, plane0z);
+
+ float2 vUv0 = PlaneIntersectionUV(plane0normal, plane0x, plane0z, center, size, ray);
+ vUv0 /= imposterFrames;
+
+ float3 plane1x;
+ float3 plane1normal = frame1ray;
+ float3 plane1z;
+ float3 frame1local = FrameTransformLocal(BillboardPosToCam, frame1ray, plane1x, plane1z);
+
+ float2 vUv1 = PlaneIntersectionUV(plane1normal, plane1x, plane1z, center, size, ray);
+ vUv1 /= imposterFrames;
+
+ float3 plane2x;
+ float3 plane2normal = frame2ray;
+ float3 plane2z;
+ float3 frame2local = FrameTransformLocal(BillboardPosToCam, frame2ray, plane2x, plane2z);
+
+ float2 vUv2 = PlaneIntersectionUV(plane2normal, plane2x, plane2z, center, size, ray);
+ vUv2 /= imposterFrames;
+
+ frame0local.xy /= imposterFrames;
+ frame1local.xy /= imposterFrames;
+ frame2local.xy /= imposterFrames;
+
+ float2 gridSnap = floor(grid) / imposterFrames.xx;
+
+ float2 frame0grid = gridSnap;
+ float2 frame1grid = gridSnap + (lerp(float2(0, 1), float2(1, 0), weights.w) / imposterFrames.xx);
+ float2 frame2grid = gridSnap + (float2(1, 1) / imposterFrames.xx);
+
+ float2 vp0uv = frame0grid + vUv0.xy;
+ float2 vp1uv = frame1grid + vUv1.xy;
+ float2 vp2uv = frame2grid + vUv2.xy;
+
+ //vert pos
+ outPos = BillboardPos + imposterOffset;
+
+ float frameSize = TextureSize / imposterFrames;
+ float actualTextureSize = floor(frameSize) * imposterFrames;
+ float scalar = TextureSize / actualTextureSize;
+
+ vp0uv *= scalar;
+ vp0uv *= scalar;
+ vp0uv *= scalar;
+
+ if (parallax != 0) {
+
+ float h0 = SAMPLE_TEXTURE2D(heightMap, ss, vp0uv)[heightMapChannel];
+ float h1 = SAMPLE_TEXTURE2D(heightMap, ss, vp1uv)[heightMapChannel];
+ float h2 = SAMPLE_TEXTURE2D(heightMap, ss, vp2uv)[heightMapChannel];
+
+ vp0uv += (0.5 - h0) * frame0local.xy * parallax;
+ vp1uv += (0.5 - h1) * frame1local.xy * parallax;
+ vp2uv += (0.5 - h2) * frame2local.xy * parallax;
+ }
+ //clip out neighboring frames
+ float2 gridSize = 1.0 / imposterFrames.xx;
+ float2 bleeds = imposterFrameClip/ TextureSize;
+ vp0uv = clamp(vp0uv, frame0grid - bleeds, frame0grid + gridSize + bleeds);
+ vp1uv = clamp(vp1uv, frame1grid - bleeds, frame1grid + gridSize + bleeds);
+ vp2uv = clamp(vp2uv, frame2grid - bleeds, frame2grid + gridSize + bleeds);
+
+ //surface
+ outUV0 = vp0uv;
+ outUV1 = vp1uv;
+ outUV2 = vp2uv;
+ outWeights = weights;
+ outUVGrid.xy = UVscaled;
+ outUVGrid.zw = grid;
+}
+
+void ImposterUV_oneFrame(in float3 inPos, in float2 inUV, in int imposterFrames, in float3 imposterOffset, in float imposterSize, in float imposterFrameClip,
+ in bool isHemi, in float parallax, in int heightMapChannel, in SamplerState ss, in Texture2D heightMap, in int TextureSize,
+ out float3 outPos, out float2 outUV0, out float4 outUVGrid)
+{
+ float framesMinusOne = imposterFrames - 1;
+
+ //camera pos in object space
+ float3 objectSpaceCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos.xyz, 1)).xyz - imposterOffset;
+ float3 objectSpaceCameraDir = normalize(objectSpaceCameraPos.xyz);
+
+ //get uv in a single frame
+ float2 UVscaled = inUV * (1.0 / imposterFrames);
+ float2 size = imposterSize.xx * 1.33;
+
+ float3 BillboardPos = CalculateBillboardProjection(objectSpaceCameraDir, inUV);
+ BillboardPos *= 0.67;
+
+ //camera to projection vector
+ float3 rayDirLocal = BillboardPos - objectSpaceCameraPos;
+
+ //BillboardPos position to camera ray
+ float3 BillboardPosToCam = normalize(objectSpaceCameraPos - BillboardPos);
+
+ Ray ray;
+ ray.Origin = objectSpaceCameraPos;
+ ray.Direction = rayDirLocal;
+
+ //set up virtual grid
+ float2 grid;
+ if (isHemi) {
+ objectSpaceCameraDir.y = max(0.001, objectSpaceCameraDir.y);
+ grid = VectorToHemi(objectSpaceCameraDir);
+ }
+ else {
+ grid = VectorToOcta(objectSpaceCameraDir);
+ }
+
+ grid = saturate(grid * 0.5 + 0.5); //scale to 0 to 1
+ grid *= framesMinusOne;//multiply framesMinusOne to cover the texture
+
+ float2 gridFrac = frac(grid);
+ float2 gridFloor = floor(grid);
+
+ //convert frame coord to octahedron ray
+ float3 frame0ray = normalize(GridToVector(float2(gridFloor / framesMinusOne * 2 - 1), isHemi));
+
+ float3 center = float3(0, 0, 0);
+
+ float3 plane0x;
+ float3 plane0normal = frame0ray;
+ float3 plane0z;
+ float3 frame0local = FrameTransformLocal(BillboardPosToCam, frame0ray, plane0x, plane0z);
+
+ float2 vUv0 = PlaneIntersectionUV(plane0normal, plane0x, plane0z, center, size, ray);
+ vUv0 /= imposterFrames;
+
+ frame0local.xy /= imposterFrames;
+
+ float2 gridSnap = floor(grid) / imposterFrames.xx;
+ float2 frame0grid = gridSnap;
+ float2 vp0uv = frame0grid + vUv0.xy;
+
+ //vert pos
+ outPos = BillboardPos + imposterOffset;
+
+ float frameSize = TextureSize / imposterFrames;
+ float actualTextureSize = floor(frameSize) * imposterFrames;
+ float scalar = TextureSize / actualTextureSize;
+
+ vp0uv *= scalar;
+
+ if (parallax != 0) {
+
+ float h0 = SAMPLE_TEXTURE2D(heightMap, ss, vp0uv)[heightMapChannel];
+ vp0uv += (0.5 - h0) * frame0local.xy * parallax;
+ }
+ //clip out neighboring frames
+ float2 gridSize = 1.0 / imposterFrames.xx;
+ float2 bleeds = imposterFrameClip / TextureSize;
+ vp0uv = clamp(vp0uv, frame0grid - bleeds, frame0grid + gridSize + bleeds);
+
+ //surface
+ outUV0 = vp0uv;
+ outUVGrid.xy = UVscaled;
+ outUVGrid.zw = grid;
+
+}
+//Sample from UVs and blend bases on the weights
+void ImposterSample(in texture2D Texture, in float4 weights, in float4 inUVGrid,
+ in float2 inUV0, in float2 inUV1, in float2 inUV2, in SamplerState ss, out float4 outColor)
+{
+ outColor = SAMPLE_TEXTURE2D_GRAD(Texture, ss, inUV0, ddx(inUVGrid.xy), ddy(inUVGrid.xy)) * weights.x
+ + SAMPLE_TEXTURE2D_GRAD(Texture, ss, inUV1, ddx(inUVGrid.xy), ddy(inUVGrid.xy)) * weights.y
+ + SAMPLE_TEXTURE2D_GRAD(Texture, ss, inUV2, ddx(inUVGrid.xy), ddy(inUVGrid.xy)) * weights.z;
+}
+
+void ImposterSample_oneFrame(in texture2D Texture, in float4 inUVGrid,
+ in float2 inUV0, in SamplerState ss, out float4 outColor)
+{
+ outColor = SAMPLE_TEXTURE2D_GRAD(Texture, ss, inUV0, ddx(inUVGrid.xy), ddy(inUVGrid.xy));
+}
+
+#endif
diff --git a/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/Imposter.hlsl.meta b/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/Imposter.hlsl.meta
new file mode 100644
index 00000000000..6c340c1de4e
--- /dev/null
+++ b/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/Imposter.hlsl.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 1142271a2968b4249b58c9ba1e9012f7
+ShaderIncludeImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/ImposterSampleNode.cs b/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/ImposterSampleNode.cs
new file mode 100644
index 00000000000..2e9bb7bdc85
--- /dev/null
+++ b/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/ImposterSampleNode.cs
@@ -0,0 +1,145 @@
+using UnityEditor.ShaderGraph.GraphDelta;
+using Usage = UnityEditor.ShaderGraph.GraphDelta.GraphType.Usage;
+
+namespace UnityEditor.ShaderGraph.Defs
+{
+ internal class ImposterSampleNode : IStandardNode
+ {
+ static string Name => "ImposterSampleNode";
+ static int Version => 1;
+ public static NodeDescriptor NodeDescriptor => new(
+ Version,
+ Name,
+ "ImposterSample",
+ functions: new FunctionDescriptor[] {
+ new(
+ "ThreeFrames",
+ @"ImposterSample( Texture.tex, Weights, Grid, UV0, UV1, UV2, Sampler.samplerstate, RGBA);
+ RGB = RGBA.rgb;
+ R = RGBA.r;
+ G = RGBA.g;
+ B = RGBA.b;
+ A = RGBA.a;
+",
+ new ParameterDescriptor[]
+ {
+ new ParameterDescriptor("Texture", TYPE.Texture2D, Usage.In),
+ new ParameterDescriptor("Sampler", TYPE.SamplerState, Usage.In),
+ new ParameterDescriptor("UV0", TYPE.Vec2, Usage.In),
+ new ParameterDescriptor("UV1", TYPE.Vec2, Usage.In),
+ new ParameterDescriptor("UV2", TYPE.Vec2, Usage.In),
+ new ParameterDescriptor("Grid", TYPE.Vec4, Usage.In),
+ new ParameterDescriptor("Weights", TYPE.Vec4, Usage.In),
+ new ParameterDescriptor("RGBA", TYPE.Vec4, Usage.Out),
+ new ParameterDescriptor("RGB", TYPE.Vec3, Usage.Out),
+ new ParameterDescriptor("R", TYPE.Float, Usage.Out),
+ new ParameterDescriptor("G", TYPE.Float, Usage.Out),
+ new ParameterDescriptor("B", TYPE.Float, Usage.Out),
+ new ParameterDescriptor("A", TYPE.Float, Usage.Out)
+ },
+ new string[]
+ {
+ "\"Packages/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/Imposter.hlsl\""
+ }
+ ),
+ new(
+ "OneFrame",//TODO: change back to one frame
+ @"ImposterSample_oneFrame ( Texture.tex, Grid, UV0, Sampler.samplerstate, RGBA);
+ RGB = RGBA.rgb;
+ R = RGBA.r;
+ G = RGBA.g;
+ B = RGBA.b;
+ A = RGBA.a;
+",
+ new ParameterDescriptor[]
+ {
+ new ParameterDescriptor("Texture", TYPE.Texture2D, Usage.In),
+ new ParameterDescriptor("Sampler", TYPE.SamplerState, Usage.In),
+ new ParameterDescriptor("UV0", TYPE.Vec2, Usage.In),
+ new ParameterDescriptor("Grid", TYPE.Vec4, Usage.In),
+ new ParameterDescriptor("RGBA", TYPE.Vec4, Usage.Out),
+ new ParameterDescriptor("RGB", TYPE.Vec3, Usage.Out),
+ new ParameterDescriptor("R", TYPE.Float, Usage.Out),
+ new ParameterDescriptor("G", TYPE.Float, Usage.Out),
+ new ParameterDescriptor("B", TYPE.Float, Usage.Out),
+ new ParameterDescriptor("A", TYPE.Float, Usage.Out) },
+ new string[]
+ {
+ "\"Packages/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/Imposter.hlsl\""
+ }
+ )
+ }
+ );
+
+ public static NodeUIDescriptor NodeUIDescriptor => new(
+ Version,
+ Name,
+ displayName: "Imposter Sample",
+ tooltip: "Samples from the three virtual UVs and blends them base on the camera intersection point to get the correct result.",
+ category: "Utility",
+ hasPreview: false,
+ description: "pkg://Documentation~/previews/ImposterSample.md",
+ synonyms: new string[] { "billboard" },
+ selectableFunctions: new()
+ {
+ { "ThreeFrames", "Three Frames" },
+ { "OneFrame", "One Frame" }
+ },
+ functionSelectorLabel: "Sample Type",
+ parameters: new ParameterUIDescriptor[] {
+ new ParameterUIDescriptor(
+ name: "Texture",
+ tooltip: "The texture asset to sample"
+ ),
+ new ParameterUIDescriptor(
+ name: "Sampler",
+ tooltip: "The texture sampler to use for sampling the texture"
+ ),
+ new ParameterUIDescriptor(
+ name: "UV0",
+ tooltip: "The virtual UV for the base frame"
+ ),
+ new ParameterUIDescriptor(
+ name: "UV1",
+ tooltip: "The virtual UV for the second frame"
+ ),
+ new ParameterUIDescriptor(
+ name: "UV2",
+ tooltip: "The virtual UV for the third frame"
+ ),
+ new ParameterUIDescriptor(
+ name: "Grid",
+ tooltip: "The current UV grid"
+ ),
+ new ParameterUIDescriptor(
+ name: "Weights",
+ tooltip: "Blending weights for three frames"
+ ),
+ new ParameterUIDescriptor(
+ name: "RGBA",
+ tooltip: "A vector4 from the sampled texture"
+ ),
+ new ParameterUIDescriptor(
+ name: "RGB",
+ tooltip: "A vector3 from the sampled texture"
+ ),
+ new ParameterUIDescriptor(
+ name: "R",
+ tooltip: "The red channel of the sampled texture"
+ ),
+ new ParameterUIDescriptor(
+ name: "G",
+ tooltip: "The green channel of the sampled texture"
+ ),
+ new ParameterUIDescriptor(
+ name: "B",
+ tooltip: "The blue channel of the sampled texture"
+ ),
+ new ParameterUIDescriptor(
+ name: "A",
+ tooltip: "The alpha channel of the sampled texture"
+ )
+ }
+ );
+ }
+}
diff --git a/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/ImposterSampleNode.cs.meta b/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/ImposterSampleNode.cs.meta
new file mode 100644
index 00000000000..8a706bbb5be
--- /dev/null
+++ b/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/ImposterSampleNode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a6f1bf7c54fba824fb10c73483a88e77
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/ImposterUVNode.cs b/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/ImposterUVNode.cs
new file mode 100644
index 00000000000..f54f451866e
--- /dev/null
+++ b/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/ImposterUVNode.cs
@@ -0,0 +1,175 @@
+using UnityEditor.ShaderGraph.GraphDelta;
+using Usage = UnityEditor.ShaderGraph.GraphDelta.GraphType.Usage;
+
+namespace UnityEditor.ShaderGraph.Defs
+{
+ internal class ImposterUVNode : IStandardNode
+ {
+ static string Name => "ImposterUVNode";
+ static int Version => 1;
+ public static NodeDescriptor NodeDescriptor => new(
+ Version,
+ Name,
+ "ImposteUV",
+ functions: new FunctionDescriptor[] {
+ new(
+ "ThreeFrames",
+" ImposterUV(Pos, inUV, Frames, Offset, Size, FrameClip, HemiSphere, Parallax, HeightMapChannel, " +
+ " Sampler.samplerstate, Texture.tex, TextureSize, OutPos, Weights, UV0, UV1, UV2, Grid);",
+ new ParameterDescriptor[]
+ {
+ new ParameterDescriptor("Pos", TYPE.Vec3, Usage.In, REF.ObjectSpace_Position),
+ new ParameterDescriptor("inUV", TYPE.Vec2, Usage.In, REF.UV0),
+ new ParameterDescriptor("Frames", TYPE.Int, Usage.In, new float[] {16}),
+ new ParameterDescriptor("Size", TYPE.Float, Usage.In, new float[] {1}),
+ new ParameterDescriptor("Offset", TYPE.Vec3, Usage.In),
+ new ParameterDescriptor("FrameClip", TYPE.Float, Usage.In),
+ new ParameterDescriptor("TextureSize", TYPE.Int, Usage.In, new float[]{ 1024}),
+ new ParameterDescriptor("HemiSphere", TYPE.Bool, Usage.In),
+ new ParameterDescriptor("Parallax", TYPE.Float, Usage.In),
+ new ParameterDescriptor("Texture", TYPE.Texture2D, Usage.In),
+ new ParameterDescriptor("Sampler", TYPE.SamplerState, Usage.In),
+ new ParameterDescriptor("HeightMapChannel", TYPE.Int, Usage.In, 3),//TODO: this one should be a dropdown with r/g/b/a chnnal options like Parallax Mapping node
+ new ParameterDescriptor("OutPos", TYPE.Vec3, Usage.Out),
+ new ParameterDescriptor("UV0", TYPE.Vec2, Usage.Out),
+ new ParameterDescriptor("UV1", TYPE.Vec2, Usage.Out),
+ new ParameterDescriptor("UV2", TYPE.Vec2, Usage.Out),
+ new ParameterDescriptor("Grid", TYPE.Vec4, Usage.Out),
+ new ParameterDescriptor("Weights", TYPE.Vec4, Usage.Out)
+ },
+ new string[]
+ {
+ "\"Packages/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/Imposter.hlsl\""
+ }
+ ),new(
+ "OneFrame",
+" ImposterUV_oneFrame(Pos, inUV, Frames, Offset, Size, FrameClip, HemiSphere, Parallax, HeightMapChannel, " +
+ " Sampler.samplerstate, Texture.tex, TextureSize, OutPos, UV0, Grid);",
+ new ParameterDescriptor[]
+ {
+ new ParameterDescriptor("Pos", TYPE.Vec3, Usage.In, REF.ObjectSpace_Position),
+ new ParameterDescriptor("inUV", TYPE.Vec2, Usage.In, REF.UV0),
+ new ParameterDescriptor("Frames", TYPE.Int, Usage.In, new float[] {16}),
+ new ParameterDescriptor("Size", TYPE.Float, Usage.In, new float[] {1}),
+ new ParameterDescriptor("Offset", TYPE.Vec3, Usage.In),
+ new ParameterDescriptor("FrameClip", TYPE.Float, Usage.In),
+ new ParameterDescriptor("TextureSize", TYPE.Int, Usage.In, new float[]{ 1024}),
+ new ParameterDescriptor("HemiSphere", TYPE.Bool, Usage.In),
+ new ParameterDescriptor("Parallax", TYPE.Float, Usage.In),
+ new ParameterDescriptor("Texture", TYPE.Texture2D, Usage.In),
+ new ParameterDescriptor("Sampler", TYPE.SamplerState, Usage.In),
+ new ParameterDescriptor("HeightMapChannel", TYPE.Int, Usage.In, 3),//TODO: this one should be a dropdown with r/g/b/a chnnal options like Parallax Mapping node
+ new ParameterDescriptor("OutPos", TYPE.Vec3, Usage.Out),
+ new ParameterDescriptor("UV0", TYPE.Vec2, Usage.Out),
+ new ParameterDescriptor("Grid", TYPE.Vec4, Usage.Out)
+ },
+ new string[]
+ {
+ "\"Packages/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/Imposter.hlsl\""
+ }
+ )
+ }
+ );
+
+ public static NodeUIDescriptor NodeUIDescriptor => new(
+ Version,
+ Name,
+ displayName: "Imposter UV",
+ tooltip: "Calculates the billboard positon and the virtual UVs for sampling.",
+ category: "Utility",
+ hasPreview: false,
+ description: "pkg://Documentation~/previews/ImposterUV.md",
+ synonyms: new string[] { "billboard" },
+ selectableFunctions: new()
+ {
+ { "ThreeFrames", "Three Frames" },
+ { "OneFrame", "One Frame" }
+ },
+ functionSelectorLabel: "Sample Type",
+ parameters: new ParameterUIDescriptor[] {
+ new ParameterUIDescriptor(
+ name: "Pos",
+ displayName:"In Position",
+ options: REF.OptionList.Positions,
+ tooltip: "The postiont in Object space"
+ ),
+ new ParameterUIDescriptor(
+ name: "inUV",
+ displayName:"In UV",
+ options: REF.OptionList.UVs,
+ tooltip: "The UV coordinates of the mesh"
+ ),
+ new ParameterUIDescriptor(
+ name: "Frames",
+ tooltip: "The amount of the imposter frames"
+ ),
+ new ParameterUIDescriptor(
+ name: "Offest",
+ tooltip: "The offset value from the origin vertex positon"
+ ),
+ new ParameterUIDescriptor(
+ name: "FrameClip",
+ displayName:"Frame Clipping Threshold",
+ tooltip: "The value to clamp between imposter frame. Useful when doing parallax mapping."
+ ),
+ new ParameterUIDescriptor(
+ name: "TextureSize",
+ displayName:"Texture Size",
+ tooltip: "The resolution of the sampling texture."
+ ),
+ new ParameterUIDescriptor(
+ name: "Size",
+ tooltip: "The size of the imposter"
+ ),
+ new ParameterUIDescriptor(
+ name: "Hemisphere",
+ tooltip: "If it's true, calculate imposter grid and UVs base on hemisphere type."
+ ),
+ new ParameterUIDescriptor(
+ name: "Texture",
+ displayName:"Heightmap",
+ tooltip: "The texture asset to sample"
+ ),
+ new ParameterUIDescriptor(
+ name: "Sampler",
+ displayName:"Heightmap Sampler",
+ tooltip: "The texture sampler to use for sampling the texture"
+ ),
+ new ParameterUIDescriptor(
+ name: "Parallax",
+ tooltip: "Adds a parallax effect if the port value is greater than zero"
+ ),
+ new ParameterUIDescriptor(
+ name: "HeightMapChannel",
+ displayName:"Heighmap Sample Channel",
+ tooltip: "The texture channel to sample from for the parallax effect"
+ ),
+ new ParameterUIDescriptor(
+ name: "OutPos",
+ displayName:"Out Position",
+ tooltip: "The output billboard position."
+ ),
+ new ParameterUIDescriptor(
+ name: "UV0",
+ tooltip: "The virtual UV for the base frame"
+ ),
+ new ParameterUIDescriptor(
+ name: "UV1",
+ tooltip: "The virtual UV for the second frame"
+ ),
+ new ParameterUIDescriptor(
+ name: "UV2",
+ tooltip: "The virtual UV for the third frame"
+ ),
+ new ParameterUIDescriptor(
+ name: "Weights",
+ tooltip: "Blending weights for three frames"
+ ),
+ new ParameterUIDescriptor(
+ name: "Grid",
+ tooltip: "The current UV grid"
+ )
+ }
+ );
+ }
+}
diff --git a/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/ImposterUVNode.cs.meta b/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/ImposterUVNode.cs.meta
new file mode 100644
index 00000000000..f89ec0d890f
--- /dev/null
+++ b/com.unity.sg2/Editor/GraphDeltaRegistry/FunctionDefinitions/StandardDefinitions/Utility/ImposterUVNode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 983c760811aff784b9ceb86980c5eb57
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant: