270 lines
8.1 KiB
HLSL
270 lines
8.1 KiB
HLSL
#include "shared/point.hlsl"
|
|
#include "shared/quat-functions.hlsl"
|
|
#include "shared/hash-functions.hlsl"
|
|
|
|
static const float3 Corners[] =
|
|
{
|
|
float3(-1, -1, 0),
|
|
float3(1, -1, 0),
|
|
float3(1, 1, 0),
|
|
float3(1, 1, 0),
|
|
float3(-1, 1, 0),
|
|
float3(-1, -1, 0),
|
|
};
|
|
|
|
cbuffer Transforms : register(b0)
|
|
{
|
|
float4x4 CameraToClipSpace;
|
|
float4x4 ClipSpaceToCamera;
|
|
float4x4 WorldToCamera;
|
|
float4x4 CameraToWorld;
|
|
float4x4 WorldToClipSpace;
|
|
float4x4 ClipSpaceToWorld;
|
|
float4x4 ObjectToWorld;
|
|
float4x4 WorldToObject;
|
|
float4x4 ObjectToCamera;
|
|
float4x4 ObjectToClipSpace;
|
|
};
|
|
|
|
cbuffer Params : register(b1)
|
|
{
|
|
float Scale;
|
|
float2 Stretch;
|
|
float __padding;
|
|
|
|
float3 Offset;
|
|
float OrientationMode;
|
|
|
|
float Rotate;
|
|
float3 RotationAxis;
|
|
|
|
float Randomize;
|
|
float RandomPhase;
|
|
float RandomRotate;
|
|
float __padding0;
|
|
|
|
float3 RandomPosition;
|
|
float RandomScale;
|
|
|
|
float4 Color;
|
|
|
|
float ColorVariationMode;
|
|
float ScaleDistribution;
|
|
float SpreadLength;
|
|
float SpreadPhase;
|
|
|
|
float SpreadPingPong;
|
|
float SpreadRepeat;
|
|
float2 AtlasSize;
|
|
|
|
float TextureAtlasMode;
|
|
float FxTextureMode;
|
|
float AlphaCutOff;
|
|
float IsFxTextureConnected;
|
|
|
|
// float __padding1; // order adjusted for 4x4 padding
|
|
|
|
float4 FxTextureAmount;
|
|
|
|
float UseRotationAsRgba;
|
|
|
|
float UseWFoScale;
|
|
float UseScale;
|
|
float TooCloseFadeOut;
|
|
};
|
|
|
|
cbuffer FogParams : register(b2)
|
|
{
|
|
float4 FogColor;
|
|
float FogDistance;
|
|
float FogBias;
|
|
}
|
|
|
|
struct psInput
|
|
{
|
|
float4 position : SV_POSITION;
|
|
float4 color : COLOR;
|
|
float2 texCoord : TEXCOORD;
|
|
float fog : FOG;
|
|
};
|
|
|
|
sampler texSampler : register(s0);
|
|
|
|
StructuredBuffer<Point> Points : t0;
|
|
Texture2D<float4> SpriteTexture : register(t1);
|
|
Texture2D<float4> FxTexture : register(t2);
|
|
Texture2D<float4> ColorOverW : register(t3);
|
|
Texture2D<float4> SizeOverW : register(t4);
|
|
|
|
inline float fmod(float x, float y)
|
|
{
|
|
return (x - y * floor(x / y));
|
|
}
|
|
|
|
inline float GetUFromMode(float mode, int id, float f, float4 scatter, float w, float fog)
|
|
{
|
|
switch ((int)(mode + 0.5))
|
|
{
|
|
|
|
case 0:
|
|
return scatter.w;
|
|
|
|
case 1:
|
|
return hash11u(id);
|
|
|
|
case 2:
|
|
float f1 = (f + SpreadPhase) / SpreadLength;
|
|
f1 = SpreadRepeat > 0.5 ? fmod(f1, 1) : f1;
|
|
return SpreadPingPong > 0.5 ? (1 - abs(f1 * 2 - 1)) : f1;
|
|
|
|
case 3:
|
|
float w1 = (w + SpreadPhase) / SpreadLength;
|
|
w1 = SpreadRepeat > 0.5 ? fmod(w1, 1) : w1;
|
|
return SpreadPingPong > 0.5 ? (1 - abs(w1 * 2 - 1)) : w1;
|
|
|
|
default:
|
|
return fog;
|
|
}
|
|
}
|
|
|
|
psInput vsMain(uint id : SV_VertexID)
|
|
{
|
|
uint particleCount, stride;
|
|
Points.GetDimensions(particleCount, stride);
|
|
|
|
uint width, height, mips;
|
|
SpriteTexture.GetDimensions(0, width, height, mips);
|
|
float2 textureAspect = width > height ? float2((float)width / height, 1)
|
|
: float2(1, (float)height / width);
|
|
|
|
psInput output;
|
|
|
|
uint quadIndex = id % 6;
|
|
uint pointId = id / 6;
|
|
float3 cornerFactors = Corners[quadIndex];
|
|
|
|
Point p = Points[pointId];
|
|
|
|
float4 pRotation = normalize(p.Rotation);
|
|
float f = pointId / (float)particleCount;
|
|
|
|
float phase = RandomPhase + 133.1123 * f;
|
|
int phaseId = (int)phase;
|
|
|
|
float4 normalizedScatter = lerp(hash41u(pointId * 12341 + phaseId),
|
|
hash41u(pointId * 12341 + phaseId + 1),
|
|
smoothstep(0, 1, phase - phaseId));
|
|
|
|
float3 scatterForScale = normalizedScatter.xyx * 2 - 1;
|
|
|
|
output.fog = 0;
|
|
|
|
int2 atlasSize = (int2)AtlasSize;
|
|
|
|
float textureUx = GetUFromMode(TextureAtlasMode, (pointId * atlasSize.x), (f * atlasSize.x) % 1, normalizedScatter, (p.FX1 * atlasSize.x) % 1, output.fog) % atlasSize.x;
|
|
float textureUy = GetUFromMode(TextureAtlasMode, pointId, f, normalizedScatter.wxyz, p.FX1, output.fog);
|
|
|
|
int textureCelX = textureUx * atlasSize.x;
|
|
int textureCelY = textureUy * atlasSize.y;
|
|
output.texCoord = (cornerFactors.xy * float2(-1, 1) * 0.5 + 0.5);
|
|
output.texCoord /= atlasSize;
|
|
output.texCoord += float2(textureCelX, textureCelY) / atlasSize;
|
|
|
|
float4 posInObject = float4(p.Position, 1);
|
|
|
|
float3 randomOffset = qRotateVec3((normalizedScatter.xyz - 0.5) * 2 * RandomPosition * Randomize, pRotation);
|
|
posInObject.xyz += randomOffset;
|
|
|
|
if (OrientationMode <= 1.5)
|
|
{
|
|
posInObject.xyz += qRotateVec3(float3(0, 0, Offset.z), pRotation);
|
|
}
|
|
|
|
float4 quadPosInCamera = mul(posInObject, ObjectToCamera);
|
|
|
|
// Shrink too close particles
|
|
float4 posInCamera = mul(posInObject, ObjectToCamera);
|
|
float tooCloseFactor = saturate(-posInCamera.z / 0.1 - 1);
|
|
|
|
output.fog = pow(saturate(-posInCamera.z / FogDistance), FogBias);
|
|
|
|
float4 colorFromPoint = (UseRotationAsRgba > 0.5) ? pRotation : 1;
|
|
|
|
float colorFxU = GetUFromMode(ColorVariationMode, pointId, f, normalizedScatter, p.FX1, output.fog);
|
|
if (TooCloseFadeOut > 0.5)
|
|
{
|
|
p.Color.a *= tooCloseFactor; // fade out the points too close to the camera
|
|
}
|
|
|
|
output.color = p.Color * Color * ColorOverW.SampleLevel(texSampler, float2(colorFxU, 0), 0) * colorFromPoint;
|
|
|
|
float adjustedRotate = Rotate;
|
|
float adjustedScale = Scale;
|
|
float adjustedRandomize = Randomize;
|
|
|
|
if (IsFxTextureConnected)
|
|
{
|
|
float4 centerPos = mul(float4(quadPosInCamera.xyz, 1), CameraToClipSpace);
|
|
centerPos.xyz /= centerPos.w;
|
|
|
|
float4 fxColor = FxTexture.SampleLevel(texSampler, (centerPos.xy * float2(1, -1) + 1) / 2, 0);
|
|
|
|
if (FxTextureMode < 0.5)
|
|
{
|
|
output.color *= fxColor;
|
|
}
|
|
else
|
|
{
|
|
adjustedRotate += FxTextureAmount.r * fxColor.r * fxColor.a * 360;
|
|
adjustedScale += FxTextureAmount.g * fxColor.g * fxColor.a;
|
|
adjustedRandomize += FxTextureAmount.b * fxColor.b * fxColor.a;
|
|
}
|
|
}
|
|
|
|
// Scale and stretch
|
|
float scaleFxU = GetUFromMode(ScaleDistribution, pointId, f, normalizedScatter, p.FX1, output.fog);
|
|
float scaleFromCurve = SizeOverW.SampleLevel(texSampler, float2(scaleFxU, 0), 0).r;
|
|
float hideUndefinedPoints = isnan(p.FX1) ? 0 : (UseWFoScale > 0.5 ? p.FX1 : 1);
|
|
// float computedScale = adjustedScale * (RandomScale * scatterForScale.y *adjustedRandomize + 1) * tooCloseFactor * scaleFromCurve * hideUndefinedPoints;
|
|
float computedScale = adjustedScale * (RandomScale * scatterForScale.y * adjustedRandomize + 1) * scaleFromCurve * hideUndefinedPoints;
|
|
output.position = 0;
|
|
|
|
if (OrientationMode <= 1.5)
|
|
{
|
|
float2 corner = float2((cornerFactors.xy + Offset.xy) * 0.010 * Stretch * (UseScale > 0.5 ? p.Scale.xy : 1) * textureAspect) * float2(-1, -1);
|
|
float4 rot = qFromAngleAxis((adjustedRotate + RandomRotate * scatterForScale.x * adjustedRandomize) * 3.141578 / 180, RotationAxis);
|
|
|
|
if ((int)OrientationMode == 1)
|
|
{
|
|
float3 yRotated = qRotateVec3(float3(0, 1, 0), pRotation);
|
|
float4 yRotatedInCam = mul(float4(yRotated, 1), ObjectToCamera);
|
|
float a = atan2(yRotatedInCam.x, yRotatedInCam.y);
|
|
float4 xx = qFromAngleAxis(-a, float3(0, 0, 1));
|
|
rot = qMul(xx, rot);
|
|
}
|
|
|
|
corner = qRotateVec3(float3(corner, 0), rot).xy;
|
|
output.position = mul(quadPosInCamera + float4(corner * computedScale, 0, 0), CameraToClipSpace);
|
|
}
|
|
else
|
|
{
|
|
float3 axis = (cornerFactors + Offset) * 0.010 * float3(Stretch * (UseScale > 0.5 ? p.Scale.xy : 1) * textureAspect, 1);
|
|
float4 rotation = qMul(normalize(pRotation), qFromAngleAxis((adjustedRotate + 180 + RandomRotate * scatterForScale.x * Randomize) / 180 * PI, RotationAxis));
|
|
axis = qRotateVec3(axis, rotation) * computedScale;
|
|
output.position = mul(posInObject + float4(axis, 0), ObjectToClipSpace);
|
|
}
|
|
return output;
|
|
}
|
|
|
|
float4 psMain(psInput input) : SV_TARGET
|
|
{
|
|
float4 imgColor = SpriteTexture.Sample(texSampler, input.texCoord);
|
|
float4 color = input.color * imgColor;
|
|
|
|
if (color.a < AlphaCutOff)
|
|
discard;
|
|
|
|
color.rgb = lerp(color.rgb, FogColor.rgb, input.fog * FogColor.a);
|
|
return clamp(color, 0, float4(100, 100, 100, 1));
|
|
}
|