Implement sun & moon

This commit is contained in:
Drew DeVault 2016-04-20 20:54:00 -04:00
parent 528eb2c5f4
commit e5aaf73d12
8 changed files with 257 additions and 7 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -46,16 +46,17 @@ namespace TrueCraft.Client.Modules
OpaqueEffect.TextureEnabled = true;
OpaqueEffect.Texture = Game.TextureMapper.GetTexture("terrain.png");
OpaqueEffect.FogEnabled = true;
OpaqueEffect.FogStart = 512f;
OpaqueEffect.FogEnd = 1000f;
OpaqueEffect.FogColor = Color.CornflowerBlue.ToVector3();
OpaqueEffect.FogStart = 0;
OpaqueEffect.FogEnd = Game.Camera.Frustum.Far.D * 0.8f;
OpaqueEffect.VertexColorEnabled = true;
OpaqueEffect.LightingEnabled = true;
TransparentEffect = new AlphaTestEffect(Game.GraphicsDevice);
TransparentEffect.AlphaFunction = CompareFunction.Greater;
TransparentEffect.ReferenceAlpha = 127;
TransparentEffect.Texture = Game.TextureMapper.GetTexture("terrain.png");
TransparentEffect.VertexColorEnabled = true;
OpaqueEffect.LightingEnabled = true;
ChunkMeshes = new List<ChunkMesh>();
IncomingChunks = new ConcurrentBag<Mesh>();
@ -164,8 +165,11 @@ namespace TrueCraft.Client.Modules
public void Draw(GameTime gameTime)
{
OpaqueEffect.FogColor = Game.SkyModule.WorldFogColor.ToVector3();
Game.Camera.ApplyTo(OpaqueEffect);
Game.Camera.ApplyTo(TransparentEffect);
OpaqueEffect.AmbientLightColor = TransparentEffect.DiffuseColor = Color.White.ToVector3()
* new Microsoft.Xna.Framework.Vector3(0.25f + Game.SkyModule.BrightnessModifier);
int chunks = 0;
Game.GraphicsDevice.DepthStencilState = DepthStencilState.Default;

View File

@ -0,0 +1,233 @@
using Microsoft.Xna.Framework;
using System;
using Microsoft.Xna.Framework.Graphics;
namespace TrueCraft.Client.Modules
{
public class SkyModule : IGraphicalModule
{
// https://github.com/SirCmpwn/TrueCraft/wiki/Sky
private TrueCraftGame Game { get; set; }
private BasicEffect SkyPlaneEffect { get; set; }
private BasicEffect CelestialPlaneEffect { get; set; }
private VertexBuffer SkyPlane { get; set; }
private VertexBuffer CelestialPlane { get; set; }
public SkyModule(TrueCraftGame game)
{
Game = game;
CelestialPlaneEffect = new BasicEffect(Game.GraphicsDevice);
CelestialPlaneEffect.TextureEnabled = true;
SkyPlaneEffect = new BasicEffect(Game.GraphicsDevice);
SkyPlaneEffect.VertexColorEnabled = false;
SkyPlaneEffect.FogEnabled = true;
SkyPlaneEffect.FogStart = 0;
SkyPlaneEffect.FogEnd = 64 * 0.8f;
SkyPlaneEffect.LightingEnabled = true;
var plane = new[]
{
new VertexPositionColor(new Vector3(-64, 0, -64), Color.White),
new VertexPositionColor(new Vector3(64, 0, -64), Color.White),
new VertexPositionColor(new Vector3(-64, 0, 64), Color.White),
new VertexPositionColor(new Vector3(64, 0, -64), Color.White),
new VertexPositionColor(new Vector3(64, 0, 64), Color.White),
new VertexPositionColor(new Vector3(-64, 0, 64), Color.White)
};
SkyPlane = new VertexBuffer(Game.GraphicsDevice, VertexPositionColor.VertexDeclaration,
plane.Length, BufferUsage.WriteOnly);
SkyPlane.SetData<VertexPositionColor>(plane);
var celestialPlane = new[]
{
new VertexPositionTexture(new Vector3(-60, 0, -60), new Vector2(0, 0)),
new VertexPositionTexture(new Vector3(60, 0, -60), new Vector2(1, 0)),
new VertexPositionTexture(new Vector3(-60, 0, 60), new Vector2(0, 1)),
new VertexPositionTexture(new Vector3(60, 0, -60), new Vector2(1, 0)),
new VertexPositionTexture(new Vector3(60, 0, 60), new Vector2(1, 1)),
new VertexPositionTexture(new Vector3(-60, 0, 60), new Vector2(0, 1))
};
CelestialPlane = new VertexBuffer(Game.GraphicsDevice, VertexPositionTexture.VertexDeclaration,
celestialPlane.Length, BufferUsage.WriteOnly);
CelestialPlane.SetData<VertexPositionTexture>(celestialPlane);
}
private float CelestialAngle
{
get
{
float x = (Game.Client.World.Time % 24000f) / 24000f - 0.25f;
if (x < 0) x = 0;
if (x > 1) x = 1;
return x + ((1 - ((float)Math.Cos(x * MathHelper.Pi) + 1) / 2) - x) / 3;
}
}
public static Color HSL2RGB(float h, float sl, float l)
{
// Thanks http://www.java2s.com/Code/CSharp/2D-Graphics/HSLtoRGBconversion.htm
float v, r, g, b;
r = g = b = l; // default to gray
v = (l <= 0.5f) ? (l * (1.0f + sl)) : (l + sl - l * sl);
if (v > 0)
{
int sextant;
float m, sv, fract, vsf, mid1, mid2;
m = l + l - v;
sv = (v - m) / v;
h *= 6.0f;
sextant = (int)h;
fract = h - sextant;
vsf = v * sv * fract;
mid1 = m + vsf;
mid2 = v - vsf;
switch (sextant)
{
case 0:
r = v; g = mid1; b = m;
break;
case 1:
r = mid2; g = v; b = m;
break;
case 2:
r = m; g = v; b = mid1;
break;
case 3:
r = m; g = mid2; b = v;
break;
case 4:
r = mid1; g = m; b = v;
break;
case 5:
r = v; g = m; b = mid2;
break;
}
}
return new Color(r, g, b);
}
private Color BaseColor
{
get
{
// Note: temperature comes from the current biome, but we have to
// do biomes differently than Minecraft so we'll un-hardcode this later.
const float temp = 0.8f / 3;
return HSL2RGB(0.6222222f - temp * 0.05f, 0.5f + temp * 0.1f, BrightnessModifier);
}
}
public float BrightnessModifier
{
get
{
var mod = (float)Math.Cos(CelestialAngle * MathHelper.TwoPi) * 2 + 0.5f;
if (mod < 0) mod = 0;
if (mod > 1) mod = 1;
return mod;
}
}
public Color WorldSkyColor
{
get
{
return BaseColor;
}
}
public Color WorldFogColor
{
get
{
float y = (float)Math.Cos(CelestialAngle * MathHelper.TwoPi) * 2 + 0.5f;
return new Color(0.7529412f * y * 0.94f + 0.06f,
0.8470588f * y * 0.94f + 0.06f, 1.0f * y * 0.91f + 0.09f);
}
}
public Color AtmosphereColor
{
get
{
const float blendFactor = 0.29f; // TODO: Compute based on view distance
Func<float, float, float> blend = (float source, float destination) =>
destination + (source - destination) * blendFactor;
var fog = WorldFogColor.ToVector3();
var sky = WorldSkyColor.ToVector3();
var color = new Vector3(blend(sky.X, fog.X), blend(sky.Y, fog.Y), blend(sky.Z, fog.Z));
// TODO: more stuff
return new Color(color);
}
}
public void Draw(GameTime gameTime)
{
Game.GraphicsDevice.Clear(AtmosphereColor);
Game.GraphicsDevice.SetVertexBuffer(SkyPlane);
var position = Game.Camera.Position;
var yaw = Game.Camera.Yaw;
Game.Camera.Position = TrueCraft.API.Vector3.Zero;
Game.Camera.Yaw = 0;
Game.Camera.ApplyTo(SkyPlaneEffect);
Game.Camera.Yaw = yaw;
Game.Camera.ApplyTo(CelestialPlaneEffect);
Game.Camera.Position = position;
// Sky
SkyPlaneEffect.FogColor = AtmosphereColor.ToVector3();
SkyPlaneEffect.World = Matrix.CreateRotationX(MathHelper.Pi)
* Matrix.CreateTranslation(0, 100, 0)
* Matrix.CreateRotationX(MathHelper.TwoPi * CelestialAngle);
SkyPlaneEffect.AmbientLightColor = WorldSkyColor.ToVector3(); foreach (var pass in SkyPlaneEffect.CurrentTechnique.Passes)
{
pass.Apply();
SkyPlaneEffect.GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);
}
// Sun
Game.GraphicsDevice.SetVertexBuffer(CelestialPlane);
var backup = Game.GraphicsDevice.BlendState;
Game.GraphicsDevice.BlendState = BlendState.Additive;
Game.GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
CelestialPlaneEffect.Texture = Game.TextureMapper.GetTexture("terrain/sun.png");
CelestialPlaneEffect.World = Matrix.CreateRotationX(MathHelper.Pi)
* Matrix.CreateTranslation(0, 100, 0)
* Matrix.CreateRotationX(MathHelper.TwoPi * CelestialAngle);
foreach (var pass in CelestialPlaneEffect.CurrentTechnique.Passes)
{
pass.Apply();
CelestialPlaneEffect.GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);
}
// Moon
CelestialPlaneEffect.Texture = Game.TextureMapper.GetTexture("terrain/moon.png");
CelestialPlaneEffect.World = Matrix.CreateTranslation(0, -100, 0)
* Matrix.CreateRotationX(MathHelper.TwoPi * CelestialAngle);
foreach (var pass in CelestialPlaneEffect.CurrentTechnique.Passes)
{
pass.Apply();
CelestialPlaneEffect.GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);
}
Game.GraphicsDevice.BlendState = backup;
Game.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
// Void
Game.GraphicsDevice.SetVertexBuffer(SkyPlane);
SkyPlaneEffect.World = Matrix.CreateTranslation(0, -16, 0);
SkyPlaneEffect.AmbientLightColor = WorldSkyColor.ToVector3()
* new Vector3(0.2f, 0.2f, 0.6f)
+ new Vector3(0.04f, 0.04f, 0.1f);
foreach (var pass in SkyPlaneEffect.CurrentTechnique.Passes)
{
pass.Apply();
SkyPlaneEffect.GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);
}
}
public void Update(GameTime gameTime)
{
}
}
}

View File

@ -15,6 +15,8 @@ namespace TrueCraft.Client
internal World World { get; set; }
public long Time { get { return World.Time; } }
internal ReadOnlyWorld()
{
World = new World("default");

View File

@ -36,6 +36,8 @@ namespace TrueCraft.Client.Rendering
Defaults.Add("gui/crafting.png", new PngReader().Read(File.OpenRead("Content/crafting.png"), graphicsDevice));
Defaults.Add("gui/furnace.png", new PngReader().Read(File.OpenRead("Content/furnace.png"), graphicsDevice));
Defaults.Add("gui/inventory.png", new PngReader().Read(File.OpenRead("Content/inventory.png"), graphicsDevice));
Defaults.Add("terrain/moon.png", new PngReader().Read(File.OpenRead("Content/moon.png"), graphicsDevice));
Defaults.Add("terrain/sun.png", new PngReader().Read(File.OpenRead("Content/sun.png"), graphicsDevice));
}
/// <summary>

View File

@ -151,6 +151,7 @@
<Compile Include="AudioManager.cs" />
<Compile Include="Modules\ChatModule.cs" />
<Compile Include="Modules\WindowModule.cs" />
<Compile Include="Modules\SkyModule.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
@ -379,6 +380,12 @@
<Link>OpenTK.dll.config</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Content\moon.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Content\sun.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup />
</Project>

View File

@ -42,6 +42,7 @@ namespace TrueCraft.Client
public AudioManager Audio { get; set; }
public Texture2D White1x1 { get; set; }
public PlayerControlModule ControlModule { get; set; }
public SkyModule SkyModule { get; set; }
private List<IGameplayModule> InputModules { get; set; }
private List<IGameplayModule> GraphicalModules { get; set; }
@ -121,18 +122,23 @@ namespace TrueCraft.Client
base.Initialize(); // (calls LoadContent)
Camera = new Camera(GraphicsDevice.Viewport.AspectRatio, 70.0f, 0.1f, 1000.0f);
UpdateCamera();
White1x1 = new Texture2D(GraphicsDevice, 1, 1);
White1x1.SetData<Color>(new[] { Color.White });
Audio = new AudioManager();
Audio.LoadDefaultPacks(Content);
SkyModule = new SkyModule(this);
ChunkModule = new ChunkModule(this);
DebugInfoModule = new DebugInfoModule(this, Pixel);
ChatModule = new ChatModule(this, Pixel);
var hud = new HUDModule(this, Pixel);
var windowModule = new WindowModule(this, Pixel);
GraphicalModules.Add(SkyModule);
GraphicalModules.Add(ChunkModule);
GraphicalModules.Add(new HighlightModule(this));
GraphicalModules.Add(hud);
@ -161,9 +167,6 @@ namespace TrueCraft.Client
var centerY = GraphicsDevice.Viewport.Height / 2;
Mouse.SetPosition(centerX, centerY);
Camera = new Camera(GraphicsDevice.Viewport.AspectRatio, 70.0f, 0.1f, 1000.0f);
UpdateCamera();
MouseComponent.Scroll += OnMouseComponentScroll;
MouseComponent.Move += OnMouseComponentMove;
MouseComponent.ButtonDown += OnMouseComponentButtonDown;
@ -397,7 +400,6 @@ namespace TrueCraft.Client
GraphicsDevice.SetRenderTarget(RenderTarget);
GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
Graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
GraphicsDevice.SamplerStates[0] = SamplerState.PointClamp;
GraphicsDevice.SamplerStates[1] = SamplerState.PointClamp;