Adding a dynamic sky to your mod
This article will show you how to implement a dynamic sky for your mod. This tutorial uses code from the canceled mod Vance.
Requirements
- Ability to compile shaders.
- Ability to compile the solution.
Implementation
Before doing anything, we need to download the files we need. They are inside the zip file.
When you have downloaded the zip file, extract the files inside of shaders to: src/materialsystem/stdshaders/.
Extract the files inside of code to src/game/.
Open up src/game/client/client_base.vpc
Go to line $File "$SRCDIR\game\client\c_vote_controller.cpp"
Under there add
$File "c_env_skydome.cpp"
$File "c_env_skydome.h"
Then open src/game/server/server_base.vpc Under $File "$SRCDIR\game\server\vote_controller.cpp"
Add
$file "env_skydome.cpp"
Now, rebuild your games.sln
Now we can go ahead and implement the rendering code.
Rendering code
First, we need to edit the client code for the sky dome. Go to src/game/client/view.cpp.
In void CViewRender::Init( void )
Under
m_ModulateSingleColor.Init( "engine/modulatesinglecolor", TEXTURE_GROUP_OTHER );
Add
m_SkydomeMaterial.Init("shaders/skydome", TEXTURE_GROUP_MODEL);
Now go to src/game/client/viewrender.h.
And under the function
void SetWaterOverlayMaterial( IMaterial *pMaterial )
Add
void DrawSky(const CViewSetup& view);
Find CMaterialReference m_UnderWaterOverlayMaterial;
Under that, add
CMaterialReference m_SkydomeMaterial;
Now we need to create the dome. To do that, go to src/game/client/viewrender.cpp.
Underneath the #include "sourcevr/isourcevirtualreality.h"
Add
#include "c_env_skydome.h"
Underneath the function void CViewRender::DrawViewModels( const CViewSetup &view, bool drawViewmodel )
Add
void CViewRender::DrawSky(const CViewSetup& view)
{
float flRadius = 32.0f;
int nTheta = 8;
int nPhi = 8;
CMatRenderContextPtr pRenderContext(materials);
pRenderContext->OverrideDepthEnable(true, false);
int nTriangles = 2 * nTheta * (nPhi - 1); // Two extra degenerate triangles per row (except the last one)
int nIndices = 2 * (nTheta + 1) * (nPhi - 1);
pRenderContext->Bind(m_SkydomeMaterial);
CMeshBuilder meshBuilder;
IMesh* pMesh = pRenderContext->GetDynamicMesh();
meshBuilder.Begin(pMesh, MATERIAL_TRIANGLE_STRIP, nTriangles, nIndices);
//
// Build the index buffer.
//
int i, j;
for (i = 0; i < nPhi; ++i)
{
for (j = 0; j < nTheta; ++j)
{
float u = j / (float)(nTheta - 1);
float v = i / (float)(nPhi - 1);
float theta = 2.0f * M_PI * u;
float phi = M_PI * v;
Vector vecPos;
vecPos.x = flRadius * sin(phi) * cos(theta);
vecPos.y = flRadius * sin(phi) * sin(theta);
vecPos.z = flRadius * cos(phi);
Vector vecNormal = vecPos;
VectorNormalize(vecNormal);
meshBuilder.Position3f(vecPos.x, vecPos.y, vecPos.z);
meshBuilder.AdvanceVertex();
}
}
//
// Emit the triangle strips.
//
int idx = 0;
for (i = nPhi - 2; i >= 0; --i)
{
for (j = nTheta - 1; j >= 0; --j)
{
idx = nTheta * i + j;
meshBuilder.Index(idx + nTheta);
meshBuilder.AdvanceIndex();
meshBuilder.Index(idx);
meshBuilder.AdvanceIndex();
}
//
// Emit a degenerate triangle to skip to the next row without
// a connecting triangle.
//
if (i < nPhi - 2)
{
meshBuilder.Index(idx);
meshBuilder.AdvanceIndex();
meshBuilder.Index(idx + nTheta + 1);
meshBuilder.AdvanceIndex();
}
}
pRenderContext->MatrixMode(MATERIAL_MODEL);
pRenderContext->PushMatrix();
pRenderContext->LoadIdentity();
pRenderContext->Translate(view.origin.x, view.origin.y, view.origin.z);
meshBuilder.End();
pMesh->Draw();
pRenderContext->MatrixMode(MATERIAL_MODEL);
pRenderContext->PopMatrix();
pRenderContext->OverrideDepthEnable(false, true);
}
Now to enable and disable drawing you need to go to void CRendering3dView::DrawWorld( float waterZAdjust )
And above unsigned long engineFlags = BuildEngineDrawWorldListFlags( m_DrawFlags );
Add
if ((m_DrawFlags & DF_DRAWSKYBOX) && (g_pSkyDome && g_pSkyDome->IsDynamicSkyEnabled()))
{
m_DrawFlags &= ~DF_DRAWSKYBOX; // dont render engine sky, we have our own sky now
m_pMainView->DrawSky(*this);
}
Shaders
Then open up game_shader_dx9_base.vpc and add under $File "screenspace_general.cpp"
$File "skydome_atmosphere.cpp"
$File "skydome_atmosphere_helper.cpp"
$File "skydome_atmosphere_helper.h"
Now, compile the skydome shaders. Then rebuild your shader vpc. Alright, now we need to make our sky dome accessible through hammer.
You will need a custom fgd entry for this to work.
@include "halflife2.fgd"
//-------------------------------------------------------------------------
// Environment (Global Light copy, also handles dynamic sky)
//-------------------------------------------------------------------------
@PointClass base(Targetname) iconsprite("editor/shadow_control.vmt") = env_skydome :
"An entity to control the sky dynamic sky."
[
sunpos(vector) : "Pitch Yaw Roll (Y Z X)" : "1 1 1 5" : "This is the light cast direction. Pitch is rotation around the Y axis, yaw is the rotation around the Z axis, and roll is the rotation around the X axis. THE LAST 0 IS FOR HOW BRIGHT THE SUN IS!!!!"
coverage(float) : "Coverage of clouds" : "0.50" : "How much of the clouds cover the sky"
thickness(float) : "Thickness of clouds" : "3" : "How thicker, how weirder the sky looks, DON'T GO ABOVE 100!"
windspeed(string) : "Dir and clearity of wind (X Y Z Clear)" : "0 0 0 5" : "Using stuff like .01 is a good habit as it is the most realistic"
// Inputs
input SetSunPos(vector) : "Set the position of the sun."
input SetWindSpeed(vector) : "Set the ambient color."
input InputSetThicknes(float) : "Set the thickness of the clouds."
input InputSetCoverage(float) : "Set how many clouds cover the sky."
input EnableDynamicSky(integer) : "Set if the sky is on or off"
]
Conclusion
You just need one last thing, and that is a material. Go to your materials folder and create a folder called shaders. Then create a .vmt material called skydome.vmt. Put this inside skydome.vmt
"SKYDOME_ATMOSPHERE"
{
"$lut" "skybox/sky_fake_white"
"$ALPHATESTREFERENCE" 1
}
Create a map with env_skydome in it and that's it! You should now have a dynamic sky in your mod.