Эта статья покажет вам как реализовать динамическое небо в вашем
Source 2013 моде.
Примечание:Это руководство использует код из отмененного мода Vance
Предупреждение:Этот шейдер очень требовательный и снижает частоту кадров в секунду на 25-40. Поэтому лучше использовать его только на мощных компьютерах
Требования
- Умение компилировать шейдеры.
- Умение компилировать решения.
Реализация
Прежде чем что-то делать, нам нужно скачать файлы. Они внутри zip-архива.
Когда вы загрузите zip-файл, извлеките файлы из shaders
в: ![🖿](/w/images/thumb/1/11/Icon-gnome-folder_alt.png/15px-Icon-gnome-folder_alt.png)
src/materialsystem/stdshaders/
, а файлы из code
в: ![🖿](/w/images/thumb/1/11/Icon-gnome-folder_alt.png/15px-Icon-gnome-folder_alt.png)
src/game/
Откройте ![File](/w/images/thumb/1/15/Icon-File-filled-cropped.png/15px-Icon-File-filled-cropped.png)
src/game/client/client_base.vpc
Перейдите к строке $File "$SRCDIR\game\client\c_vote_controller.cpp"
и под ней добавьте:
$File "c_env_skydome.cpp"
$File "c_env_skydome.h"
Далее откройте ![File](/w/images/thumb/1/15/Icon-File-filled-cropped.png/15px-Icon-File-filled-cropped.png)
src/game/server/server_base.vpc
и под $File "$SRCDIR\game\server\vote_controller.cpp"
добавьте:
И после этого, пересоберите свое ![File](/w/images/thumb/1/15/Icon-File-filled-cropped.png/15px-Icon-File-filled-cropped.png)
games.sln
решение.
Теперь мы можем перейти к реализации кода отрисовки.
Код отрисовки
Сначала нам нужно отредактировать код клиента для динамического неба.
Откройте ![File](/w/images/thumb/1/15/Icon-File-filled-cropped.png/15px-Icon-File-filled-cropped.png)
src/game/client/view.cpp
В функции void CViewRender::Init( void )
, под m_ModulateSingleColor.Init( "engine/modulatesinglecolor", TEXTURE_GROUP_OTHER );
добавьте:
m_SkydomeMaterial.Init("shaders/skydome", TEXTURE_GROUP_MODEL);
Теперь откройте ![File](/w/images/thumb/1/15/Icon-File-filled-cropped.png/15px-Icon-File-filled-cropped.png)
src/game/client/viewrender.h
И под функцией void SetWaterOverlayMaterial( IMaterial *pMaterial )
добавьте:
void DrawSky(const CViewSetup& view);
Найдите CMaterialReference m_UnderWaterOverlayMaterial;
и под этим добавьте:
CMaterialReference m_SkydomeMaterial;
Теперь нам нужно создать купол. Чтобы сделать это, откройте ![File](/w/images/thumb/1/15/Icon-File-filled-cropped.png/15px-Icon-File-filled-cropped.png)
src/game/client/viewrender.cpp
Под #include "sourcevr/isourcevirtualreality.h"
добавьте:
#include "c_env_skydome.h"
Примечание:Это должно исправить все ошибки с отсутствием определения для g_pSkyDome
Под функцией void CViewRender::DrawViewModels( const CViewSetup &view, bool drawViewmodel )
добавьте:
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 = 0; i < nPhi - 1; ++i )
{
for ( j = 0; j < nTheta; ++j )
{
idx = nTheta * i + j;
meshBuilder.Index( idx );
meshBuilder.AdvanceIndex();
meshBuilder.Index( idx + nTheta );
meshBuilder.AdvanceIndex();
}
//
// Emit a degenerate triangle to skip to the next row without
// a connecting triangle.
//
if ( i < nPhi - 2 )
{
meshBuilder.Index( idx + nTheta );
meshBuilder.AdvanceIndex();
meshBuilder.Index( ( i + 1 ) * nTheta );
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);
}
Теперь для включения и отключения отрисовки вам нужно перейти к функции void CRendering3dView::DrawWorld( float waterZAdjust )
и
выше unsigned long engineFlags = BuildEngineDrawWorldListFlags( m_DrawFlags );
добавить:
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);
}
Шейдеры
Примечание:Удалите все файлы из ![File](/w/images/thumb/1/15/Icon-File-filled-cropped.png/15px-Icon-File-filled-cropped.png)
stdshader_dx9_30.txt
и убедитесь, что в вашем ![File](/w/images/thumb/1/15/Icon-File-filled-cropped.png/15px-Icon-File-filled-cropped.png)
stdshader_dx9_30.txt
файле есть только skydome_ps30
и skydome_vs30
, чтобы ускорить компиляцию шейдеров (НЕ ЗАБУДЬТЕ ОЧИСТИТЬ ![File](/w/images/thumb/1/15/Icon-File-filled-cropped.png/15px-Icon-File-filled-cropped.png)
stdshader_dx9_20b.txt
)
А теперь откройте ![File](/w/images/thumb/1/15/Icon-File-filled-cropped.png/15px-Icon-File-filled-cropped.png)
game_shader_dx9_base.vpc
И под $File "screenspace_general.cpp"
добавьте:
$File "skydome_atmosphere.cpp"
$File "skydome_atmosphere_helper.cpp"
$File "skydome_atmosphere_helper.h"
Скомпилируйте шейдер динамического неба и пересоберите ваше решение.
Хорошо, а сейчас нам нужно сделать наше динамическое небо доступным через
Hammer.
Для этого вам понадобиться пользовательский fgd(en) файл.
@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"
]
Заключение
Теперь вам нужна последняя деталь и это - материал.
Перейдите в вашу директорию ![🖿](/w/images/thumb/1/11/Icon-gnome-folder_alt.png/15px-Icon-gnome-folder_alt.png)
materials
и создайте поддиректорию с названием ![🖿](/w/images/thumb/1/11/Icon-gnome-folder_alt.png/15px-Icon-gnome-folder_alt.png)
shaders
После этого, создайте файл ![File](/w/images/thumb/1/15/Icon-File-filled-cropped.png/15px-Icon-File-filled-cropped.png)
skydome.vmt
и вставьте это внутрь:
"SKYDOME_ATMOSPHERE"
{
"$lut" "skybox/sky_fake_white"
"$ALPHATESTREFERENCE" 1
}
Создайте карту с сущностью env_skydome
и вот оно! Теперь в вашем моде должно быть динамическое небо.