Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ public class ScreenReflectionPipeline : Pipeline
{
private RenderTarget2D screenReflectionScreen; // 反射区域

protected virtual bool IncludeLocalPlayer => true;

protected virtual Matrix CaptureTransform => Matrix.Invert(Main.GameViewMatrix.TransformationMatrix);

public override void Load()
{
Ins.MainThread.AddTask(() =>
Expand Down Expand Up @@ -43,16 +47,17 @@ public override void BeginRender()
RasterizerState.CullNone);
spriteBatch.Draw(Main.screenTarget, Vector2.Zero, Color.White);
spriteBatch.End();
List<Player> players = new List<Player>() { Main.LocalPlayer };

// 外加玩家
Main.PlayerRenderer.DrawPlayers(Main.Camera, players);
if (IncludeLocalPlayer)
{
List<Player> players = new List<Player>() { Main.LocalPlayer };
Main.PlayerRenderer.DrawPlayers(Main.Camera, players);
}

graphicsDevice.SetRenderTarget(screenReflectionScreen);

// 以另一种方法绘制保存下来的屏幕
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.PointClamp, DepthStencilState.Default,
RasterizerState.CullNone, null, Matrix.Invert(Main.GameViewMatrix.TransformationMatrix));
RasterizerState.CullNone, null, CaptureTransform);
spriteBatch.Draw(Main.screenTargetSwap, Vector2.Zero, Color.White);
spriteBatch.End();

Expand All @@ -67,6 +72,14 @@ public override void BeginRender()
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Additive, SamplerState.PointClamp, DepthStencilState.None,
RasterizerState.CullNone);

ApplyReflectionEffect();
Main.graphics.GraphicsDevice.Textures[0] = screenReflectionScreen;
Main.graphics.GraphicsDevice.SamplerStates[0] = SamplerState.PointWrap;
Main.graphics.GraphicsDevice.SamplerStates[1] = SamplerState.PointClamp;
}

protected virtual void ApplyReflectionEffect()
{
Effect ef = Commons.ModAsset.ScreenReflection_NormalColor.Value;
var viewport = Main.graphics.GraphicsDevice.Viewport;

Expand All @@ -85,9 +98,6 @@ public override void BeginRender()
ef.Parameters["uViewProj"].SetValue(Main.GameViewMatrix.TransformationMatrix * projection);

ef.CurrentTechnique.Passes["Test"].Apply();
Main.graphics.GraphicsDevice.Textures[0] = screenReflectionScreen;
Main.graphics.GraphicsDevice.SamplerStates[0] = SamplerState.PointWrap;
Main.graphics.GraphicsDevice.SamplerStates[1] = SamplerState.PointClamp;
}

public override void Render(IEnumerable<IVisual> visuals)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

namespace Everglow.Yggdrasil.YggdrasilTown.NPCs.KingJellyBall;

[Pipeline(typeof(ScreenReflectionPipeline))]
[Pipeline(typeof(KingJellyBall_ReflectionPipeline))]
public class KingJellyBall_Reflection : Visual
{
public override CodeLayer DrawLayer => CodeLayer.PostDrawProjectiles;
public override CodeLayer DrawLayer => CodeLayer.PreDrawFilter;

public NPC MyKingJellyBallOwner;

Expand Down Expand Up @@ -51,20 +51,24 @@ public override void Draw()
Active = false;
return;
}

var textureOld = Main.graphics.GraphicsDevice.Textures[1];
Main.graphics.GraphicsDevice.Textures[1] = ModAsset.KingJellyBall_Reflect.Value;
float timeValue = (float)Main.time * 0.03f;
List<MirrorFaceVertex> jellyBallBodyInner = new List<MirrorFaceVertex>();

// adjust center base on the polar funtion graph.
Vector2 offset = new Vector2(0, -60) + new Vector2(0, -120 * (Scale - 0.3f));
Vector2 offsetedCenter = Position + offset;
Effect reflection = ModAsset.KingJellyBall_SurfaceReflection.Value;
float bodyAsymmetry = 110 + 10 * MathF.Sin(timeValue);
reflection.Parameters["uSurfaceCenter"].SetValue(offsetedCenter + new Vector2(0, 1.3f * bodyAsymmetry * Scale) - Main.screenPosition);
reflection.Parameters["uSurfaceScale"].SetValue(Scale);
reflection.Parameters["uTime"].SetValue(Main.GlobalTimeWrappedHourly);
reflection.Parameters["uRippleStrength"].SetValue(0.65f);
reflection.CurrentTechnique.Passes["Test"].Apply();
int step = 150;
for (int theta = 0; theta <= step; theta++)
{
float a = 200;
float b = 110 + 10 * MathF.Sin(timeValue);
float b = bodyAsymmetry;
float angle = theta / (float)step * MathHelper.TwoPi;
float r = a - b * MathF.Sin(angle);

Expand All @@ -79,22 +83,9 @@ public override void Draw()
Vector2 toDistance = new Vector2(-r, 0).RotatedBy(angle);
toDistance.Y *= 1.3f;
Vector2 width = Vector2.Normalize(toDistance) * 2f;
jellyBallBodyInner.Add(new MirrorFaceVertex(new Vector3(offsetedCenter, -150), new Color(0.4f, 0.6f, 1f, 0.5f), new Vector3(0.5f, 0.5f, 0)));
jellyBallBodyInner.Add(new MirrorFaceVertex(new Vector3(offsetedCenter + toDistance - width, -10), new Color(0.7f, 0.7f, 1f, 1f), new Vector3(new Vector2(0.5f) + new Vector2(-0.27f, 0).RotatedBy(angle), 0)));
}
if (jellyBallBodyInner.Count >= 2)
{
Main.graphics.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, jellyBallBodyInner.ToArray(), 0, jellyBallBodyInner.Count - 2);
}
else
{
jellyBallBodyInner.Add(new MirrorFaceVertex(new Vector3(0), new Color(0.5f, 0.5f, 0.5f), new Vector3(0.5f, 0.5f, 0)));
jellyBallBodyInner.Add(new MirrorFaceVertex(new Vector3(0), new Color(0.5f, 0.5f, 0.5f), new Vector3(0.5f, 0.5f, 0)));
jellyBallBodyInner.Add(new MirrorFaceVertex(new Vector3(0), new Color(0.5f, 0.5f, 0.5f), new Vector3(0.5f, 0.5f, 0)));
jellyBallBodyInner.Add(new MirrorFaceVertex(new Vector3(0), new Color(0.5f, 0.5f, 0.5f), new Vector3(0.5f, 0.5f, 0)));

Main.graphics.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, jellyBallBodyInner.ToArray(), 0, jellyBallBodyInner.Count - 2);
jellyBallBodyInner.Add(new MirrorFaceVertex(new Vector3(offsetedCenter, -1), new Color(0.4f, 0.6f, 1f, 0.5f), new Vector3(0.5f, 0.5f, 0)));
jellyBallBodyInner.Add(new MirrorFaceVertex(new Vector3(offsetedCenter + toDistance - width, -1), new Color(0.7f, 0.7f, 1f, 1f), new Vector3(new Vector2(0.5f) + new Vector2(-0.27f, 0).RotatedBy(angle), 0)));
}
Main.graphics.GraphicsDevice.Textures[1] = textureOld;
Main.graphics.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, jellyBallBodyInner.ToArray(), 0, jellyBallBodyInner.Count - 2);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace Everglow.Yggdrasil.YggdrasilTown.NPCs.KingJellyBall;

public class KingJellyBall_ReflectionPipeline : ScreenReflectionPipeline
{
// PreDrawFilter captures the completed scene, including all players.
protected override bool IncludeLocalPlayer => false;

protected override Matrix CaptureTransform => Matrix.Identity;

public override void BeginRender()
{
base.BeginRender();
Main.graphics.GraphicsDevice.SamplerStates[0] = SamplerState.LinearClamp;
}

protected override void ApplyReflectionEffect()
{
Effect reflection = ModAsset.KingJellyBall_SurfaceReflection.Value;
var viewport = Main.graphics.GraphicsDevice.Viewport;
var projection = Matrix.CreateOrthographicOffCenter(0, viewport.Width, viewport.Height, 0, 0, 500);
reflection.Parameters["uModel"].SetValue(Matrix.CreateTranslation(new Vector3(-Main.screenPosition, 0)));
reflection.Parameters["uViewProj"].SetValue(Main.GameViewMatrix.TransformationMatrix * projection);
reflection.Parameters["uScreenTransform"].SetValue(Main.GameViewMatrix.TransformationMatrix);
reflection.Parameters["uViewportSize"].SetValue(new Vector2(viewport.Width, viewport.Height));
reflection.Parameters["uFresnelF0"].SetValue(new Vector3(0.17f));
reflection.Parameters["uKs"].SetValue(Vector3.One);
reflection.CurrentTechnique.Passes["Test"].Apply();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
sampler uScreenBuffer : register(s0);

float3 uFresnelF0;
float3 uKs;
float2 uViewportSize;
float4x4 uModel;
float4x4 uViewProj;
float4x4 uScreenTransform;
float2 uSurfaceCenter;
float uSurfaceScale;
float uTime;
float uRippleStrength;

struct VSInput
{
float3 Pos : POSITION0;
float4 Color : COLOR0;
float3 Texcoord : TEXCOORD0;
};

struct PSInput
{
float4 Pos : SV_POSITION;
float4 Color : COLOR0;
float2 SurfacePosition : TEXCOORD0;
};

PSInput VertexShaderFunction(VSInput input)
{
PSInput output;
float4 position = mul(float4(input.Pos, 1), uModel);
output.Pos = mul(position, uViewProj);
output.SurfacePosition = position.xy;
output.Color = input.Color;
return output;
}

float4 PixelShaderFunction(PSInput input) : COLOR0
{
float scale = max(uSurfaceScale, 0.01);
float2 localPosition = input.SurfacePosition - uSurfaceCenter;
float2 radii = float2(260, 280) * scale;
float2 surface = localPosition / radii;
float radiusSquared = dot(surface, surface);
if (radiusSquared >= 1)
return 0;

// A convex ellipsoidal cap facing the camera. The source plane is z = 0;
// the cap is closest at its center. Depth and normal describe the same surface.
float cap = sqrt(max(1 - radiusSquared, 0.0025));
float depth = scale * (12 + 70 * (1 - cap));
float2 gradient = 70 * scale * surface / (radii * cap);

// Smooth traveling waves perturb both height and its analytic derivatives.
// Coordinates scale with the body, so shrinking cannot amplify the distortion.
float2 wavePosition = localPosition / scale;
float2 frequency0 = float2(0.035, 0.022);
float2 frequency1 = float2(-0.018, 0.041);
float phase0 = dot(wavePosition, frequency0) - uTime * 1.8;
float phase1 = dot(wavePosition, frequency1) + uTime * 1.3;
depth += scale * uRippleStrength * (0.65 * sin(phase0) + 0.35 * sin(phase1));
gradient += uRippleStrength * (0.65 * cos(phase0) * frequency0 + 0.35 * cos(phase1) * frequency1);

// All positions and derivatives use screen axes: positive Y points down.
float3 normal = normalize(float3(gradient, 1));
float3 reflected = reflect(float3(0, 0, -1), normal);
float visibility = smoothstep(0.12, 0.3, reflected.z);
float2 sourcePosition = input.SurfacePosition + depth * reflected.xy / max(reflected.z, 0.12);

// Keep the captured image in screen space; transform the intersection once.
float2 screenPosition = mul(float4(sourcePosition, 0, 1), uScreenTransform).xy;
float2 edgeDistance = min(screenPosition, uViewportSize - screenPosition);
visibility *= smoothstep(0, 8, min(edgeDistance.x, edgeDistance.y));
float2 uv = clamp(screenPosition / uViewportSize, 0.5 / uViewportSize, 1 - 0.5 / uViewportSize);

float3 fresnel = uFresnelF0 + (1 - uFresnelF0) * pow(saturate(1 - normal.z), 5);
float3 scene = pow(max(tex2D(uScreenBuffer, uv).rgb, 0), 2.2);
float3 color = pow(max(scene * uKs * fresnel, 0), 1 / 2.2);
return float4(color, 1) * input.Color * visibility;
}

technique Technique1
{
pass Test
{
VertexShader = compile vs_3_0 VertexShaderFunction();
PixelShader = compile ps_3_0 PixelShaderFunction();
}
}
Loading