#include "shared/point.hlsl" #include "shared/quat-functions.hlsl" #include "shared/hash-functions.hlsl" static const float4 Corners[] = { // px py u v float4(-1, -1, 0,1), float4( 1, -1, 1,1), float4( 1, 1, 1,0), float4( 1, 1, 1,0), float4(-1, 1, 0,0), float4(-1, -1, 0,1), }; cbuffer Params : register(b0) { float Style; float Complexity; float Gamma; float ScatterDistribution; float ScatterLength; float ScatterBrightness; float Colorize; float CoreBrightness; float CircularCompletion; float CircularCompletionEdge; float Time; float UseRGSSMultiSampling; float TargetWidth; float TargetHeight; float CompletionAffectsLength; }; cbuffer Transforms : register(b1) { float4x4 CameraToClipSpace; float4x4 ClipSpaceToCamera; float4x4 WorldToCamera; float4x4 CameraToWorld; float4x4 WorldToClipSpace; float4x4 ClipSpaceToWorld; float4x4 ObjectToWorld; float4x4 WorldToObject; float4x4 ObjectToCamera; float4x4 ObjectToClipSpace; }; struct psInput { float4 position : SV_POSITION; float4 color : COLOR; float2 texCoord : TEXCOORD; float spriteIndex : COLOR1; float rotation: ROTATION; }; struct Sprite { float2 PosInClipSpace; float2 Size; float Rotation; float4 Color; float2 UvMin; float2 UvMax; float3 __padding; }; sampler WrappedSampler : register(s0); sampler ClampedSampler : register(s1); StructuredBuffer Sprites : t0; Texture2D NoiseImage : register(t1); Texture2D Gradient : register(t2); static const float ShimmerStyle = 0; static const float SparkleStyle = 1; static const float TextureStyle = 2; float3 hsb2rgb(float3 c) { float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www); return c.z < 0.5 ? //float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www); c.z*2 * lerp(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y) : lerp(K.xxx, clamp(p - K.xxx, 0.0, 1.0), lerp(c.y, 0, (c.z * 2 - 1) ) ); } psInput vsMain(uint id: SV_VertexID) { psInput output; float discardFactor = 1; int cornerIndex = id % 6; int particleId = id / 6; output.spriteIndex = particleId; float4 cornerFactors = Corners[cornerIndex]; float4 aspect = float4(CameraToClipSpace[1][1] / CameraToClipSpace[0][0],1,1,1); Sprite sprite = Sprites[particleId]; float2 corner = float2(cornerFactors.x * sprite.Size.x, cornerFactors.y * sprite.Size.y); float imageRotationRad = (-sprite.Rotation - 90) / 180 * PI; float sina = sin(-imageRotationRad - PI/2); float cosa = cos(-imageRotationRad - PI/2); corner = float2( cosa * corner.x - sina * corner.y, cosa * corner.y + sina * corner.x ); float2 p = float2( corner.x / aspect.x + sprite.PosInClipSpace.x, corner.y + sprite.PosInClipSpace.y); output.position = float4(p, 0,1); output.rotation = sprite.Rotation; output.texCoord = lerp(sprite.UvMin, sprite.UvMax, cornerFactors.zw); output.color = sprite.Color; return output; } float remap(float value, float inMin, float inMax, float outMin, float outMax) { float factor = (value - inMin) / (inMax - inMin); float v = factor * (outMax - outMin) + outMin; return v; } static const float SimmerComplexitFactor = 100; static float _rotation = 0; float4 ComputeShimmer(float2 p, float spriteIndex) { float2 Center = 0; float d = length(p) * 2; float angle = (atan2(p.x, p.y)) / (2*PI)+0.5; // Scatter distribution... float distributrionComplexity = Complexity / SimmerComplexitFactor; float angleForFx = (angle + _rotation/360 + 0.5) % 1; float2 noiseAPos = float2(angleForFx * distributrionComplexity + spriteIndex*0.1, angleForFx*0.2 + Time*0.1 + spriteIndex * 0.2); float4 noiseA = NoiseImage.SampleLevel(WrappedSampler, noiseAPos, 0.0) * 1; float distributionOffset = (noiseA.r - 0.5) * ScatterDistribution / Complexity*2; angleForFx += distributionOffset; angleForFx %= 1; // Noise for other effects float4 noiseB = NoiseImage.SampleLevel(WrappedSampler, float2( angleForFx * Complexity / SimmerComplexitFactor + spriteIndex * 0.2, angleForFx*0.3 + Time*-0.11 + spriteIndex * 0.13 ), 0.0); float brightness = 1-pow(d, 1+Gamma); // Completion float c2 = CircularCompletion/720; float cEdge = CircularCompletionEdge/720; float cc= smoothstep(c2+cEdge, c2, angle) + smoothstep(1-c2- cEdge, 1-c2, angle); brightness *= lerp(1, (noiseB.b), ScatterBrightness) * cc; float completionRatio = CircularCompletion/360; brightness += pow( 1-d, lerp(50, 20, completionRatio) ) * CoreBrightness * pow(completionRatio,0.1); brightness = pow(brightness, Gamma); // Colorize float4 randomColor = float4(noiseB.rbg,1); randomColor.xyz /= length(randomColor.xyz); float4 colorOut = float4(brightness.xxx * lerp(1,randomColor.rgb, Colorize),1); float2 uv = float2(d + (noiseB.g - 0.5) * ScatterLength, 0.75); colorOut *= Gradient.Sample(ClampedSampler, uv); return clamp(colorOut,0,1000); } float4 ComputeSparkle(float2 p, float spriteIndex) { float2 Center = 0; float angle = (atan2(p.x, p.y)) / (2*PI)+0.5; float2 noisePos = float2(angle * Complexity/64 + spriteIndex*0.1, angle*0.2 + Time*0.1 + spriteIndex * 0.2); float4 noiseA = NoiseImage.SampleLevel(WrappedSampler, noisePos, 0.0) * 1; float noiseDistort = (noiseA.r - 0.5) * ScatterDistribution/Complexity; angle += noiseDistort; float c2 = CircularCompletion/720; float cEdge = CircularCompletionEdge/720; float cc= (smoothstep(c2+cEdge/2, c2-cEdge/2, angle) + smoothstep(1-c2- cEdge/2, 1-c2+cEdge/2, angle)); // return float4( // smoothstep(c2+cEdge/2, c2-cEdge/2, angle), // smoothstep(1-c2- cEdge/2, 1-c2+cEdge/2, angle), // 0,1); float repeatFraction = 1/Complexity; float segments = angle * Complexity; float segmentF = segments % 1; float segmentIndex = segments - segmentF; float mappedGamma = 0.8- Gamma /2; float d = length(p) * 2; float constantLineWidthOffset = 0.5- mappedGamma/d; float segmentFill = abs(segmentF - 0.5) * 2 + constantLineWidthOffset; float filled = smoothstep(mappedGamma + 0.4, mappedGamma, segmentFill); float4 segmentNoise = NoiseImage.SampleLevel(WrappedSampler, float2( (segmentIndex / Complexity*173.1236) %1 + spriteIndex * 0.213 - Time*0.14, Time*0.2 + segmentIndex *0.14 ), 0.0); float segmentD = (d + (segmentNoise.r-0.5) * ScatterLength) / lerp(1, cc, CompletionAffectsLength); float4 gradient= Gradient.Sample(ClampedSampler, float2(1-segmentD, 0.25)); filled *= 1+ (segmentNoise.r - 0.5) * ScatterBrightness; // Colorize float4 randomColor = float4(segmentNoise.rbg,1); randomColor.xyz /= length(randomColor.xyz); gradient.xyz *= lerp(1, randomColor.xyz, Colorize); float4 colorOut = gradient * filled; colorOut.a *= cc; //return float4(randomColor.rgb,1) ; //d= gradient.r; // float brightness = pow(1-d,3); // brightness *= lerp(1, (noiseB.b), ScatterBrightness) * cc; //float completionRatio = CircularCompletion/360; //brightness += pow(1-d, lerp(50, 20, completionRatio) ) * CoreBrightness * pow(completionRatio,0.1); // brightness = pow(brightness, Gamma); // float4 colorOut = float4(brightness.xxx * lerp(1,noiseB.rgb, Colorize),1); // colorOut *= float4(1,0,0,1); //float4 colorOut = float4(x.xxx,1); return clamp(colorOut,0,1000); } float4 psMain(psInput input) : SV_TARGET { float2 p = input.texCoord; p -= 0.5; _rotation = input.rotation; //return float4(_rotation/360, 0,0,1); float4 colorOut =0; float d = length(p) * 2; if(d > 1) return 0; if(Style < 0.5) { //float4 gradient= Gradient.SampleLevel(WrappedSampler,1-d,0); //d= gradient.r; if(UseRGSSMultiSampling) { // 4x rotated grid float4 offsets[2]; offsets[0] = float4(-0.375, 0.125, 0.125, 0.375); offsets[1] = float4(0.375, -0.125, -0.125, -0.375); float2 sxy = float2(TargetWidth, TargetHeight); float4 colorOut4 = ComputeShimmer(p + offsets[0].xy / sxy, input.spriteIndex)+ ComputeShimmer(p + offsets[0].zw / sxy, input.spriteIndex)+ ComputeShimmer(p + offsets[1].xy / sxy, input.spriteIndex)+ ComputeShimmer(p + offsets[1].zw / sxy, input.spriteIndex); float4 colorOutB = colorOut4 /4 * input.color; return clamp(float4(colorOutB.rgb, colorOutB.a), 0, float4(1000,1000,1000,1)); } colorOut = ComputeShimmer(p, input.spriteIndex) * input.color; } else { float4 gradient= Gradient.SampleLevel(WrappedSampler,1-d,0); d= gradient.r; if(UseRGSSMultiSampling) { // 4x rotated grid float4 offsets[2]; offsets[0] = float4(-0.375, 0.125, 0.125, 0.375); offsets[1] = float4(0.375, -0.125, -0.125, -0.375); float2 sxy = float2(TargetWidth, TargetHeight); float4 colorOut4 = ComputeSparkle(p + offsets[0].xy / sxy, input.spriteIndex)+ ComputeSparkle(p + offsets[0].zw / sxy, input.spriteIndex)+ ComputeSparkle(p + offsets[1].xy / sxy, input.spriteIndex)+ ComputeSparkle(p + offsets[1].zw / sxy, input.spriteIndex); float4 colorOutB = colorOut4 * input.color /4; return clamp(float4(colorOutB.rgb, colorOutB.a), 0, float4(1000,1000,1000,1)); } colorOut = ComputeSparkle(p, input.spriteIndex) * input.color; } return clamp(float4(colorOut.rgb, colorOut.a), 0, float4(1000,1000,1000,1)); }