Skip to content

Commit a2846e9

Browse files
AndrewSaraevUnitypastasfuture
authored andcommitted
Decal Scaling (#9)
* Apply lossy scale of a Decal Projector transform to handles and rendering in addition to the size. Doesn't support non-positive scale yet. * Support non-positive scale by Decal Projector handles. * Workaround for rendering of a Decal Projector with flipped scale. * Apply scale to a Decal Projector position offset to support scaling along the Z axis. * Fixed Decal Projector Angle Fade for scale with negative Z. * Cleaned up Decal Projector handles drawing.
1 parent cb17dc6 commit a2846e9

File tree

2 files changed

+99
-24
lines changed

2 files changed

+99
-24
lines changed

com.unity.render-pipelines.high-definition/Editor/Material/Decal/DecalProjectorEditor.cs

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,8 @@ void DrawHandles()
204204

205205
if (editMode == k_EditShapePreservingUV || editMode == k_EditShapeWithoutPreservingUV)
206206
{
207-
using (new Handles.DrawingScope(Color.white, Matrix4x4.TRS(decalProjector.transform.position, decalProjector.transform.rotation, Vector3.one)))
207+
Vector3 scale = decalProjector.transform.lossyScale;
208+
using (new Handles.DrawingScope(Color.white, Matrix4x4.TRS(decalProjector.transform.position, decalProjector.transform.rotation, scale)))
208209
{
209210
bool needToRefreshDecalProjector = false;
210211

@@ -223,8 +224,26 @@ void DrawHandles()
223224
// Adjust decal transform if handle changed.
224225
Undo.RecordObject(decalProjector, "Decal Projector Change");
225226

226-
decalProjector.size = handle.size;
227-
decalProjector.offset = handle.center;
227+
// Preserve serialized state for axes with scale 0.
228+
Vector3 newSize = decalProjector.size;
229+
Vector3 newOffset = decalProjector.offset;
230+
if (scale.x != 0f)
231+
{
232+
newSize.x = handle.size.x;
233+
newOffset.x = handle.center.x;
234+
}
235+
if (scale.y != 0f)
236+
{
237+
newSize.y = handle.size.y;
238+
newOffset.y = handle.center.y;
239+
}
240+
if (scale.z != 0f)
241+
{
242+
newSize.z = handle.size.z;
243+
newOffset.z = handle.center.z;
244+
}
245+
decalProjector.size = newSize;
246+
decalProjector.offset = newOffset;
228247

229248
Vector3 boundsSizeCurrentOS = handle.size;
230249
Vector3 boundsMinCurrentOS = handle.size * -0.5f + handle.center;
@@ -233,14 +252,19 @@ void DrawHandles()
233252
{
234253
// Treat decal projector bounds as a crop tool, rather than a scale tool.
235254
// Compute a new uv scale and bias terms to pin decal projection pixels in world space, irrespective of projector bounds.
255+
// Preserve serialized state for axes with scale 0.
236256
Vector2 uvScale = decalProjector.uvScale;
237-
uvScale.x *= Mathf.Max(1e-5f, boundsSizeCurrentOS.x) / Mathf.Max(1e-5f, boundsSizePreviousOS.x);
238-
uvScale.y *= Mathf.Max(1e-5f, boundsSizeCurrentOS.y) / Mathf.Max(1e-5f, boundsSizePreviousOS.y);
257+
if (scale.x != 0f)
258+
uvScale.x *= Mathf.Max(1e-5f, boundsSizeCurrentOS.x) / Mathf.Max(1e-5f, boundsSizePreviousOS.x);
259+
if (scale.y != 0f)
260+
uvScale.y *= Mathf.Max(1e-5f, boundsSizeCurrentOS.y) / Mathf.Max(1e-5f, boundsSizePreviousOS.y);
239261
decalProjector.uvScale = uvScale;
240262

241263
Vector2 uvBias = decalProjector.uvBias;
242-
uvBias.x += (boundsMinCurrentOS.x - boundsMinPreviousOS.x) / Mathf.Max(1e-5f, boundsSizeCurrentOS.x) * decalProjector.uvScale.x;
243-
uvBias.y += (boundsMinCurrentOS.y - boundsMinPreviousOS.y) / Mathf.Max(1e-5f, boundsSizeCurrentOS.y) * decalProjector.uvScale.y;
264+
if (scale.x != 0f)
265+
uvBias.x += (boundsMinCurrentOS.x - boundsMinPreviousOS.x) / Mathf.Max(1e-5f, boundsSizeCurrentOS.x) * decalProjector.uvScale.x;
266+
if (scale.y != 0f)
267+
uvBias.y += (boundsMinCurrentOS.y - boundsMinPreviousOS.y) / Mathf.Max(1e-5f, boundsSizeCurrentOS.y) * decalProjector.uvScale.y;
244268
decalProjector.uvBias = uvBias;
245269
}
246270

@@ -263,7 +287,7 @@ void DrawHandles()
263287
// Re-center the transform to the center of the decal projector bounds,
264288
// while maintaining the world-space coordinates of the decal projector boundings vertices.
265289
// Center of the decal projector is not the same of the HierarchicalBox as we want it to be on the z face as lights
266-
decalProjector.transform.Translate(decalProjector.offset + new Vector3(0f, 0f, handle.size.z * -0.5f), Space.Self);
290+
decalProjector.transform.Translate(Vector3.Scale(decalProjector.offset + new Vector3(0f, 0f, handle.size.z * -0.5f), scale), Space.Self);
267291

268292
decalProjector.offset = new Vector3(0f, 0f, handle.size.z * 0.5f);
269293
if (PrefabUtility.IsPartOfNonAssetPrefabInstance(decalProjector))
@@ -290,18 +314,22 @@ void DrawHandles()
290314
[DrawGizmo(GizmoType.Selected | GizmoType.Active)]
291315
static void DrawGizmosSelected(DecalProjector decalProjector, GizmoType gizmoType)
292316
{
293-
//draw them scale independent
317+
//draw them with scale applied to size and offset instead of TRS to keep proportions of the arrow and bold lines.
294318
using (new Handles.DrawingScope(Color.white, Matrix4x4.TRS(decalProjector.transform.position, decalProjector.transform.rotation, Vector3.one)))
295319
{
296-
handle.center = decalProjector.offset;
297-
handle.size = decalProjector.size;
320+
Vector3 scale = decalProjector.transform.lossyScale;
321+
Vector3 scaledOffset = Vector3.Scale(decalProjector.offset, scale);
322+
Vector3 scaledSize = Vector3.Scale(decalProjector.size, scale);
323+
324+
handle.center = scaledOffset;
325+
handle.size = scaledSize;
298326
bool inEditMode = editMode == k_EditShapePreservingUV || editMode == k_EditShapeWithoutPreservingUV;
299327
handle.DrawHull(inEditMode);
300328

301329
Quaternion arrowRotation = Quaternion.LookRotation(Vector3.down, Vector3.right);
302-
float arrowSize = decalProjector.size.z * 0.25f;
303-
Vector3 pivot = decalProjector.offset;
304-
Vector3 projectedPivot = pivot + decalProjector.size.z * 0.5f * Vector3.back;
330+
float arrowSize = scaledSize.z * 0.25f;
331+
Vector3 pivot = scaledOffset;
332+
Vector3 projectedPivot = pivot + scaledSize.z * 0.5f * Vector3.back;
305333
Handles.ArrowHandleCap(0, projectedPivot, Quaternion.identity, arrowSize, EventType.Repaint);
306334

307335
//[TODO: add editable pivot. Uncomment this when ready]
@@ -315,13 +343,13 @@ static void DrawGizmosSelected(DecalProjector decalProjector, GizmoType gizmoTyp
315343
//Handles.DrawLine(projectedPivot, projectedPivot + decalProjector.m_Size.z * 0.5f * Vector3.forward);
316344

317345
//draw UV and bolder edges
318-
using (new Handles.DrawingScope(Matrix4x4.TRS(decalProjector.transform.position - decalProjector.transform.rotation * (decalProjector.size * 0.5f + decalProjector.offset.z * Vector3.back), decalProjector.transform.rotation, Vector3.one)))
346+
using (new Handles.DrawingScope(Matrix4x4.TRS(decalProjector.transform.position - decalProjector.transform.rotation * (scaledSize * 0.5f + scaledOffset.z * Vector3.back), decalProjector.transform.rotation, Vector3.one)))
319347
{
320348
if (inEditMode)
321349
{
322350
Vector2 size = new Vector2(
323-
(decalProjector.uvScale.x > 100000 || decalProjector.uvScale.x < -100000 ? 0f : 1f / decalProjector.uvScale.x) * decalProjector.size.x,
324-
(decalProjector.uvScale.y > 100000 || decalProjector.uvScale.y < -100000 ? 0f : 1f / decalProjector.uvScale.y) * decalProjector.size.y
351+
(decalProjector.uvScale.x > 100000 || decalProjector.uvScale.x < -100000 ? 0f : 1f / decalProjector.uvScale.x) * scaledSize.x,
352+
(decalProjector.uvScale.y > 100000 || decalProjector.uvScale.y < -100000 ? 0f : 1f / decalProjector.uvScale.y) * scaledSize.y
325353
);
326354
Vector2 start = (Vector2)projectedPivot - new Vector2(decalProjector.uvBias.x * size.x, decalProjector.uvBias.y * size.y);
327355
Handles.DrawDottedLines(
@@ -335,7 +363,7 @@ static void DrawGizmosSelected(DecalProjector decalProjector, GizmoType gizmoTyp
335363
5f);
336364
}
337365

338-
Vector2 halfSize = decalProjector.size * .5f;
366+
Vector2 halfSize = scaledSize * .5f;
339367
Vector2 halfSize2 = new Vector2(halfSize.x, -halfSize.y);
340368
Vector2 center = (Vector2)projectedPivot + halfSize;
341369
Handles.DrawLine(center - halfSize, center - halfSize2, 3f);

com.unity.render-pipelines.high-definition/Runtime/Material/Decal/DecalProjector.cs

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ namespace UnityEngine.Rendering.HighDefinition
1616
public partial class DecalProjector : MonoBehaviour
1717
{
1818
internal static readonly Quaternion k_MinusYtoZRotation = Quaternion.Euler(-90, 0, 0);
19+
static readonly Quaternion k_YtoZRotation = Quaternion.Euler(90, 0, 0);
1920

2021
[SerializeField]
2122
private Material m_Material = null;
@@ -239,17 +240,63 @@ public float fadeFactor
239240
private DecalSystem.DecalHandle m_Handle = null;
240241

241242

242-
/// <summary>current rotation in a way the DecalSystem will be able to use it</summary>
243-
internal Quaternion rotation => transform.rotation * k_MinusYtoZRotation;
244243
/// <summary>current position in a way the DecalSystem will be able to use it</summary>
245244
internal Vector3 position => transform.position;
246-
/// <summary>current size in a way the DecalSystem will be able to use it</summary>
247-
internal Vector3 decalSize => new Vector3(m_Size.x, m_Size.z, m_Size.y);
248-
/// <summary>current size in a way the DecalSystem will be able to use it</summary>
249-
internal Vector3 decalOffset => new Vector3(m_Offset.x, -m_Offset.z, m_Offset.y);
250245
/// <summary>current uv parameters in a way the DecalSystem will be able to use it</summary>
251246
internal Vector4 uvScaleBias => new Vector4(m_UVScale.x, m_UVScale.y, m_UVBias.x, m_UVBias.y);
252247

248+
/// <summary>current rotation in a way the DecalSystem will be able to use it</summary>
249+
internal Quaternion rotation
250+
{
251+
get
252+
{
253+
// If Z-scale is negative we rotate decal differently to have correct forward direction for Angle Fade.
254+
return transform.rotation * (transform.lossyScale.z >= 0f ? k_MinusYtoZRotation : k_YtoZRotation);
255+
}
256+
}
257+
258+
/// <summary>current size in a way the DecalSystem will be able to use it</summary>
259+
internal Vector3 decalSize
260+
{
261+
get
262+
{
263+
Vector3 scale = transform.lossyScale;
264+
265+
// If Z-scale is negative the forward direction for rendering will be fixed by rotation,
266+
// so we need to flip the scale of the affected axes back.
267+
// The final sign of Z will depend on the other two axes, so we actually need to fix only Y here.
268+
if (scale.z < 0f)
269+
scale.y *= -1f;
270+
271+
// Flipped projector (with 1 or 3 negative components of scale) would be invisible.
272+
// In this case we additionally flip Z.
273+
bool flipped = scale.x < 0f ^ scale.y < 0f ^ scale.z < 0f;
274+
if (flipped)
275+
scale.z *= -1f;
276+
277+
return new Vector3(m_Size.x * scale.x, m_Size.z * scale.z, m_Size.y * scale.y);
278+
}
279+
}
280+
281+
/// <summary>current offset in a way the DecalSystem will be able to use it</summary>
282+
internal Vector3 decalOffset
283+
{
284+
get
285+
{
286+
Vector3 scale = transform.lossyScale;
287+
288+
// If Z-scale is negative the forward direction for rendering will be fixed by rotation,
289+
// so we need to flip the scale of the affected axes back.
290+
if (scale.z < 0f)
291+
{
292+
scale.y *= -1f;
293+
scale.z *= -1f;
294+
}
295+
296+
return new Vector3(m_Offset.x * scale.x, -m_Offset.z * scale.z, m_Offset.y * scale.y);
297+
}
298+
}
299+
253300
internal DecalSystem.DecalHandle Handle
254301
{
255302
get

0 commit comments

Comments
 (0)