Adding a dynamic sky to your mod

From Valve Developer Community
Jump to navigation Jump to search
English (en)Русский (ru)Translate (Translate)


The dynamic sky


This article will show you how to implement a dynamic sky for your mod. This tutorial uses code from the canceled mod Vance.

Warning.pngWarning:This shader is performance wise heavy, and decreases your fps by 25-40. So it is best to use on beefy computers only

Requirements

  • Ability to compile shaders.
  • Ability to compile the solution.


Note.pngNote:If you do not know how to compile shaders, or haven't worked with shaders in Source yet, it is advised that you follow and understand these articles first: Shader Authoring & Your First Shader

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"
Note.pngNote:This should fix any undefined errors for g_pSkyDome

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

Note.pngNote:Clear out all the files in stdshader_dx9_30.txt and make sure that only skydome_ps30 and skydome_vs30 are in your stdshader_dx9_30.txt file, to make compiling the shaders faster(DON'T FORGET TO CLEAR stdshader_dx9_20b.txt)

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.