Files
UnrealEngine/Engine/Plugins/TextureGraph/Shaders/Expressions/Expression_Transform.usf
2025-05-18 13:04:45 +08:00

161 lines
5.1 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#include "/Engine/Public/Platform.ush"
#include "/Plugin/TextureGraph/SamplerStates.ush"
#include "/Plugin/TextureGraph/TileInfo.ush"
#include "/Plugin/TextureGraph/Paint.ush"
Texture2D SourceTexture;
float4 FillColor;
float CoverageX;
float CoverageY;
float TranslationX;
float TranslationY;
float PivotX;
float PivotY;
float RotationX;
float RotationY;
float ScaleX;
float ScaleY;
float FilterMode;
float MirrorX;
float MirrorY;
float StaggerX;
float StaggerY;
float StrideX;
float StrideY;
float Zoom;
float StretchToFit;
float SpacingX;
float SpacingY;
float CellScaling;
float BlendDebugGrid;
float MaskBox(in float2 uv, in float2 minValue, in float2 maxValue)
{
float2 masked = step(minValue, uv) * step(uv, maxValue);
return min(masked.x, masked.y);
}
float MaskBox(in float2 uv, in float minValue, in float maxValue)
{
return MaskBox(uv, float2(minValue, minValue), float2(maxValue, maxValue));
}
float4 FSH_TransformBlit(float2 uv : TEXCOORD0) : SV_Target0
{
float2 layerPos = TileInfo_fromCurrentTileToLayer(uv);
float2 layerResolution = TileInfo_layerResolution();
float2 pixelSize = rcp(layerResolution);
float LayerAspectRatio = layerResolution.x/layerResolution.y;
float2 Coverage = float2(CoverageX, CoverageY);
float2 Translation = float2(TranslationX, TranslationY);
float2 Pivot = float2(PivotX, PivotY) * Coverage; // Pivot is applied in the normalized Coverage rectangle
float2 Rotation = float2(RotationX, RotationY);
float2 Scale = float2(ScaleX, ScaleY);
float2 Stagger = float2(StaggerX, StaggerY);
int2 Stride = int2(StrideX, StrideY);
// TilePos is the going to be the uv of the pixel on which we are going to apply the transformation steps
// Frst of all flip the y to work with Y up
float2 tilePos = float2(layerPos.x, 1.0 - layerPos.y);
// Apply translation
tilePos -= Translation;
// Apply the pivot and rotation
tilePos -= Pivot;
tilePos = float2(dot(tilePos, Rotation), dot(tilePos, float2(-Rotation.y, Rotation.x)));
tilePos += Pivot;
// eval the tile grid mask for debug
float tileGridMask = Paint_Grid(tilePos, 1.0, length(pixelSize) * 4);
// Eval the coverage mask, wrap it on the neighboor tiles or not
float2 filteredTilePos = (FilterMode > 0.0 ? frac(tilePos) : tilePos);
float CoverageMask = MaskBox(filteredTilePos, 0, Coverage);
// focus on the cell domain inside of the tile
float2 cellPos = tilePos - floor(tilePos);
// eval debug mask for coverage box and the Pivot point
float coverageGridMask = CoverageMask * Paint_BoxEdge(cellPos, 0, Coverage, 0, pixelSize * 3);
float pivotMask = Paint_BoxEdge(tilePos, Pivot, Pivot, pixelSize * 6, -pixelSize * 3);
// Aspect ratio of the uv space is going follow scaling transformations
float UVAspectRatio = 1.0;
// apply coverage scaling
cellPos /= Coverage;
UVAspectRatio *= (Coverage.x / Coverage.y);
pixelSize /= Coverage;
// apply scaling
cellPos *= Scale;
UVAspectRatio *= (Scale.y / Scale.x);
pixelSize *= Scale;
// apply stagger
cellPos -= floor(cellPos).yx * Stagger;
// Eval the staggered grid for debug
float stagGridMask = CoverageMask * Paint_BoxEdge(cellPos, 0, 1.0, 0.0, pixelSize * 2.5 );
// apply stride effect as a mask
int2 cellTilePos = int2(floor(cellPos)); // this is the cell tile coordinate
int2 StrideCell = (cellTilePos % (1 + Stride));
float StrideMask = (float((StrideCell.x == 0) && (StrideCell.y == 0)));
// Eval spacing as a stretching to respect the aspect ratio or not
float2 spacing = lerp(float2(0, 1 - (UVAspectRatio)), float2(1 - rcp(UVAspectRatio), 0), (UVAspectRatio > 1.0));
spacing = lerp(spacing, float2(SpacingX, SpacingY), StretchToFit);
// Eval the spaced cell pos
// we do a simple remap of the cellPos from [half_spacing, 1 - half_spacing] to [0, 1]
float2 spacedCellPos = ( (cellPos - cellTilePos) - spacing * 0.5) / (1 - spacing);
// and a last scaling to apply the zoom control
float scaling = rcp(max(length(pixelSize), Zoom));
spacedCellPos = ((spacedCellPos * 2 - 1) * scaling) * 0.5 + 0.5;
// Eval the cell grid masked for debug
float cellGridMask = CoverageMask * Paint_BoxEdge(spacedCellPos, 0, 1.0, -pixelSize * 0.5, pixelSize * 1.25);
// also compute the mask for spacedCell and exclude anything out of the [0,1] box
float CellMask = MaskBox(spacedCellPos, 0, 1);
CoverageMask *= CellMask;
// Finally fetch the source texture
float2 fetchPos = spacedCellPos;
// Apply mirroring to uvs
fetchPos.x = lerp(fetchPos.x, 1.0 - fetchPos.x, MirrorX);
fetchPos.y = lerp(1.0 - fetchPos.y, fetchPos.y, MirrorY);
float4 SourceColor = float4(0, 0, 0, 1);
SourceColor = SourceTexture.Sample(SamplerStates_Linear_Wrap, fetchPos);
float4 Color = lerp(FillColor, SourceColor, (CoverageMask * StrideMask * SourceColor.a));
Color = lerp(Color, float4(1, 1, 0, 1), BlendDebugGrid * tileGridMask);
Color = lerp(Color, float4(0, 1, 1, 1), BlendDebugGrid * coverageGridMask);
//Color = lerp(Color, float4(1, 0.5, 0, 1), BlendDebugGrid * stagGridMask);
Color = lerp(Color, float4(1, 0, 1, 1), BlendDebugGrid * cellGridMask);
Color = lerp(Color, float4(0, 1, 1, 1), BlendDebugGrid * pivotMask);
return Color;
}