API update
parent
beb9a4dff0
commit
922e4cf0f1
Binary file not shown.
|
@ -1 +1 @@
|
||||||
Subproject commit d2fca3654bd90817885f0006058cccd6437da22c
|
Subproject commit 111df04c0f7be740108cc3536eda3629572714d8
|
Binary file not shown.
|
@ -1,11 +1,12 @@
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using MoonWorks.Math;
|
||||||
|
|
||||||
namespace MoonWorksTest
|
namespace MoonWorksTest
|
||||||
{
|
{
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
struct Vertex
|
struct PositionTexture
|
||||||
{
|
{
|
||||||
public float x, y, z;
|
public Vector3 Position;
|
||||||
public float u, v;
|
public Vector2 Texture;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
|
using MoonWorks;
|
||||||
using MoonWorks.Graphics;
|
using MoonWorks.Graphics;
|
||||||
using MoonWorks.Window;
|
|
||||||
|
|
||||||
namespace MoonWorksTest
|
namespace MoonWorksTest
|
||||||
{
|
{
|
||||||
|
@ -15,7 +15,13 @@ namespace MoonWorksTest
|
||||||
ScreenMode = ScreenMode.Windowed
|
ScreenMode = ScreenMode.Windowed
|
||||||
};
|
};
|
||||||
|
|
||||||
TestGame game = new TestGame(windowCreateInfo, PresentMode.FIFO, 60, true);
|
TestGame game = new TestGame(
|
||||||
|
windowCreateInfo,
|
||||||
|
PresentMode.FIFO,
|
||||||
|
60,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
game.Run();
|
game.Run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
295
src/TestGame.cs
295
src/TestGame.cs
|
@ -2,9 +2,8 @@ using MoonWorks;
|
||||||
using MoonWorks.Audio;
|
using MoonWorks.Audio;
|
||||||
using MoonWorks.Graphics;
|
using MoonWorks.Graphics;
|
||||||
using MoonWorks.Input;
|
using MoonWorks.Input;
|
||||||
using MoonWorks.Window;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace MoonWorksTest
|
namespace MoonWorksTest
|
||||||
{
|
{
|
||||||
|
@ -20,28 +19,20 @@ namespace MoonWorksTest
|
||||||
|
|
||||||
Buffer vertexBuffer;
|
Buffer vertexBuffer;
|
||||||
|
|
||||||
Rect renderArea;
|
|
||||||
Rect flip;
|
|
||||||
Color clearColor;
|
Color clearColor;
|
||||||
DepthStencilValue depthStencilClear;
|
|
||||||
|
|
||||||
Texture mainColorTargetTexture;
|
|
||||||
TextureSlice mainColorTargetTextureSlice;
|
|
||||||
RenderTarget mainColorTarget;
|
|
||||||
|
|
||||||
RenderPass mainRenderPass;
|
|
||||||
Framebuffer mainFramebuffer;
|
|
||||||
GraphicsPipeline mainGraphicsPipeline;
|
GraphicsPipeline mainGraphicsPipeline;
|
||||||
|
|
||||||
byte[] screenshotPixels;
|
byte[] screenshotPixels;
|
||||||
Buffer screenshotBuffer;
|
Buffer screenshotBuffer;
|
||||||
uint screenShotBufferSize;
|
uint screenshotBufferSize;
|
||||||
Thread screenshotThread;
|
|
||||||
|
|
||||||
StaticSound music;
|
StaticSound music;
|
||||||
StaticSoundInstance musicInstance;
|
StaticSoundInstance musicInstance;
|
||||||
StreamingSoundOgg musicStream;
|
StreamingSoundOgg musicStream;
|
||||||
|
|
||||||
|
bool screenshotInProgress = false;
|
||||||
|
|
||||||
public TestGame(WindowCreateInfo windowCreateInfo, PresentMode presentMode, int targetTimestep = 60, bool debugMode = false) : base(windowCreateInfo, presentMode, targetTimestep, debugMode)
|
public TestGame(WindowCreateInfo windowCreateInfo, PresentMode presentMode, int targetTimestep = 60, bool debugMode = false) : base(windowCreateInfo, presentMode, targetTimestep, debugMode)
|
||||||
{
|
{
|
||||||
var windowWidth = windowCreateInfo.WindowWidth;
|
var windowWidth = windowCreateInfo.WindowWidth;
|
||||||
|
@ -64,206 +55,60 @@ namespace MoonWorksTest
|
||||||
|
|
||||||
/* Load Vertex Data */
|
/* Load Vertex Data */
|
||||||
|
|
||||||
var vertices = new Vertex[3];
|
var vertices = new PositionTexture[3];
|
||||||
vertices[0].x = -1;
|
vertices[0].Position.X = -1;
|
||||||
vertices[0].y = -1;
|
vertices[0].Position.Y = -1;
|
||||||
vertices[0].z = 0;
|
vertices[0].Position.Z = 0;
|
||||||
vertices[0].u = 0;
|
vertices[0].Texture.X = 0;
|
||||||
vertices[0].v = 1;
|
vertices[0].Texture.Y = 1;
|
||||||
|
|
||||||
vertices[1].x = 3;
|
vertices[1].Position.X = 3;
|
||||||
vertices[1].y = -1;
|
vertices[1].Position.Y = -1;
|
||||||
vertices[1].z = 0;
|
vertices[1].Position.Z = 0;
|
||||||
vertices[1].u = 1;
|
vertices[1].Texture.X = 1;
|
||||||
vertices[1].v = 1;
|
vertices[1].Texture.Y = 1;
|
||||||
|
|
||||||
vertices[2].x = -1;
|
vertices[2].Position.X = -1;
|
||||||
vertices[2].y = 3;
|
vertices[2].Position.Y = 3;
|
||||||
vertices[2].z = 0;
|
vertices[2].Position.Z = 0;
|
||||||
vertices[2].u = 0;
|
vertices[2].Texture.X = 0;
|
||||||
vertices[2].v = 0;
|
vertices[2].Texture.Y = 0;
|
||||||
|
|
||||||
vertexBuffer = new Buffer(GraphicsDevice, BufferUsageFlags.Vertex, 4 * 5 * 3);
|
vertexBuffer = Buffer.Create<PositionTexture>(GraphicsDevice, BufferUsageFlags.Vertex, 3);
|
||||||
uploadCommandBuffer.SetBufferData(vertexBuffer, vertices);
|
uploadCommandBuffer.SetBufferData(vertexBuffer, vertices);
|
||||||
|
|
||||||
GraphicsDevice.Submit(uploadCommandBuffer);
|
GraphicsDevice.Submit(uploadCommandBuffer);
|
||||||
|
|
||||||
/* Render Pass */
|
|
||||||
|
|
||||||
renderArea.X = 0;
|
|
||||||
renderArea.Y = 0;
|
|
||||||
renderArea.W = (int) windowWidth;
|
|
||||||
renderArea.H = (int) windowHeight;
|
|
||||||
|
|
||||||
flip.X = 0;
|
|
||||||
flip.Y = (int) windowHeight;
|
|
||||||
flip.W = (int) windowWidth;
|
|
||||||
flip.H = -(int) windowHeight;
|
|
||||||
|
|
||||||
clearColor.R = 237;
|
|
||||||
clearColor.G = 41;
|
|
||||||
clearColor.B = 57;
|
|
||||||
clearColor.A = byte.MaxValue;
|
|
||||||
|
|
||||||
ColorTargetDescription colorTargetDescription = new ColorTargetDescription
|
|
||||||
{
|
|
||||||
Format = TextureFormat.R8G8B8A8,
|
|
||||||
MultisampleCount = SampleCount.One,
|
|
||||||
LoadOp = LoadOp.Clear,
|
|
||||||
StoreOp = StoreOp.Store
|
|
||||||
};
|
|
||||||
|
|
||||||
mainRenderPass = new RenderPass(GraphicsDevice, colorTargetDescription);
|
|
||||||
|
|
||||||
mainColorTargetTexture = Texture.CreateTexture2D(
|
|
||||||
GraphicsDevice,
|
|
||||||
windowWidth,
|
|
||||||
windowHeight,
|
|
||||||
TextureFormat.R8G8B8A8,
|
|
||||||
TextureUsageFlags.ColorTarget
|
|
||||||
);
|
|
||||||
|
|
||||||
mainColorTargetTextureSlice = new TextureSlice(mainColorTargetTexture);
|
|
||||||
mainColorTarget = new RenderTarget(GraphicsDevice, mainColorTargetTextureSlice);
|
|
||||||
|
|
||||||
mainFramebuffer = new Framebuffer(
|
|
||||||
GraphicsDevice,
|
|
||||||
windowWidth,
|
|
||||||
windowHeight,
|
|
||||||
mainRenderPass,
|
|
||||||
null,
|
|
||||||
mainColorTarget
|
|
||||||
);
|
|
||||||
|
|
||||||
/* Pipeline */
|
/* Pipeline */
|
||||||
|
|
||||||
ColorTargetBlendState[] colorTargetBlendStates = new ColorTargetBlendState[1]
|
|
||||||
{
|
|
||||||
ColorTargetBlendState.None
|
|
||||||
};
|
|
||||||
|
|
||||||
ColorBlendState colorBlendState = new ColorBlendState
|
|
||||||
{
|
|
||||||
LogicOpEnable = false,
|
|
||||||
LogicOp = LogicOp.NoOp,
|
|
||||||
BlendConstants = new BlendConstants(),
|
|
||||||
ColorTargetBlendStates = colorTargetBlendStates
|
|
||||||
};
|
|
||||||
|
|
||||||
DepthStencilState depthStencilState = DepthStencilState.Disable;
|
|
||||||
|
|
||||||
ShaderStageState vertexShaderState = new ShaderStageState
|
|
||||||
{
|
|
||||||
ShaderModule = passthroughVertexShaderModule,
|
|
||||||
EntryPointName = "main",
|
|
||||||
UniformBufferSize = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
ShaderStageState fragmentShaderState = new ShaderStageState
|
|
||||||
{
|
|
||||||
ShaderModule = raymarchFragmentShaderModule,
|
|
||||||
EntryPointName = "main",
|
|
||||||
UniformBufferSize = 16
|
|
||||||
};
|
|
||||||
|
|
||||||
MultisampleState multisampleState = MultisampleState.None;
|
|
||||||
|
|
||||||
GraphicsPipelineLayoutInfo pipelineLayoutInfo = new GraphicsPipelineLayoutInfo
|
|
||||||
{
|
|
||||||
VertexSamplerBindingCount = 0,
|
|
||||||
FragmentSamplerBindingCount = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
RasterizerState rasterizerState = RasterizerState.CW_CullBack;
|
|
||||||
|
|
||||||
var vertexBindings = new VertexBinding[1]
|
|
||||||
{
|
|
||||||
new VertexBinding
|
|
||||||
{
|
|
||||||
Binding = 0,
|
|
||||||
InputRate = VertexInputRate.Vertex,
|
|
||||||
Stride = 4 * 5
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var vertexAttributes = new VertexAttribute[2]
|
|
||||||
{
|
|
||||||
new VertexAttribute
|
|
||||||
{
|
|
||||||
Binding = 0,
|
|
||||||
Location = 0,
|
|
||||||
Format = VertexElementFormat.Vector3,
|
|
||||||
Offset = 0
|
|
||||||
},
|
|
||||||
new VertexAttribute
|
|
||||||
{
|
|
||||||
Binding = 0,
|
|
||||||
Location = 1,
|
|
||||||
Format = VertexElementFormat.Vector2,
|
|
||||||
Offset = 4 * 3
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
VertexInputState vertexInputState = new VertexInputState
|
|
||||||
{
|
|
||||||
VertexBindings = vertexBindings,
|
|
||||||
VertexAttributes = vertexAttributes
|
|
||||||
};
|
|
||||||
|
|
||||||
var viewports = new Viewport[1]
|
|
||||||
{
|
|
||||||
new Viewport
|
|
||||||
{
|
|
||||||
X = 0,
|
|
||||||
Y = 0,
|
|
||||||
W = windowWidth,
|
|
||||||
H = windowHeight,
|
|
||||||
MinDepth = 0,
|
|
||||||
MaxDepth = 1
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var scissors = new Rect[1]
|
|
||||||
{
|
|
||||||
new Rect
|
|
||||||
{
|
|
||||||
X = 0,
|
|
||||||
Y = 0,
|
|
||||||
W = (int) windowWidth,
|
|
||||||
H = (int) windowHeight
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ViewportState viewportState = new ViewportState
|
|
||||||
{
|
|
||||||
Viewports = viewports,
|
|
||||||
Scissors = scissors
|
|
||||||
};
|
|
||||||
|
|
||||||
var graphicsPipelineCreateInfo = new GraphicsPipelineCreateInfo
|
|
||||||
{
|
|
||||||
ColorBlendState = colorBlendState,
|
|
||||||
DepthStencilState = depthStencilState,
|
|
||||||
VertexShaderState = vertexShaderState,
|
|
||||||
FragmentShaderState = fragmentShaderState,
|
|
||||||
MultisampleState = multisampleState,
|
|
||||||
PipelineLayoutInfo = pipelineLayoutInfo,
|
|
||||||
RasterizerState = rasterizerState,
|
|
||||||
PrimitiveType = PrimitiveType.TriangleList,
|
|
||||||
VertexInputState = vertexInputState,
|
|
||||||
ViewportState = viewportState,
|
|
||||||
RenderPass = mainRenderPass
|
|
||||||
};
|
|
||||||
|
|
||||||
mainGraphicsPipeline = new GraphicsPipeline(
|
mainGraphicsPipeline = new GraphicsPipeline(
|
||||||
GraphicsDevice,
|
GraphicsDevice,
|
||||||
graphicsPipelineCreateInfo
|
new GraphicsPipelineCreateInfo
|
||||||
|
{
|
||||||
|
AttachmentInfo = new GraphicsPipelineAttachmentInfo(
|
||||||
|
new ColorAttachmentDescription(
|
||||||
|
GraphicsDevice.GetSwapchainFormat(Window),
|
||||||
|
ColorAttachmentBlendState.None
|
||||||
|
)
|
||||||
|
),
|
||||||
|
DepthStencilState = DepthStencilState.Disable,
|
||||||
|
VertexShaderInfo = GraphicsShaderInfo.Create(passthroughVertexShaderModule, "main", 0),
|
||||||
|
VertexInputState = new VertexInputState(
|
||||||
|
VertexBinding.Create<PositionTexture>(),
|
||||||
|
VertexAttribute.Create<PositionTexture>("Position", 0),
|
||||||
|
VertexAttribute.Create<PositionTexture>("Texture", 1)
|
||||||
|
),
|
||||||
|
PrimitiveType = PrimitiveType.TriangleList,
|
||||||
|
FragmentShaderInfo = GraphicsShaderInfo.Create<RaymarchUniforms>(raymarchFragmentShaderModule, "main", 2),
|
||||||
|
RasterizerState = RasterizerState.CW_CullBack,
|
||||||
|
ViewportState = new ViewportState((int)Window.Width, (int)Window.Height),
|
||||||
|
MultisampleState = MultisampleState.None
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
screenShotBufferSize = windowWidth * windowHeight * 4;
|
screenshotBufferSize = windowWidth * windowHeight * 4;
|
||||||
screenshotPixels = new byte[screenShotBufferSize];
|
screenshotPixels = new byte[screenshotBufferSize];
|
||||||
screenshotBuffer = new Buffer(GraphicsDevice, 0, screenShotBufferSize);
|
screenshotBuffer = new Buffer(GraphicsDevice, 0, screenshotBufferSize);
|
||||||
screenshotThread = new Thread(new ThreadStart(SaveScreenshot));
|
|
||||||
|
|
||||||
music = StaticSound.LoadOgg(AudioDevice, Path.Combine("Content", "title_screen.ogg"));
|
music = StaticSound.LoadOgg(AudioDevice, Path.Combine("Content", "title_screen.ogg"));
|
||||||
musicInstance = music.CreateInstance();
|
musicInstance = music.CreateInstance();
|
||||||
|
@ -280,21 +125,20 @@ namespace MoonWorksTest
|
||||||
|
|
||||||
protected override void Draw(System.TimeSpan dt, double alpha)
|
protected override void Draw(System.TimeSpan dt, double alpha)
|
||||||
{
|
{
|
||||||
var screenshotPressed = Inputs.Keyboard.IsPressed(Keycode.S);
|
|
||||||
|
|
||||||
var commandBuffer = GraphicsDevice.AcquireCommandBuffer();
|
var commandBuffer = GraphicsDevice.AcquireCommandBuffer();
|
||||||
|
|
||||||
|
var swapchainTexture = commandBuffer.AcquireSwapchainTexture(Window);
|
||||||
|
var takeScreenshot = Inputs.Keyboard.IsPressed(Keycode.S) && !screenshotInProgress && (swapchainTexture != null);
|
||||||
|
|
||||||
|
if (swapchainTexture != null)
|
||||||
|
{
|
||||||
commandBuffer.BeginRenderPass(
|
commandBuffer.BeginRenderPass(
|
||||||
mainRenderPass,
|
new ColorAttachmentInfo(swapchainTexture, clearColor)
|
||||||
mainFramebuffer,
|
|
||||||
renderArea,
|
|
||||||
depthStencilClear,
|
|
||||||
clearColor.ToVector4()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
commandBuffer.BindGraphicsPipeline(mainGraphicsPipeline);
|
commandBuffer.BindGraphicsPipeline(mainGraphicsPipeline);
|
||||||
|
|
||||||
commandBuffer.BindVertexBuffers(0, new BufferBinding(vertexBuffer, 0));
|
commandBuffer.BindVertexBuffers(vertexBuffer);
|
||||||
commandBuffer.BindFragmentSamplers(
|
commandBuffer.BindFragmentSamplers(
|
||||||
new TextureSamplerBinding(woodTexture, sampler),
|
new TextureSamplerBinding(woodTexture, sampler),
|
||||||
new TextureSamplerBinding(noiseTexture, sampler)
|
new TextureSamplerBinding(noiseTexture, sampler)
|
||||||
|
@ -304,25 +148,46 @@ namespace MoonWorksTest
|
||||||
commandBuffer.DrawPrimitives(0, 1, 0, fragmentParamOffset);
|
commandBuffer.DrawPrimitives(0, 1, 0, fragmentParamOffset);
|
||||||
commandBuffer.EndRenderPass();
|
commandBuffer.EndRenderPass();
|
||||||
|
|
||||||
if (screenshotPressed)
|
if (takeScreenshot)
|
||||||
{
|
{
|
||||||
commandBuffer.CopyTextureToBuffer(mainColorTargetTextureSlice, screenshotBuffer);
|
commandBuffer.CopyTextureToBuffer(new TextureSlice(swapchainTexture), screenshotBuffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
commandBuffer.QueuePresent(mainColorTargetTextureSlice, flip, Filter.Nearest);
|
|
||||||
GraphicsDevice.Submit(commandBuffer);
|
GraphicsDevice.Submit(commandBuffer);
|
||||||
|
|
||||||
if (screenshotPressed)
|
if (takeScreenshot)
|
||||||
{
|
{
|
||||||
screenshotThread.Start();
|
Task.Run(() => SaveScreenshot());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveScreenshot()
|
private void SaveScreenshot()
|
||||||
{
|
{
|
||||||
|
screenshotInProgress = true;
|
||||||
|
|
||||||
|
var name = "MoonWorksTest-" + System.DateTime.Now.ToString("MM-dd-yyyy-hh-mm-ss") + ".png";
|
||||||
|
System.Console.WriteLine("Saving screenshot " + name + " ...");
|
||||||
|
|
||||||
GraphicsDevice.Wait();
|
GraphicsDevice.Wait();
|
||||||
screenshotBuffer.GetData(screenshotPixels, screenShotBufferSize);
|
screenshotBuffer.GetData(screenshotPixels, screenshotBufferSize);
|
||||||
Texture.SavePNG("screenshot.png", 1280, 720, screenshotPixels);
|
|
||||||
|
Texture.SavePNG(
|
||||||
|
name,
|
||||||
|
1280,
|
||||||
|
720,
|
||||||
|
GraphicsDevice.GetSwapchainFormat(Window),
|
||||||
|
screenshotPixels
|
||||||
|
);
|
||||||
|
|
||||||
|
System.Console.WriteLine("Screenshot saved!");
|
||||||
|
|
||||||
|
screenshotInProgress = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDestroy()
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,550 @@
|
||||||
|
// Created by inigo quilez - iq/2020
|
||||||
|
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
|
||||||
|
|
||||||
|
|
||||||
|
// Everybody has to implement an hexagonal grid. This it mine.
|
||||||
|
// It does raycasting on it, efficiently (just a few muls per step) and robustly
|
||||||
|
// (works in integers). Each cell is visited only once and in the right order.
|
||||||
|
// Based on https://www.shadertoy.com/view/WtSBWK Check castRay() in line 92.
|
||||||
|
|
||||||
|
// That, plus the fact the ambient occlusion is analytical means this shader should
|
||||||
|
// run smoothly even on a crappy phone. It does on mine!
|
||||||
|
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(set = 1, binding = 0) uniform sampler2D iChannel0;
|
||||||
|
layout(set = 1, binding = 1) uniform sampler2D iChannel1;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform UniformBlock
|
||||||
|
{
|
||||||
|
float time;
|
||||||
|
vec2 resolution;
|
||||||
|
} Uniforms;
|
||||||
|
|
||||||
|
//layout(location = 0) in vec2 fragCoord;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
|
// make this bigger if you have a storng PC
|
||||||
|
#define AA 2
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
// mod3 - not as trivial as you first though
|
||||||
|
// -----------------------------------------
|
||||||
|
int mod3( int n )
|
||||||
|
{
|
||||||
|
return (n<0) ? 2-((2-n)%3) : n%3;
|
||||||
|
|
||||||
|
// Some methods of computing mod3: // PC-WebGL Native-OpenGL Android WebGL
|
||||||
|
// // -------- ------------- -------
|
||||||
|
// 1. return (n<0) ? 2-((2-n)%3) : n%3; // Ok Ok Ok
|
||||||
|
// 2. return int((uint(n)+0x80000001U)%3u); // Ok Ok Broken
|
||||||
|
// 3. n %= 3; return (n<0)?n+3:n; // Ok Broken Ok
|
||||||
|
// 4. n %= 3; n+=((n>>31)&3); return n; // Ok Broken Ok
|
||||||
|
// 5. return ((n%3)+3)%3; // Ok Broken Ok
|
||||||
|
// 6. return int[](1,2,0,1,2)[n%3+2]; // Ok Broken Ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------
|
||||||
|
// hash by Hugo Elias)
|
||||||
|
// --------------------------------------
|
||||||
|
int hash( int n ) { n=(n<<13)^n; return n*(n*n*15731+789221)+1376312589; }
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------------------
|
||||||
|
// basic hexagon grid functions
|
||||||
|
// --------------------------------------
|
||||||
|
ivec2 hexagonID( vec2 p )
|
||||||
|
{
|
||||||
|
const float k3 = 1.732050807;
|
||||||
|
vec2 q = vec2( p.x, p.y*k3*0.5 + p.x*0.5 );
|
||||||
|
|
||||||
|
ivec2 pi = ivec2(floor(q));
|
||||||
|
vec2 pf = fract(q);
|
||||||
|
|
||||||
|
int v = mod3(pi.x+pi.y);
|
||||||
|
|
||||||
|
int ca = (v<1)?0:1;
|
||||||
|
int cb = (v<2)?0:1;
|
||||||
|
ivec2 ma = (pf.x>pf.y)?ivec2(0,1):ivec2(1,0);
|
||||||
|
|
||||||
|
ivec2 id = pi + ca - cb*ma;
|
||||||
|
|
||||||
|
return ivec2( id.x, id.y - (id.x+id.y)/3 );
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 hexagonCenFromID( in ivec2 id )
|
||||||
|
{
|
||||||
|
const float k3 = 1.732050807;
|
||||||
|
return vec2(float(id.x),float(id.y)*k3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// the height function. yes, i know reading from a video texture is cool
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
const float kMaxH = 6.0;
|
||||||
|
|
||||||
|
float map( vec2 p, in float time )
|
||||||
|
{
|
||||||
|
p *= 0.5;
|
||||||
|
float f = 0.5+0.5*sin(0.53*p.x+0.5*time+1.0*sin(p.y*0.24))*
|
||||||
|
sin(0.13*p.y+time);
|
||||||
|
f*= 0.75+0.25*sin(1.7*p.x+1.32*time)*sin(1.3*p.y+time*2.1);
|
||||||
|
return kMaxH*(0.005+0.995*f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------
|
||||||
|
// raycast. this function is the point of this shader
|
||||||
|
// --------------------------------------------------
|
||||||
|
vec4 castRay( in vec3 ro, in vec3 rd, in float time,
|
||||||
|
out ivec2 outPrismID, out int outFaceID )
|
||||||
|
{
|
||||||
|
ivec2 hid = hexagonID(ro.xz);
|
||||||
|
|
||||||
|
vec4 res = vec4( -1.0, 0.0, 0.0, 0.0 );
|
||||||
|
|
||||||
|
const float k3 = 0.866025;
|
||||||
|
const vec2 n1 = vec2( 1.0,0.0);
|
||||||
|
const vec2 n2 = vec2( 0.5,k3);
|
||||||
|
const vec2 n3 = vec2(-0.5,k3);
|
||||||
|
|
||||||
|
float d1 = 1.0/dot(rd.xz,n1);
|
||||||
|
float d2 = 1.0/dot(rd.xz,n2);
|
||||||
|
float d3 = 1.0/dot(rd.xz,n3);
|
||||||
|
float d4 = 1.0/rd.y;
|
||||||
|
|
||||||
|
float s1 = (d1<0.0)?-1.0:1.0;
|
||||||
|
float s2 = (d2<0.0)?-1.0:1.0;
|
||||||
|
float s3 = (d3<0.0)?-1.0:1.0;
|
||||||
|
float s4 = (d4<0.0)?-1.0:1.0;
|
||||||
|
|
||||||
|
ivec2 i1 = ivec2( 2,0); if(d1<0.0) i1=-i1;
|
||||||
|
ivec2 i2 = ivec2( 1,1); if(d2<0.0) i2=-i2;
|
||||||
|
ivec2 i3 = ivec2(-1,1); if(d3<0.0) i3=-i3;
|
||||||
|
|
||||||
|
// traverse hexagon grid (in 2D)
|
||||||
|
bool found = false;
|
||||||
|
vec2 t1, t2, t3, t4;
|
||||||
|
for( int i=0; i<100; i++ )
|
||||||
|
{
|
||||||
|
// fetch height for this hexagon
|
||||||
|
vec2 ce = hexagonCenFromID( hid );
|
||||||
|
float he = 0.5*map(ce, time);
|
||||||
|
|
||||||
|
// compute ray-hexaprism intersection
|
||||||
|
vec3 oc = ro - vec3(ce.x,he,ce.y);
|
||||||
|
t1 = (vec2(-s1,s1)-dot(oc.xz,n1))*d1;
|
||||||
|
t2 = (vec2(-s2,s2)-dot(oc.xz,n2))*d2;
|
||||||
|
t3 = (vec2(-s3,s3)-dot(oc.xz,n3))*d3;
|
||||||
|
t4 = (vec2(-s4,s4)*he-oc.y)*d4;
|
||||||
|
float tN = max(max(t1.x,t2.x),max(t3.x,t4.x));
|
||||||
|
float tF = min(min(t1.y,t2.y),min(t3.y,t4.y));
|
||||||
|
if( tN<tF && tF>0.0 )
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// move to next hexagon
|
||||||
|
if( t1.y<t2.y && t1.y<t3.y ) hid += i1;
|
||||||
|
else if( t2.y<t3.y ) hid += i2;
|
||||||
|
else hid += i3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( found )
|
||||||
|
{
|
||||||
|
{res=vec4(t1.x,s1*vec3(n1.x,0,n1.y)); outFaceID=(d1<0.0)?-1: 1;}
|
||||||
|
if( t2.x>res.x ) {res=vec4(t2.x,s2*vec3(n2.x,0,n2.y)); outFaceID=(d2<0.0)?-2: 2;}
|
||||||
|
if( t3.x>res.x ) {res=vec4(t3.x,s3*vec3(n3.x,0,n3.y)); outFaceID=(d3<0.0)?-3: 3;}
|
||||||
|
if( t4.x>res.x ) {res=vec4(t4.x,s4*vec3( 0.0,1,0)); outFaceID=(d4<0.0)? 4:-4;}
|
||||||
|
|
||||||
|
outPrismID = hid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// same as above, but simpler sinec we don't need the normal and primtive id
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
float castShadowRay( in vec3 ro, in vec3 rd, in float time )
|
||||||
|
{
|
||||||
|
float res = 1.0;
|
||||||
|
|
||||||
|
ivec2 hid = hexagonID(ro.xz);
|
||||||
|
|
||||||
|
const float k3 = 0.866025;
|
||||||
|
const vec2 n1 = vec2( 1.0,0.0);
|
||||||
|
const vec2 n2 = vec2( 0.5,k3);
|
||||||
|
const vec2 n3 = vec2(-0.5,k3);
|
||||||
|
|
||||||
|
float d1 = 1.0/dot(rd.xz,n1);
|
||||||
|
float d2 = 1.0/dot(rd.xz,n2);
|
||||||
|
float d3 = 1.0/dot(rd.xz,n3);
|
||||||
|
float d4 = 1.0/rd.y;
|
||||||
|
|
||||||
|
float s1 = (d1<0.0)?-1.0:1.0;
|
||||||
|
float s2 = (d2<0.0)?-1.0:1.0;
|
||||||
|
float s3 = (d3<0.0)?-1.0:1.0;
|
||||||
|
float s4 = (d4<0.0)?-1.0:1.0;
|
||||||
|
|
||||||
|
ivec2 i1 = ivec2( 2,0); if(d1<0.0) i1=-i1;
|
||||||
|
ivec2 i2 = ivec2( 1,1); if(d2<0.0) i2=-i2;
|
||||||
|
ivec2 i3 = ivec2(-1,1); if(d3<0.0) i3=-i3;
|
||||||
|
|
||||||
|
vec2 c1 = (vec2(-s1,s1)-dot(ro.xz,n1))*d1;
|
||||||
|
vec2 c2 = (vec2(-s2,s2)-dot(ro.xz,n2))*d2;
|
||||||
|
vec2 c3 = (vec2(-s3,s3)-dot(ro.xz,n3))*d3;
|
||||||
|
|
||||||
|
// traverse regular grid (2D)
|
||||||
|
for( int i=0; i<8; i++ )
|
||||||
|
{
|
||||||
|
vec2 ce = hexagonCenFromID( hid );
|
||||||
|
float he = 0.5*map(ce, time);
|
||||||
|
|
||||||
|
vec2 t1 = c1 + dot(ce,n1)*d1;
|
||||||
|
vec2 t2 = c2 + dot(ce,n2)*d2;
|
||||||
|
vec2 t3 = c3 + dot(ce,n3)*d3;
|
||||||
|
vec2 t4 = (vec2(1.0-s4,1.0+s4)*he-ro.y)*d4;
|
||||||
|
|
||||||
|
float tN = max(max(t1.x,t2.x),max(t3.x,t4.x));
|
||||||
|
float tF = min(min(t1.y,t2.y),min(t3.y,t4.y));
|
||||||
|
if( tN < tF && tF > 0.0)
|
||||||
|
{
|
||||||
|
res = 0.0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( t1.y<t2.y && t1.y<t3.y ) hid += i1;
|
||||||
|
else if( t2.y<t3.y ) hid += i2;
|
||||||
|
else hid += i3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// analytic occlusion of a quad and an hexagon
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
float macos(float x ) { return acos(clamp(x,-1.0,1.0));}
|
||||||
|
|
||||||
|
float occlusionQuad( in vec3 pos, in vec3 nor,
|
||||||
|
in vec3 v0, in vec3 v1,
|
||||||
|
in vec3 v2, in vec3 v3 )
|
||||||
|
{
|
||||||
|
v0 = normalize(v0-pos);
|
||||||
|
v1 = normalize(v1-pos);
|
||||||
|
v2 = normalize(v2-pos);
|
||||||
|
v3 = normalize(v3-pos);
|
||||||
|
float k01 = dot( nor, normalize( cross(v0,v1)) ) * macos( dot(v0,v1) );
|
||||||
|
float k12 = dot( nor, normalize( cross(v1,v2)) ) * macos( dot(v1,v2) );
|
||||||
|
float k23 = dot( nor, normalize( cross(v2,v3)) ) * macos( dot(v2,v3) );
|
||||||
|
float k30 = dot( nor, normalize( cross(v3,v0)) ) * macos( dot(v3,v0) );
|
||||||
|
|
||||||
|
return abs(k01+k12+k23+k30)/6.283185;
|
||||||
|
}
|
||||||
|
|
||||||
|
float occlusionHexagon( in vec3 pos, in vec3 nor,
|
||||||
|
in vec3 v0, in vec3 v1,
|
||||||
|
in vec3 v2, in vec3 v3,
|
||||||
|
in vec3 v4, in vec3 v5)
|
||||||
|
{
|
||||||
|
v0 = normalize(v0-pos);
|
||||||
|
v1 = normalize(v1-pos);
|
||||||
|
v2 = normalize(v2-pos);
|
||||||
|
v3 = normalize(v3-pos);
|
||||||
|
v4 = normalize(v4-pos);
|
||||||
|
v5 = normalize(v5-pos);
|
||||||
|
float k01 = dot( nor, normalize( cross(v0,v1)) ) * macos( dot(v0,v1) );
|
||||||
|
float k12 = dot( nor, normalize( cross(v1,v2)) ) * macos( dot(v1,v2) );
|
||||||
|
float k23 = dot( nor, normalize( cross(v2,v3)) ) * macos( dot(v2,v3) );
|
||||||
|
float k34 = dot( nor, normalize( cross(v3,v4)) ) * macos( dot(v3,v4) );
|
||||||
|
float k45 = dot( nor, normalize( cross(v4,v5)) ) * macos( dot(v4,v5) );
|
||||||
|
float k50 = dot( nor, normalize( cross(v5,v0)) ) * macos( dot(v5,v0) );
|
||||||
|
|
||||||
|
return abs(k01+k12+k23+k34+k45+k50)/6.283185;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// get the walls and top face vertex positions
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool getPrismWall( ivec2 prismID, int sid, in float time,
|
||||||
|
out vec3 v0, out vec3 v1, out vec3 v2, out vec3 v3 )
|
||||||
|
{
|
||||||
|
const ivec2 i1 = ivec2( 2,0);
|
||||||
|
const ivec2 i2 = ivec2( 1,1);
|
||||||
|
const ivec2 i3 = ivec2(-1,1);
|
||||||
|
|
||||||
|
vec2 ce = hexagonCenFromID( prismID );
|
||||||
|
vec3 ce3 = vec3(ce.x,0.0,ce.y);
|
||||||
|
float he = map( ce, time);
|
||||||
|
|
||||||
|
const float kRa = 2.0/sqrt(3.0);
|
||||||
|
const float kC1 = kRa*0.5;
|
||||||
|
const float kC2 = kRa*1.0;
|
||||||
|
|
||||||
|
if( sid==0 )
|
||||||
|
{
|
||||||
|
float he1p = map(hexagonCenFromID( prismID+i1 ), time);
|
||||||
|
if( he1p<he ) return false;
|
||||||
|
v0 = vec3(1.0,he, kC1);
|
||||||
|
v1 = vec3(1.0,he1p, kC1);
|
||||||
|
v2 = vec3(1.0,he1p,-kC1);
|
||||||
|
v3 = vec3(1.0,he, -kC1);
|
||||||
|
}
|
||||||
|
else if( sid==1 )
|
||||||
|
{
|
||||||
|
float he3m = map(hexagonCenFromID( prismID-i3 ), time);
|
||||||
|
if( he3m<he ) return false;
|
||||||
|
v0 = vec3( 1.0,he, -kC1);
|
||||||
|
v1 = vec3( 1.0,he3m,-kC1);
|
||||||
|
v2 = vec3( 0.0,he3m,-kC2);
|
||||||
|
v3 = vec3( 0.0,he, -kC2);
|
||||||
|
}
|
||||||
|
else if( sid==2 )
|
||||||
|
{
|
||||||
|
float he2m = map(hexagonCenFromID( prismID-i2 ), time);
|
||||||
|
if( he2m<he ) return false;
|
||||||
|
v0 = vec3( 0.0,he, -kC2);
|
||||||
|
v1 = vec3( 0.0,he2m,-kC2);
|
||||||
|
v2 = vec3(-1.0,he2m,-kC1);
|
||||||
|
v3 = vec3(-1.0,he, -kC1);
|
||||||
|
}
|
||||||
|
else if( sid==3 )
|
||||||
|
{
|
||||||
|
float he1m = map(hexagonCenFromID( prismID-i1 ), time);
|
||||||
|
if( he1m<he ) return false;
|
||||||
|
v0 = vec3(-1.0,he, -kC1);
|
||||||
|
v1 = vec3(-1.0,he1m,-kC1);
|
||||||
|
v2 = vec3(-1.0,he1m, kC1);
|
||||||
|
v3 = vec3(-1.0,he, kC1);
|
||||||
|
}
|
||||||
|
else if( sid==4 )
|
||||||
|
{
|
||||||
|
float he3p = map(hexagonCenFromID( prismID+i3 ), time);
|
||||||
|
if( he3p<he ) return false;
|
||||||
|
v0 = vec3(-1.0,he, kC1);
|
||||||
|
v1 = vec3(-1.0,he3p, kC1);
|
||||||
|
v2 = vec3( 0.0,he3p, kC2);
|
||||||
|
v3 = vec3( 0.0,he, kC2);
|
||||||
|
}
|
||||||
|
else //if( sid==5 )
|
||||||
|
{
|
||||||
|
float he2p = map(hexagonCenFromID( prismID+i2 ), time);
|
||||||
|
if( he2p<he ) return false;
|
||||||
|
v0 = vec3( 0.0,he, kC2);
|
||||||
|
v1 = vec3( 0.0,he2p, kC2);
|
||||||
|
v2 = vec3( 1.0,he2p, kC1);
|
||||||
|
v3 = vec3( 1.0,he, kC1);
|
||||||
|
}
|
||||||
|
|
||||||
|
v0 += ce3;
|
||||||
|
v1 += ce3;
|
||||||
|
v2 += ce3;
|
||||||
|
v3 += ce3;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void getPrismTop( ivec2 prismID, in float time,
|
||||||
|
out vec3 v0, out vec3 v1, out vec3 v2,
|
||||||
|
out vec3 v3, out vec3 v4, out vec3 v5 )
|
||||||
|
{
|
||||||
|
vec2 ce = hexagonCenFromID( prismID );
|
||||||
|
vec3 ce3 = vec3(ce.x,0.0,ce.y);
|
||||||
|
float he = map( ce, time);
|
||||||
|
|
||||||
|
const float kRa = 2.0/sqrt(3.0);
|
||||||
|
const float kC1 = kRa*0.5;
|
||||||
|
const float kC2 = kRa*1.0;
|
||||||
|
|
||||||
|
v0 = ce3+vec3( 0.0,he, -kC2);
|
||||||
|
v1 = ce3+vec3( -1.0,he, -kC1);
|
||||||
|
v2 = ce3+vec3( -1.0,he, kC1);
|
||||||
|
v3 = ce3+vec3( 0.0,he, kC2);
|
||||||
|
v4 = ce3+vec3( 1.0,he, kC1);
|
||||||
|
v5 = ce3+vec3( 1.0,he, -kC1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// compute analytical ambient occlusion, by using the solid angle of the
|
||||||
|
// faces surrounding the current point. if one face is missing (it's below
|
||||||
|
// the current prism's height) we ignore the portal and assume light comes
|
||||||
|
// through it. Ideally portals should be recursivelly traversed and clipped
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
float calcOcclusion( in vec3 pos, in vec3 nor, in float time,
|
||||||
|
in ivec2 prismID, in int faceID )
|
||||||
|
{
|
||||||
|
const ivec2 i1 = ivec2( 2,0);
|
||||||
|
const ivec2 i2 = ivec2( 1,1);
|
||||||
|
const ivec2 i3 = ivec2(-1,1);
|
||||||
|
|
||||||
|
vec3 v0, v1, v2, v3, v4, v5;
|
||||||
|
|
||||||
|
if( faceID==-1 ) prismID += i1;
|
||||||
|
else if( faceID== 1 ) prismID -= i1;
|
||||||
|
else if( faceID==-2 ) prismID += i2;
|
||||||
|
else if( faceID== 2 ) prismID -= i2;
|
||||||
|
else if( faceID==-3 ) prismID += i3;
|
||||||
|
else if( faceID== 3 ) prismID -= i3;
|
||||||
|
|
||||||
|
float occ = 0.0;
|
||||||
|
if( faceID!=1 && getPrismWall( prismID, 0, time, v0, v1, v2, v3 ) )
|
||||||
|
occ += occlusionQuad(pos,nor,v0,v1,v2,v3);
|
||||||
|
if( faceID!=-3 && getPrismWall( prismID, 1, time, v0, v1, v2, v3 ) )
|
||||||
|
occ += occlusionQuad(pos,nor,v0,v1,v2,v3);
|
||||||
|
if( faceID!=-2 && getPrismWall( prismID, 2, time, v0, v1, v2, v3 ) )
|
||||||
|
occ += occlusionQuad(pos,nor,v0,v1,v2,v3);
|
||||||
|
if( faceID!=-1 && getPrismWall( prismID, 3, time, v0, v1, v2, v3 ) )
|
||||||
|
occ += occlusionQuad(pos,nor,v0,v1,v2,v3);
|
||||||
|
if( faceID!=3 && getPrismWall( prismID, 4, time, v0, v1, v2, v3 ) )
|
||||||
|
occ += occlusionQuad(pos,nor,v0,v1,v2,v3);
|
||||||
|
if( faceID!=2 && getPrismWall( prismID, 5, time, v0, v1, v2, v3 ) )
|
||||||
|
occ += occlusionQuad(pos,nor,v0,v1,v2,v3);
|
||||||
|
|
||||||
|
if( faceID!=4 )
|
||||||
|
{
|
||||||
|
getPrismTop( prismID, time, v0, v1, v2, v3, v4, v5 );
|
||||||
|
occ += occlusionHexagon(pos,nor,v0,v1,v2,v3,v4,v5);
|
||||||
|
|
||||||
|
occ = 1.0-min(0.5,0.2+0.8*(1.0-occ)*pos.y/kMaxH);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1.0-occ;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// render = raycast + shade + light
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
vec3 render( in vec3 ro, in vec3 rd, in float time )
|
||||||
|
{
|
||||||
|
// raycast
|
||||||
|
vec3 col = vec3(1.0);
|
||||||
|
ivec2 prismID; int faceID;
|
||||||
|
vec4 tnor = castRay( ro, rd, time, prismID, faceID );
|
||||||
|
float t = tnor.x;
|
||||||
|
// if intersection found
|
||||||
|
if( t>0.0 )
|
||||||
|
{
|
||||||
|
// data at intersection point
|
||||||
|
vec3 pos = ro + rd*t;
|
||||||
|
vec3 nor = -tnor.yzw;
|
||||||
|
vec2 ce = hexagonCenFromID(prismID);
|
||||||
|
float he = map(ce,time);
|
||||||
|
int id = prismID.x*131 + prismID.y*57;
|
||||||
|
|
||||||
|
// uvs
|
||||||
|
vec2 uv = (faceID==4) ? (pos.xz-ce)*0.15 :
|
||||||
|
vec2(atan(pos.x-ce.x,pos.z-ce.y)/3.14156,
|
||||||
|
(pos.y-he)/4.0 );
|
||||||
|
uv += ce;
|
||||||
|
|
||||||
|
// material color
|
||||||
|
vec3 mate = vec3(1.0);
|
||||||
|
id = hash(id); mate *= 0.1+0.9*float((id>>13)&3)/3.0;
|
||||||
|
id = hash(id); mate = ( ((id>>8)&15)==0 ) ? vec3(0.7,0.0,0.0) : mate;
|
||||||
|
vec3 tex = vec3(0.15,0.09,0.07)+0.75*pow(texture(iChannel0,uv.yx).xyz,vec3(1.0,0.95,0.9));
|
||||||
|
mate *= tex;
|
||||||
|
|
||||||
|
// lighting
|
||||||
|
float occ = calcOcclusion( pos, nor, time, prismID, faceID );
|
||||||
|
|
||||||
|
// diffuse
|
||||||
|
col = mate*pow(vec3(occ),vec3(0.95,1.05,1.1));
|
||||||
|
|
||||||
|
// specular
|
||||||
|
float ks = tex.x*2.0;
|
||||||
|
vec3 ref = reflect(rd,nor);
|
||||||
|
col *= 0.85;
|
||||||
|
float fre = clamp(1.0+dot(nor,rd),0.0,1.0);
|
||||||
|
col += vec3(1.1)*ks*
|
||||||
|
smoothstep(0.0,0.15,ref.y)*
|
||||||
|
(0.04 + 0.96*pow(fre,5.0))*
|
||||||
|
castShadowRay( pos+nor*0.001, ref, time );
|
||||||
|
|
||||||
|
// fog
|
||||||
|
col = mix(col,vec3(1.0), 1.0-exp2(-0.00005*t*t) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------
|
||||||
|
// main = animate + render + color grade
|
||||||
|
//-----------------------------------------------
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec2 fragCoord = gl_FragCoord.xy;
|
||||||
|
|
||||||
|
fragCoord.y = Uniforms.resolution.y - gl_FragCoord.y;
|
||||||
|
|
||||||
|
// init random seed
|
||||||
|
ivec2 q = ivec2(fragCoord);
|
||||||
|
|
||||||
|
// sample pixel and time
|
||||||
|
vec3 tot = vec3(0.0);
|
||||||
|
for( int m=0; m<AA; m++ )
|
||||||
|
for( int n=0; n<AA; n++ )
|
||||||
|
{
|
||||||
|
vec2 of = vec2(m,n)/float(AA) - 0.5;
|
||||||
|
vec2 p = (2.0*(fragCoord+of)-Uniforms.resolution.xy)/min(Uniforms.resolution.x,Uniforms.resolution.y);
|
||||||
|
#if AA>1
|
||||||
|
float d = 0.5+0.5*sin(fragCoord.x*147.0)*sin(fragCoord.y*131.0);
|
||||||
|
float time = Uniforms.time - 0.5*(1.0/24.0)*(float(m*AA+n)+d)/float(AA*AA);
|
||||||
|
#else
|
||||||
|
float time = Uniforms.time;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// camera
|
||||||
|
float cr = -0.1;
|
||||||
|
float an = 3.0*time;
|
||||||
|
vec3 ro = vec3(0.1,13.0,1.0-an);
|
||||||
|
vec3 ta = vec3(0.0,12.0,0.0-an);
|
||||||
|
|
||||||
|
// build camera matrix
|
||||||
|
vec3 ww = normalize( ta - ro);
|
||||||
|
vec3 uu = normalize(cross( ww,vec3(sin(cr),cos(cr),0.0) ));
|
||||||
|
vec3 vv = normalize(cross(uu,ww));
|
||||||
|
// distort
|
||||||
|
p *= 0.9+0.1*(p.x*p.x*0.4 + p.y*p.y);
|
||||||
|
// buid ray
|
||||||
|
vec3 rd = normalize( p.x*uu + p.y*vv + 2.0*ww );
|
||||||
|
|
||||||
|
// dof
|
||||||
|
#if AA>1
|
||||||
|
vec3 fp = ro + rd*17.0;
|
||||||
|
vec2 ra = texelFetch(iChannel1,(q+ivec2(13*m,31*n))&1023,0).xy;
|
||||||
|
ro.xy += 0.3*sqrt(ra.x)*vec2(cos(6.2831*ra.y),sin(6.2831*ra.y));
|
||||||
|
rd = normalize( fp - ro );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// render
|
||||||
|
vec3 col = render( ro, rd, time );
|
||||||
|
|
||||||
|
// accumulate for AA
|
||||||
|
tot += col;
|
||||||
|
}
|
||||||
|
tot /= float(AA*AA);
|
||||||
|
|
||||||
|
|
||||||
|
// hdr->ldr tonemap
|
||||||
|
tot = tot*1.6/(1.0+tot);
|
||||||
|
tot = tot*tot*(3.0-2.0*tot);
|
||||||
|
|
||||||
|
// gamma
|
||||||
|
tot = pow( clamp(tot,0.0,1.0), vec3(0.45) );
|
||||||
|
|
||||||
|
// color grade
|
||||||
|
vec2 p = fragCoord/Uniforms.resolution.xy;
|
||||||
|
tot.xyz += (p.xyy-0.5)*0.1;
|
||||||
|
|
||||||
|
// vignetting
|
||||||
|
tot *= 0.5 + 0.5*pow( 16.0*p.x*p.y*(1.0-p.x)*(1.0-p.y), 0.1 );
|
||||||
|
|
||||||
|
// output
|
||||||
|
fragColor = vec4( tot, 1.0 );
|
||||||
|
}
|
Loading…
Reference in New Issue