397 lines
11 KiB
C++
397 lines
11 KiB
C++
#ifndef Sky_h__
|
|||
|
|
#define Sky_h__
|
||
|
|
#include "Globals.h"
|
||
|
|
#include "DayTime.h"
|
||
|
|
#include "math/LifeMath.h"
|
||
|
|
|
||
|
|
namespace LifeGraphics
|
||
|
|
{
|
||
|
|
struct SkyVertex
|
||
|
|
{
|
||
|
|
LifeMath::float3 Position;
|
||
|
|
LifeMath::float2 Texcoord;
|
||
|
|
SkyVertex()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
SkyVertex(LifeMath::float3& _pos, LifeMath::float2& _tex)
|
||
|
|
{
|
||
|
|
Position = _pos;
|
||
|
|
Texcoord = _tex;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
struct cbRenderData
|
||
|
|
{
|
||
|
|
LifeMath::float4x4 View;
|
||
|
|
LifeMath::float4x4 Proj;
|
||
|
|
LifeMath::float4x4 ViewProj;
|
||
|
|
LifeMath::float3 SunDirection;
|
||
|
|
float dummy;
|
||
|
|
};
|
||
|
|
class Sky
|
||
|
|
{
|
||
|
|
private:
|
||
|
|
int DomeN;
|
||
|
|
int DVSize;
|
||
|
|
int DISize;
|
||
|
|
int MrlTexSize;
|
||
|
|
int MrlTexSizeHalf;
|
||
|
|
|
||
|
|
LifeMath::float3 SunrizeDirection;
|
||
|
|
LifeMath::float3 ZenithDirection;
|
||
|
|
LifeMath::float3 waveLengths;
|
||
|
|
LifeMath::float3 invWaveLengths;
|
||
|
|
LifeMath::float3 waveLengthsMie;
|
||
|
|
|
||
|
|
IVertexBuffer* skyVb;
|
||
|
|
IIndexBuffer* skyIb;
|
||
|
|
|
||
|
|
IShader* VS_Render;
|
||
|
|
IShader* VS_Update;
|
||
|
|
IShader* PS_Render;
|
||
|
|
IShader* PS_Update;
|
||
|
|
|
||
|
|
IConstantBuffer* cbUpdate;
|
||
|
|
IConstantBuffer* cbRender;
|
||
|
|
|
||
|
|
ITexture2D* skyDepth;
|
||
|
|
|
||
|
|
IInputLayout* vertexLayout;
|
||
|
|
|
||
|
|
DayTime Time;
|
||
|
|
DayTime SunsetTime;
|
||
|
|
DayTime SunrizeTime;
|
||
|
|
DayTime MidDayTime;
|
||
|
|
DayTime MidNightTime;
|
||
|
|
DayTime DayLength;
|
||
|
|
DayTime NightLength;
|
||
|
|
DayTime TimeStep;
|
||
|
|
|
||
|
|
int DayPhase;
|
||
|
|
|
||
|
|
float fExposure;
|
||
|
|
float updateTimeElapsed;
|
||
|
|
float StarsIntensity;
|
||
|
|
float updatePeriod;
|
||
|
|
bool ShouldUpdateData;
|
||
|
|
|
||
|
|
IDepthStencilState* dsZEnable;
|
||
|
|
IDepthStencilState* dsZDisable;
|
||
|
|
|
||
|
|
void RecomputeData()
|
||
|
|
{
|
||
|
|
SunrizeDirection = LifeMath::float3(-1,0,0);
|
||
|
|
ZenithDirection = LifeMath::float3(0,1,0);
|
||
|
|
DayLength = SunsetTime - SunrizeTime;
|
||
|
|
NightLength = SunrizeTime - SunsetTime;
|
||
|
|
MidNightTime = SunsetTime + (NightLength / 2);
|
||
|
|
MidDayTime = SunrizeTime + (DayLength / 2);
|
||
|
|
|
||
|
|
if (Time >= SunrizeTime && Time <= MidDayTime)
|
||
|
|
DayPhase = 0;
|
||
|
|
else if (Time >= MidDayTime && Time <= SunsetTime)
|
||
|
|
DayPhase = 1;
|
||
|
|
else if (MidNightTime - SunsetTime >= Time - SunsetTime)
|
||
|
|
DayPhase = 2;
|
||
|
|
else
|
||
|
|
DayPhase = 3;
|
||
|
|
float lamt = 0;
|
||
|
|
switch (DayPhase)
|
||
|
|
{
|
||
|
|
case 0:
|
||
|
|
lamt = (float)(Time - SunrizeTime).ToSeconds()
|
||
|
|
/ (float)(MidDayTime - SunrizeTime).ToSeconds();
|
||
|
|
SunDirection = Vec3Lerp(SunrizeDirection, ZenithDirection, lamt);
|
||
|
|
LifeMath::Vec3Normalize(&SunDirection);
|
||
|
|
StarsIntensity = 1.0f - lamt;
|
||
|
|
break;
|
||
|
|
case 1:
|
||
|
|
lamt = (float)(Time - MidDayTime).ToSeconds()
|
||
|
|
/ (float)(SunsetTime - MidDayTime).ToSeconds();
|
||
|
|
SunDirection = Vec3Lerp(ZenithDirection, -SunrizeDirection, lamt);
|
||
|
|
LifeMath::Vec3Normalize(&SunDirection);
|
||
|
|
StarsIntensity = lamt;
|
||
|
|
break;
|
||
|
|
case 2:
|
||
|
|
lamt = (float)(Time - SunsetTime).ToSeconds()
|
||
|
|
/ (float)(MidNightTime - SunsetTime).ToSeconds();
|
||
|
|
SunDirection = Vec3Lerp(-SunrizeDirection, -ZenithDirection, lamt);
|
||
|
|
LifeMath::Vec3Normalize(&SunDirection);
|
||
|
|
StarsIntensity = 1.0f;
|
||
|
|
break;
|
||
|
|
case 3:
|
||
|
|
lamt = (float)(Time - MidNightTime).ToSeconds()
|
||
|
|
/ (float)(SunrizeTime - MidNightTime).ToSeconds();
|
||
|
|
SunDirection = Vec3Lerp(-ZenithDirection, SunrizeDirection, lamt);
|
||
|
|
LifeMath::Vec3Normalize(&SunDirection);
|
||
|
|
StarsIntensity = 1.0f;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
StarsIntensity = pow(StarsIntensity,10);
|
||
|
|
|
||
|
|
invWaveLengths.X = 1.0f / pow(waveLengths.X, 4.0f);
|
||
|
|
invWaveLengths.Y = 1.0f / pow(waveLengths.Y, 4.0f);
|
||
|
|
invWaveLengths.Z = 1.0f / pow(waveLengths.Z, 4.0f);
|
||
|
|
|
||
|
|
waveLengthsMie.X = pow(waveLengths.X, -0.84f);
|
||
|
|
waveLengthsMie.Y = pow(waveLengths.Y, -0.84f);
|
||
|
|
waveLengthsMie.Z = pow(waveLengths.Z, -0.84f);
|
||
|
|
}
|
||
|
|
|
||
|
|
void GenerateDome()
|
||
|
|
{
|
||
|
|
int Latitude = DomeN / 2;
|
||
|
|
int Longitude = DomeN;
|
||
|
|
DVSize = Longitude * Latitude;
|
||
|
|
DISize = (Longitude - 1) * (Latitude - 1) * 2;
|
||
|
|
DVSize *= 2;
|
||
|
|
DISize *= 2;
|
||
|
|
|
||
|
|
IInputElement skyElements[] =
|
||
|
|
{
|
||
|
|
IInputElement("POSITION", 0, 0, FORMAT_R32G32B32_FLOAT, 0, 0, 0),
|
||
|
|
IInputElement("TEXCOORD", 0, 12, FORMAT_R32G32_FLOAT, 0, 0, 0),
|
||
|
|
};
|
||
|
|
|
||
|
|
vertexLayout = CG::me()->GetRenderer()->CreateInputLayout(skyElements, 2, VS_Render);
|
||
|
|
|
||
|
|
SkyVertex* domeVerts = new SkyVertex[DVSize];
|
||
|
|
|
||
|
|
// Fill Vertex Buffer
|
||
|
|
int DomeIndex = 0;
|
||
|
|
for (int i = 0; i < Longitude; i++)
|
||
|
|
{
|
||
|
|
float MoveXZ = 100.0f * ((float)i / (float)(Longitude - 1)) * 3.141592f / 180.0f;
|
||
|
|
|
||
|
|
for (int j = 0; j < Latitude; j++)
|
||
|
|
{
|
||
|
|
float MoveY = 3.1415f * (float)j / (float)(Latitude - 1);
|
||
|
|
|
||
|
|
domeVerts[DomeIndex] = SkyVertex();
|
||
|
|
domeVerts[DomeIndex].Position.X = (sin(MoveXZ) * cos(MoveY));
|
||
|
|
domeVerts[DomeIndex].Position.Y = cos(MoveXZ);
|
||
|
|
domeVerts[DomeIndex].Position.Z = (sin(MoveXZ) * sin(MoveY));
|
||
|
|
|
||
|
|
domeVerts[DomeIndex].Position *= 10.0f;
|
||
|
|
|
||
|
|
domeVerts[DomeIndex].Texcoord.X = 0.5f / (float)Longitude + (float)i / (float)Longitude;
|
||
|
|
domeVerts[DomeIndex].Texcoord.Y = 0.5f / (float)Latitude + (float)j / (float)Latitude;
|
||
|
|
|
||
|
|
DomeIndex++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
for (int i = 0; i < Longitude; i++)
|
||
|
|
{
|
||
|
|
float MoveXZ = 100.0f * ((float)i / (float)(Longitude - 1)) * 3.1415f / 180.0f;
|
||
|
|
|
||
|
|
for (int j = 0; j < Latitude; j++)
|
||
|
|
{
|
||
|
|
float MoveY = (3.1415f * 2.0f) - (3.1415f * (float)j / (float)(Latitude - 1));
|
||
|
|
|
||
|
|
domeVerts[DomeIndex] = SkyVertex();
|
||
|
|
domeVerts[DomeIndex].Position.X = (sin(MoveXZ) * cos(MoveY));
|
||
|
|
domeVerts[DomeIndex].Position.Y = cos(MoveXZ);
|
||
|
|
domeVerts[DomeIndex].Position.Z = (sin(MoveXZ) * sin(MoveY));
|
||
|
|
|
||
|
|
domeVerts[DomeIndex].Position *= 10.0f;
|
||
|
|
|
||
|
|
domeVerts[DomeIndex].Texcoord.X = 0.5f / (float)Longitude + (float)i / (float)Longitude;
|
||
|
|
domeVerts[DomeIndex].Texcoord.Y = 0.5f / (float)Latitude + (float)j / (float)Latitude;
|
||
|
|
|
||
|
|
DomeIndex++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Fill index buffer
|
||
|
|
USHORT* ib = new USHORT[DISize * 3];
|
||
|
|
int index = 0;
|
||
|
|
for (USHORT i = 0; i < Longitude - 1; i++)
|
||
|
|
{
|
||
|
|
for (short j = 0; j < Latitude - 1; j++)
|
||
|
|
{
|
||
|
|
ib[index++] = (USHORT)(i * Latitude + j);
|
||
|
|
ib[index++] = (USHORT)((i + 1) * Latitude + j);
|
||
|
|
ib[index++] = (USHORT)((i + 1) * Latitude + j + 1);
|
||
|
|
|
||
|
|
ib[index++] = (USHORT)((i + 1) * Latitude + j + 1);
|
||
|
|
ib[index++] = (USHORT)(i * Latitude + j + 1);
|
||
|
|
ib[index++] = (USHORT)(i * Latitude + j);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
USHORT Offset = (USHORT)(Latitude * Longitude);
|
||
|
|
for (USHORT i = 0; i < Longitude - 1; i++)
|
||
|
|
{
|
||
|
|
for (USHORT j = 0; j < Latitude - 1; j++)
|
||
|
|
{
|
||
|
|
ib[index++] = (USHORT)(Offset + i * Latitude + j);
|
||
|
|
ib[index++] = (USHORT)(Offset + (i + 1) * Latitude + j + 1);
|
||
|
|
ib[index++] = (USHORT)(Offset + (i + 1) * Latitude + j);
|
||
|
|
|
||
|
|
ib[index++] = (USHORT)(Offset + i * Latitude + j + 1);
|
||
|
|
ib[index++] = (USHORT)(Offset + (i + 1) * Latitude + j + 1);
|
||
|
|
ib[index++] = (USHORT)(Offset + i * Latitude + j);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
skyIb = CG::me()->GetRenderer()->CreateIndexBuffer(DISize * 3 * sizeof(USHORT), ib, TRUE);
|
||
|
|
skyVb = CG::me()->GetRenderer()->CreateVertexBuffer(DVSize * sizeof(SkyVertex), domeVerts, sizeof(SkyVertex));
|
||
|
|
}
|
||
|
|
|
||
|
|
public:
|
||
|
|
LifeMath::float3 SunDirection;
|
||
|
|
ITexture2D* mieTex;
|
||
|
|
ITexture2D* rayleighTex;
|
||
|
|
Sky()
|
||
|
|
:DayPhase(0), fExposure(-2.0f), updateTimeElapsed(0.0f), updatePeriod(2.0f), ShouldUpdateData(true)
|
||
|
|
{
|
||
|
|
waveLengths = LifeMath::float3(0.65f, 0.57f, 0.475f);
|
||
|
|
TimeStep = DayTime(0, 0, 1);
|
||
|
|
}
|
||
|
|
~Sky()
|
||
|
|
{
|
||
|
|
SAFE_DELETE(skyVb);
|
||
|
|
SAFE_DELETE(skyIb);
|
||
|
|
|
||
|
|
SAFE_DELETE(cbUpdate);
|
||
|
|
SAFE_DELETE(cbRender);
|
||
|
|
SAFE_DELETE(dsZDisable);
|
||
|
|
SAFE_DELETE(dsZEnable);
|
||
|
|
|
||
|
|
SAFE_DELETE(vertexLayout);
|
||
|
|
SAFE_DELETE(VS_Render);
|
||
|
|
// SAFE_DELETE(VS_Update);
|
||
|
|
SAFE_DELETE(PS_Render);
|
||
|
|
SAFE_DELETE(PS_Update);
|
||
|
|
SAFE_DELETE(mieTex);
|
||
|
|
SAFE_DELETE(rayleighTex);
|
||
|
|
SAFE_DELETE(skyDepth);
|
||
|
|
}
|
||
|
|
void Build()
|
||
|
|
{
|
||
|
|
cbUpdate = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(LifeMath::float4));
|
||
|
|
cbRender = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(cbRenderData));
|
||
|
|
|
||
|
|
dsZDisable = CG::me()->GetRenderer()->CreateDSState(false,false, COMPARISON_NEVER);
|
||
|
|
dsZEnable = CG::me()->GetRenderer()->CreateDSState(true,true, COMPARISON_LESS);
|
||
|
|
|
||
|
|
VS_Render = ResourceManager::me()->CompileUserShaderVS(String(_text("Sky.vsh")));
|
||
|
|
PS_Render = ResourceManager::me()->CompileUserShaderPS(String(_text("Sky_render.psh")));
|
||
|
|
PS_Update = ResourceManager::me()->CompileUserShaderPS(String(_text("Sky_update.psh")));
|
||
|
|
|
||
|
|
SunsetTime = DayTime(18, 2, 0);
|
||
|
|
SunrizeTime = DayTime(7, 10, 0);
|
||
|
|
Time = DayTime(12, 40, 0);
|
||
|
|
|
||
|
|
RecomputeData();
|
||
|
|
|
||
|
|
MrlTexSize = 512;
|
||
|
|
MrlTexSizeHalf = MrlTexSize / 2;
|
||
|
|
|
||
|
|
DomeN = 32;
|
||
|
|
GenerateDome();
|
||
|
|
|
||
|
|
mieTex = CG::me()->GetRenderer()->CreateRenderTarget(MrlTexSize, MrlTexSizeHalf, FORMAT_R16G16B16A16_FLOAT);
|
||
|
|
rayleighTex = CG::me()->GetRenderer()->CreateRenderTarget(MrlTexSize, MrlTexSizeHalf, FORMAT_R16G16B16A16_FLOAT);
|
||
|
|
skyDepth = CG::me()->GetRenderer()->CreateDepthTarget(MrlTexSize, MrlTexSizeHalf, FORMAT_D16_UNORM);
|
||
|
|
|
||
|
|
//g_screenQuad = new Quad(0, 0, MrlTexSize, MrlTexSizeHalf, true);
|
||
|
|
}
|
||
|
|
void SetDayTime(const DayTime& time)
|
||
|
|
{
|
||
|
|
Time = time;
|
||
|
|
RecomputeData();
|
||
|
|
}
|
||
|
|
|
||
|
|
void Update(float dt)
|
||
|
|
{
|
||
|
|
updateTimeElapsed += dt;
|
||
|
|
if (updateTimeElapsed >= updatePeriod)
|
||
|
|
{
|
||
|
|
updateTimeElapsed = 0.0f;
|
||
|
|
ShouldUpdateData = true;
|
||
|
|
}
|
||
|
|
Time.Add((int)(dt * (float)TimeStep.ToSeconds()));
|
||
|
|
RecomputeData();
|
||
|
|
}
|
||
|
|
|
||
|
|
void Render(ITexture2D* sceneRt, ITexture2D* sceneDt, Camera* cam)
|
||
|
|
{
|
||
|
|
IRenderer* renderer = CG::me()->GetRenderer();
|
||
|
|
renderer->SetDepthStencilState(dsZDisable);
|
||
|
|
|
||
|
|
//Update mie and rayleigh textures
|
||
|
|
if (ShouldUpdateData)
|
||
|
|
{
|
||
|
|
ITexture2D* tex[] = {rayleighTex, mieTex};
|
||
|
|
|
||
|
|
renderer->SetTargets(tex, 2, skyDepth);
|
||
|
|
renderer->SetPixelShader(PS_Update);
|
||
|
|
|
||
|
|
cbUpdate->Update(&SunDirection, sizeof(SunDirection));
|
||
|
|
renderer->SetPSConstantBuffer(cbUpdate, 1);
|
||
|
|
|
||
|
|
renderer->SetViewport(LifeMath::Rect2i(0,0, MrlTexSize, MrlTexSizeHalf));
|
||
|
|
renderer->RenderToTextureNoPs();
|
||
|
|
|
||
|
|
renderer->UnbindRenderTargets();
|
||
|
|
ShouldUpdateData = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
renderer->SetViewport(LifeMath::Rect2i(0,0, sceneRt->Width(), sceneRt->Height()));
|
||
|
|
|
||
|
|
renderer->SetVertexShader(VS_Render);
|
||
|
|
renderer->SetPixelShader(PS_Render);
|
||
|
|
|
||
|
|
float starIntensity = 0.7f;
|
||
|
|
float g = -0.990f;
|
||
|
|
float g2 = (-0.990f) * (-0.990f);
|
||
|
|
|
||
|
|
LifeMath::float4x4 sm;
|
||
|
|
Mat4x4LookAtLH(LifeMath::float3(0, 0, 0), cam->getDirection(), LifeMath::float3(0, 1, 0), sm);
|
||
|
|
|
||
|
|
cbRenderData data;
|
||
|
|
data.View = sm;
|
||
|
|
data.Proj = cam->getProj();
|
||
|
|
data.ViewProj = data.View * data.Proj;
|
||
|
|
data.SunDirection = SunDirection;
|
||
|
|
|
||
|
|
cbRender->Update(&data, sizeof(cbRenderData));
|
||
|
|
renderer->SetPSConstantBuffer(cbRender, 1);
|
||
|
|
renderer->SetVSConstantBuffer(cbRender, 1);
|
||
|
|
|
||
|
|
renderer->SetTargets(sceneRt, sceneDt);
|
||
|
|
|
||
|
|
////PS_Render.SetFloat("fExposure", fExposure);
|
||
|
|
////PS_Render.SetFloat("starIntensity", StarsIntensity);
|
||
|
|
|
||
|
|
////PS_Render.SetTexture("starSampler", starTex);
|
||
|
|
////PS_Render.SetTexture("mieSampler", mieTex);
|
||
|
|
////PS_Render.SetTexture("rayleighSampler", rayleighTex);
|
||
|
|
/*CG.Engine.Renderer.SetTextureFilterMin(TextureFilter.Point, 2);
|
||
|
|
CG.Engine.Renderer.SetTextureFilterMip(TextureFilter.Point, 2);
|
||
|
|
CG.Engine.Renderer.SetTextureFilterMag(TextureFilter.Point, 2);*/
|
||
|
|
////PS_Render.SetFloat3("v3SunDir", SunDirection);
|
||
|
|
|
||
|
|
renderer->SetPSTexture(rayleighTex,0);
|
||
|
|
renderer->SetPSTexture(mieTex,1);
|
||
|
|
|
||
|
|
////VS_Render.SetMatrix("matWorld", Matrix4x4.Identity);
|
||
|
|
////VS_Render.SetMatrix("matView", sm);
|
||
|
|
////VS_Render.SetMatrix("matProjection", renderer.MainCamera.ProjectionMatrix);
|
||
|
|
|
||
|
|
renderer->SetInputLayout(vertexLayout);
|
||
|
|
|
||
|
|
renderer->SetIndexBuffer(skyIb);
|
||
|
|
renderer->SetVertexBuffer(skyVb);
|
||
|
|
|
||
|
|
renderer->SetPrimitiveTopology(PT_TRIANGLE_LIST);
|
||
|
|
|
||
|
|
renderer->DrawIndexed(0, DISize);
|
||
|
|
|
||
|
|
// renderer.DrawIndexedPrimitives(IPrimitiveTopology.TriangleList, 0, 0, SkyGeometry.NumberVertices, SkyGeometry.Subsets[0].Offset, SkyGeometry.Subsets[0].FaceCount);
|
||
|
|
|
||
|
|
renderer->SetDepthStencilState(dsZEnable);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
}
|
||
|
|
#endif // Sky_h__
|