[C++] Metin2 | Skybox Rework

  • Konuyu açan Konuyu açan Kaiser
  • Açılış Tarihi Açılış Tarihi
  • Yanıt Yanıt 9
  • Gösterim Gösterim 459

Kaiser

Admin
Admin
Geliştirici
Yardımsever Üye
Mesaj
4.376
Çözümler
439
Beğeni
4.906
Puan
1.849
Ticaret Puanı
0
UYARI:
Bu düzenleme hemen eklenip kullanılabilecek bir düzenleme değildir. Buradaki işlemleri yaptıktan sonra oyununuzda kaç tane gökyüzü seçeneği varsa, artık hiçbiri mevcut haliyle çalışmayacaktır ve dünya sahnesini bozacaktır. Buradaki işlemlerden sonra tüm gökyüzü dokularınızı Photoshop, GIMP vb. programlarla yeniden düzenlemek zorundasınız.
Ambiyans,material, ışık konumu ve diğer özellikleri bu yeni düzenleme ve doku işleme mantığına uygun şekilde düzenlemeniz gerekir!


Uzun zaman önce bir merakla ya da hevesle yapmaya başlayıp sonra kenarda beklettiğim sistemi az önce itibariyle bitirdim. Metin2'nin gökyüzü yapısında küp şeklinde çalışıyor ve bu küpün(6) her bir yüzü için ayrı ayrı dokular kullanılıyor ve giydiriliyor. Ben bu mantığı değiştirip tek bir yatay cross dokusuyla bu küpü giydirmenin daha kullanışlı olacağını düşünüyorum. Böylelikle yeni ve farklı bir gökyüzü kullanmak için sırf Metin2'ye uyumlu olması için tüm forumları araştırmak yerine, Google'dan bile bulduğunuz bir gökyüzünü artık oyuna ekleyebilirsiniz.

Hazırlaması zahmetliydi, kullanması da kullanıcılar için zahmetli olacak. Ancak temel yapıyı oluşturup oturttuktan sonra, ilerleyen süreçlerde bu düzenleme size esneklik ve rahatlık verecektir. Buradaki tek şart, kullanacağınız dokunun "cross" yapısında ve yatay olmasıdır. Kullanımı dinamikleştirmek için böyle bir şey düşünmüştüm ve sonunda hazır hale geldi. Geliştirmeye ve düzenlemeye açık ve müsait bir yapıdadır.

Başlamadan önce:
Cross gökyüzü nedir?
Cubemap türünde olan bir doku haritasıdır ve her projede farklı ölçülerde kullanılabiliyor. (1:1, 3:2, 4:3 vb.)
Metin2'nin kullandığı ölçü ise genellikle 4x3'dür.

Bu anlatımda kullanılan örnek(4 sütun, 3 satır):
dd.webp


Daha açık anlatmak gerekirse; sadece bu tür bir görseli pack içine atarak gökyüzü olarak kullanabilirsiniz. Ancak konuyla ilgili küçük ve önemli bir detay var. Onu aşağıda belirteceğim.

Anlatımı dikkatli olunması için basit ve geniş yapacağım. Lütfen işlemlere dikkat edin.

Locale_inc.h:
C++:
Genişlet Daralt Kopyala
#define REWORK_SKYBOX

EterLib/SkyBox.h:

C++:
Genişlet Daralt Kopyala
// Bul:
    void SetFaceTexture( const char* c_szFileName, int iFaceIndex);

// Değiştir:
#ifdef REWORK_SKYBOX
    void SetFaceTexture( const char* c_szFileName);
    void GetCrossUVCoordinates(int faceIndex, float& uMin, float& uMax, float& vMin, float& vMax);
#else
    void SetFaceTexture( const char* c_szFileName, int iFaceIndex );
#endif

////////////////////////////////////////
// Bul:
    void SetSkyObjectQuadVertical(TSkyObjectQuadVector * pSkyObjectQuadVector, const D3DXVECTOR2 * c_pv2QuadPoints);
    void SetSkyObjectQuadHorizon(TSkyObjectQuadVector * pSkyObjectQuadVector, const D3DXVECTOR3 * c_pv3QuadPoints);

// Değiştir:
#ifdef REWORK_SKYBOX
    void SetSkyObjectQuadVertical(TSkyObjectQuadVector* pSkyObjectQuadVector, const D3DXVECTOR2* c_pv2QuadPoints, int faceIndex);
    void SetSkyObjectQuadHorizon(TSkyObjectQuadVector* pSkyObjectQuadVector, const D3DXVECTOR3* c_pv3QuadPoints, int faceIndex);
#else
    void SetSkyObjectQuadVertical(TSkyObjectQuadVector * pSkyObjectQuadVector, const D3DXVECTOR2 * c_pv2QuadPoints);
    void SetSkyObjectQuadHorizon(TSkyObjectQuadVector * pSkyObjectQuadVector, const D3DXVECTOR3 * c_pv3QuadPoints);
#endif


EterLib/SkyBox.cpp:

Bunu bulun:
C++:
Genişlet Daralt Kopyala
void CSkyBox::SetFaceTexture(const char* c_szFileName)
{
    [...]
}

Tamamen değiştirin(#else kısmına dikkat edin!):
C++:
Genişlet Daralt Kopyala
#ifdef REWORK_SKYBOX
void CSkyBox::GetCrossUVCoordinates(int faceIndex, float& uMin, float& uMax, float& vMin, float& vMax)
{
    /*
    * WARNING:
        Kaiser:
        UV koordinatları ve dokularin dikilmesi "maksimum" hassasiyet gerektirir.
        Burayı düzenlemek veya degistirmek isterseniz bunu göz önünde bulundurun!
    */
    const float texWidth = 4096.0f;
    const float texHeight = 3072.0f;

    const float faceWidth = texWidth / 4.0f;
    const float faceHeight = texHeight / 3.0f;


    float pixelOverlapU = 3.0f / texWidth;
    float pixelOverlapV = 3.0f / texHeight;

    int col = 0, row = 0;

    switch (faceIndex)
    {
    case 0: // Ön (+Z)
        col = 2; row = 1;
        break;
    case 1: // Arka (-Z)
        col = 0; row = 1;
        break;
    case 2: // Sol (-X)
        col = 1; row = 1;
        break;
    case 3: // Sağ (+X)
        col = 3; row = 1;
        break;
    case 4: // Üst (+Y)
        col = 1; row = 0;
        break;
    case 5: // Alt (-Y)
        col = 1; row = 2;
        break;
    default:
        uMin = 0.0f; uMax = 1.0f;
        vMin = 0.0f; vMax = 1.0f;
        return;
    }

    float pxMinU = col * faceWidth;
    float pxMaxU = (col + 1) * faceWidth;
    float pxMinV = row * faceHeight;
    float pxMaxV = (row + 1) * faceHeight;

    uMin = (pxMinU / texWidth) + pixelOverlapU;
    uMax = (pxMaxU / texWidth) - pixelOverlapU;
    vMin = (pxMinV / texHeight) + pixelOverlapV;
    vMax = (pxMaxV / texHeight) - pixelOverlapV;
}
void CSkyBox::SetFaceTexture(const char* c_szFileName)
{
    if (!c_szFileName || strlen(c_szFileName) <= 0)
        return;

    TGraphicImageInstanceMap::iterator itor = m_GraphicImageInstanceMap.find(c_szFileName);
    if (itor != m_GraphicImageInstanceMap.end())
        return;

    CGraphicImageInstance* pGraphicImageInstance = GenerateTexture(c_szFileName);
    if (pGraphicImageInstance)
    {
        m_GraphicImageInstanceMap.insert(TGraphicImageInstanceMap::value_type(c_szFileName, pGraphicImageInstance));
    }
    for (int i = 0; i < 6; ++i)
    {
        m_Faces[i].m_strFaceTextureFileName = c_szFileName;
    }
}
#else
// BURAYA ORJINAL SetFaceTexture KOD BLOĞUNU YAPIŞTIRIN!!!!!
#endif

Bu 3 fonksiyonu bulun: genellikle alt alta bulunurlar:
C++:
Genişlet Daralt Kopyala
void CSkyBox::SetSkyObjectQuadVertical(TSkyObjectQuadVector * pSkyObjectQuadVector, const D3DXVECTOR2 * c_pv2QuadPoints)
{
    [...]
}
void CSkyBox::SetSkyObjectQuadHorizon(TSkyObjectQuadVector* pSkyObjectQuadVector, const D3DXVECTOR3* c_pv3QuadPoints)
{
    [...]
}
void CSkyBox::Refresh()
{
    [...]
}
Tamamen değiştirin(#else kısmına dikkat edin!):
C++:
Genişlet Daralt Kopyala
#ifdef REWORK_SKYBOX
void CSkyBox::SetSkyObjectQuadVertical(TSkyObjectQuadVector* pSkyObjectQuadVector, const D3DXVECTOR2* c_pv2QuadPoints, int faceIndex)
{
    TPDTVertex aPDTVertex;
    DWORD dwIndex = 0;

    pSkyObjectQuadVector->clear();
    pSkyObjectQuadVector->resize(m_ucVirticalGradientLevelUpper + m_ucVirticalGradientLevelLower);

    float uMin, uMax, vMin, vMax;
    GetCrossUVCoordinates(faceIndex, uMin, uMax, vMin, vMax);

    unsigned char ucY;
    for (ucY = 0; ucY < m_ucVirticalGradientLevelUpper; ++ucY)
    {
        CSkyObjectQuad& rSkyObjectQuad = pSkyObjectQuadVector->at(dwIndex++);

        aPDTVertex.position.x = c_pv2QuadPoints[0].x;
        aPDTVertex.position.y = c_pv2QuadPoints[0].y;
        aPDTVertex.position.z = 1.0f - (float)(ucY + 1) / (float)(m_ucVirticalGradientLevelUpper);
        aPDTVertex.texCoord.x = uMin;
        aPDTVertex.texCoord.y = vMin + ((float)(ucY + 1) / (float)(m_ucVirticalGradientLevelUpper) * (vMax - vMin));
        rSkyObjectQuad.SetVertex(0, aPDTVertex);

        aPDTVertex.position.x = c_pv2QuadPoints[0].x;
        aPDTVertex.position.y = c_pv2QuadPoints[0].y;
        aPDTVertex.position.z = 1.0f - (float)(ucY) / (float)(m_ucVirticalGradientLevelUpper);
        aPDTVertex.texCoord.x = uMin;
        aPDTVertex.texCoord.y = vMin + ((float)(ucY) / (float)(m_ucVirticalGradientLevelUpper) * (vMax - vMin));
        rSkyObjectQuad.SetVertex(1, aPDTVertex);

        aPDTVertex.position.x = c_pv2QuadPoints[1].x;
        aPDTVertex.position.y = c_pv2QuadPoints[1].y;
        aPDTVertex.position.z = 1.0f - (float)(ucY + 1) / (float)(m_ucVirticalGradientLevelUpper);
        aPDTVertex.texCoord.x = uMax;
        aPDTVertex.texCoord.y = vMin + ((float)(ucY + 1) / (float)(m_ucVirticalGradientLevelUpper) * (vMax - vMin));
        rSkyObjectQuad.SetVertex(2, aPDTVertex);

        aPDTVertex.position.x = c_pv2QuadPoints[1].x;
        aPDTVertex.position.y = c_pv2QuadPoints[1].y;
        aPDTVertex.position.z = 1.0f - (float)(ucY) / (float)(m_ucVirticalGradientLevelUpper);
        aPDTVertex.texCoord.x = uMax;
        aPDTVertex.texCoord.y = vMin + ((float)(ucY) / (float)(m_ucVirticalGradientLevelUpper) * (vMax - vMin));
        rSkyObjectQuad.SetVertex(3, aPDTVertex);
    }
    for (ucY = 0; ucY < m_ucVirticalGradientLevelLower; ++ucY)
    {
        CSkyObjectQuad& rSkyObjectQuad = pSkyObjectQuadVector->at(dwIndex++);

        aPDTVertex.position.x = c_pv2QuadPoints[0].x;
        aPDTVertex.position.y = c_pv2QuadPoints[0].y;
        aPDTVertex.position.z = -(float)(ucY + 1) / (float)(m_ucVirticalGradientLevelLower);
        aPDTVertex.texCoord.x = uMin;
        aPDTVertex.texCoord.y = vMin + (0.5f + (float)(ucY + 1) / (float)(m_ucVirticalGradientLevelUpper) * (vMax - vMin));
        rSkyObjectQuad.SetVertex(0, aPDTVertex);

        aPDTVertex.position.x = c_pv2QuadPoints[0].x;
        aPDTVertex.position.y = c_pv2QuadPoints[0].y;
        aPDTVertex.position.z = -(float)(ucY) / (float)(m_ucVirticalGradientLevelLower);
        aPDTVertex.texCoord.x = uMin;
        aPDTVertex.texCoord.y = vMin + (0.5f + (float)(ucY) / (float)(m_ucVirticalGradientLevelUpper) * (vMax - vMin));
        rSkyObjectQuad.SetVertex(1, aPDTVertex);

        aPDTVertex.position.x = c_pv2QuadPoints[1].x;
        aPDTVertex.position.y = c_pv2QuadPoints[1].y;
        aPDTVertex.position.z = -(float)(ucY + 1) / (float)(m_ucVirticalGradientLevelLower);
        aPDTVertex.texCoord.x = uMax;
        aPDTVertex.texCoord.y = vMin + (0.5f + (float)(ucY + 1) / (float)(m_ucVirticalGradientLevelUpper) * (vMax - vMin));
        rSkyObjectQuad.SetVertex(2, aPDTVertex);

        aPDTVertex.position.x = c_pv2QuadPoints[1].x;
        aPDTVertex.position.y = c_pv2QuadPoints[1].y;
        aPDTVertex.position.z = -(float)(ucY) / (float)(m_ucVirticalGradientLevelLower);
        aPDTVertex.texCoord.x = uMax;
        aPDTVertex.texCoord.y = vMin + (0.5f + (float)(ucY) / (float)(m_ucVirticalGradientLevelUpper) * (vMax - vMin));
        rSkyObjectQuad.SetVertex(3, aPDTVertex);
    }
}
void CSkyBox::SetSkyObjectQuadHorizon(TSkyObjectQuadVector* pSkyObjectQuadVector, const D3DXVECTOR3* c_pv3QuadPoints, int faceIndex)
{
    pSkyObjectQuadVector->clear();
    pSkyObjectQuadVector->resize(1);
    CSkyObjectQuad& rSkyObjectQuad = pSkyObjectQuadVector->at(0);

    float uMin, uMax, vMin, vMax;
    GetCrossUVCoordinates(faceIndex, uMin, uMax, vMin, vMax);

    TPDTVertex aPDTVertex;
    aPDTVertex.position = c_pv3QuadPoints[0];
    aPDTVertex.texCoord.x = uMin;
    aPDTVertex.texCoord.y = vMax;
    rSkyObjectQuad.SetVertex(0, aPDTVertex);

    aPDTVertex.position = c_pv3QuadPoints[1];
    aPDTVertex.texCoord.x = uMin;
    aPDTVertex.texCoord.y = vMin;
    rSkyObjectQuad.SetVertex(1, aPDTVertex);

    aPDTVertex.position = c_pv3QuadPoints[2];
    aPDTVertex.texCoord.x = uMax;
    aPDTVertex.texCoord.y = vMax;
    rSkyObjectQuad.SetVertex(2, aPDTVertex);

    aPDTVertex.position = c_pv3QuadPoints[3];
    aPDTVertex.texCoord.x = uMax;
    aPDTVertex.texCoord.y = vMin;
    rSkyObjectQuad.SetVertex(3, aPDTVertex);
}
void CSkyBox::Refresh()
{
    D3DXVECTOR3 v3QuadPoints[4];

    if (m_ucRenderMode == CSkyObject::SKY_RENDER_MODE_DEFAULT || m_ucRenderMode == CSkyObject::SKY_RENDER_MODE_DIFFUSE)
    {
        if (m_ucVirticalGradientLevelUpper + m_ucVirticalGradientLevelLower <= 0)
            return;

        D3DXVECTOR2 v2QuadPoints[2];

        // Face 0: FRONT
        v2QuadPoints[0] = D3DXVECTOR2(1.0f, -1.0f);
        v2QuadPoints[1] = D3DXVECTOR2(-1.0f, -1.0f);
        SetSkyObjectQuadVertical(&m_Faces[0].m_SkyObjectQuadVector, v2QuadPoints, 0);
        m_Faces[0].m_strfacename = "front";

        // Face 1: BACK
        v2QuadPoints[0] = D3DXVECTOR2(-1.0f, 1.0f);
        v2QuadPoints[1] = D3DXVECTOR2(1.0f, 1.0f);
        SetSkyObjectQuadVertical(&m_Faces[1].m_SkyObjectQuadVector, v2QuadPoints, 1);
        m_Faces[1].m_strfacename = "back";

        // Face 2: LEFT
        v2QuadPoints[0] = D3DXVECTOR2(-1.0f, -1.0f);
        v2QuadPoints[1] = D3DXVECTOR2(-1.0f, 1.0f);
        SetSkyObjectQuadVertical(&m_Faces[2].m_SkyObjectQuadVector, v2QuadPoints, 2);
        m_Faces[2].m_strfacename = "left";

        // Face 3: RIGHT
        v2QuadPoints[0] = D3DXVECTOR2(1.0f, 1.0f);
        v2QuadPoints[1] = D3DXVECTOR2(1.0f, -1.0f);
        SetSkyObjectQuadVertical(&m_Faces[3].m_SkyObjectQuadVector, v2QuadPoints, 3);
        m_Faces[3].m_strfacename = "right";

        // Face 4: TOP
        v3QuadPoints[0] = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
        v3QuadPoints[1] = D3DXVECTOR3(-1.0f, 1.0f, 1.0f);
        v3QuadPoints[2] = D3DXVECTOR3(1.0f, -1.0f, 1.0f);
        v3QuadPoints[3] = D3DXVECTOR3(-1.0f, -1.0f, 1.0f);
        SetSkyObjectQuadHorizon(&m_Faces[4].m_SkyObjectQuadVector, v3QuadPoints, 4);
        m_Faces[4].m_strfacename = "top";

        // Face 5: BOTTOM
        v3QuadPoints[0] = D3DXVECTOR3(-1.0f, 1.0f, -1.0f);
        v3QuadPoints[1] = D3DXVECTOR3(1.0f, 1.0f, -1.0f);
        v3QuadPoints[2] = D3DXVECTOR3(-1.0f, -1.0f, -1.0f);
        v3QuadPoints[3] = D3DXVECTOR3(1.0f, -1.0f, -1.0f);
        SetSkyObjectQuadHorizon(&m_Faces[5].m_SkyObjectQuadVector, v3QuadPoints, 5);
        m_Faces[5].m_strfacename = "bottom";
    }
    else if (m_ucRenderMode == CSkyObject::SKY_RENDER_MODE_TEXTURE)
    {
        // Face 0: FRONT (+Z)
        v3QuadPoints[0] = D3DXVECTOR3(1.0f, -1.0f, -1.0f);
        v3QuadPoints[1] = D3DXVECTOR3(1.0f, -1.0f, 1.0f);
        v3QuadPoints[2] = D3DXVECTOR3(-1.0f, -1.0f, -1.0f);
        v3QuadPoints[3] = D3DXVECTOR3(-1.0f, -1.0f, 1.0f);
        SetSkyObjectQuadHorizon(&m_Faces[0].m_SkyObjectQuadVector, v3QuadPoints, 0);
        m_Faces[0].m_strfacename = "front";

        // Face 1: BACK (-Z)
        v3QuadPoints[0] = D3DXVECTOR3(-1.0f, 1.0f, -1.0f);
        v3QuadPoints[1] = D3DXVECTOR3(-1.0f, 1.0f, 1.0f);
        v3QuadPoints[2] = D3DXVECTOR3(1.0f, 1.0f, -1.0f);
        v3QuadPoints[3] = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
        SetSkyObjectQuadHorizon(&m_Faces[1].m_SkyObjectQuadVector, v3QuadPoints, 1);
        m_Faces[1].m_strfacename = "back";

        // Face 2: LEFT (-X)
        v3QuadPoints[0] = D3DXVECTOR3(1.0f, 1.0f, -1.0f);
        v3QuadPoints[1] = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
        v3QuadPoints[2] = D3DXVECTOR3(1.0f, -1.0f, -1.0f);
        v3QuadPoints[3] = D3DXVECTOR3(1.0f, -1.0f, 1.0f);
        SetSkyObjectQuadHorizon(&m_Faces[2].m_SkyObjectQuadVector, v3QuadPoints, 2);
        m_Faces[2].m_strfacename = "left";

        // Face 3: RIGHT (+X)
        v3QuadPoints[0] = D3DXVECTOR3(-1.0f, -1.0f, -1.0f);
        v3QuadPoints[1] = D3DXVECTOR3(-1.0f, -1.0f, 1.0f);
        v3QuadPoints[2] = D3DXVECTOR3(-1.0f, 1.0f, -1.0f);
        v3QuadPoints[3] = D3DXVECTOR3(-1.0f, 1.0f, 1.0f);
        SetSkyObjectQuadHorizon(&m_Faces[3].m_SkyObjectQuadVector, v3QuadPoints, 3);
        m_Faces[3].m_strfacename = "right";

        // Face 4: TOP (+Y)
        v3QuadPoints[0] = D3DXVECTOR3(1.0f, -1.0f, 1.0f);
        v3QuadPoints[1] = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
        v3QuadPoints[2] = D3DXVECTOR3(-1.0f, -1.0f, 1.0f);
        v3QuadPoints[3] = D3DXVECTOR3(-1.0f, 1.0f, 1.0f);
        SetSkyObjectQuadHorizon(&m_Faces[4].m_SkyObjectQuadVector, v3QuadPoints, 4);
        m_Faces[4].m_strfacename = "top";

        // Face 5: BOTTOM (-Y)
        v3QuadPoints[0] = D3DXVECTOR3(1.0f, 1.0f, -1.0f);
        v3QuadPoints[1] = D3DXVECTOR3(1.0f, -1.0f, -1.0f);
        v3QuadPoints[2] = D3DXVECTOR3(-1.0f, 1.0f, -1.0f);
        v3QuadPoints[3] = D3DXVECTOR3(-1.0f, -1.0f, -1.0f);
        SetSkyObjectQuadHorizon(&m_Faces[5].m_SkyObjectQuadVector, v3QuadPoints, 5);
        m_Faces[5].m_strfacename = "bottom";
    }

    // Clouds
    v3QuadPoints[0] = D3DXVECTOR3(1.0f, 1.0f, 0.0f);
    v3QuadPoints[1] = D3DXVECTOR3(-1.0f, 1.0f, 0.0f);
    v3QuadPoints[2] = D3DXVECTOR3(1.0f, -1.0f, 0.0f);
    v3QuadPoints[3] = D3DXVECTOR3(-1.0f, -1.0f, 0.0f);
    SetSkyObjectQuadHorizon(&m_FaceCloud.m_SkyObjectQuadVector, v3QuadPoints, 0); // Kaiser: bulutlar bu duzenlemeden muaftir = 0
}
#else
// BU 3 FONKSIYONUN ORJINAL KOD BLOKLARINI BURAYA YAPIŞTIRIN !!!!!!!!!!!!!!
#endif

Bulun:
C++:
Genişlet Daralt Kopyala
void CSkyBox::Render()
{
    [...]
}

Tamamen değiştirin(#else kısmına dikkat edin!):
C++:
Genişlet Daralt Kopyala
#ifdef REWORK_SKYBOX
void CSkyBox::Render()
{
    STATEMANAGER.SaveRenderState(D3DRS_ZENABLE, TRUE);
    STATEMANAGER.SaveRenderState(D3DRS_ZWRITEENABLE, FALSE);
    STATEMANAGER.SaveRenderState(D3DRS_LIGHTING, FALSE);
    STATEMANAGER.SaveRenderState(D3DRS_FOGENABLE, FALSE);
    STATEMANAGER.SaveRenderState(D3DRS_ALPHABLENDENABLE, FALSE);

    STATEMANAGER.SaveTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG2);
    STATEMANAGER.SaveTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
    STATEMANAGER.SaveTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);

    STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);

    STATEMANAGER.SetTexture(1, NULL);
    STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
    STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);

    STATEMANAGER.SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);

    STATEMANAGER.SetTransform(D3DTS_WORLD, &m_matWorld);

    // Render Face
    if (m_ucRenderMode == CSkyObject::SKY_RENDER_MODE_TEXTURE)
    {
        CGraphicImageInstance* pFaceImageInstance = m_GraphicImageInstanceMap[m_Faces[0].m_strFaceTextureFileName];
        if (!pFaceImageInstance)
        {
            TraceError("Skybox Face Texture NULL!");
            return;
        }
        STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
        STATEMANAGER.SaveSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
        STATEMANAGER.SaveSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
        STATEMANAGER.SetTexture(0, pFaceImageInstance->GetTextureReference().GetD3DTexture());

        for (unsigned int i = 0; i < 6; ++i)
        {
            m_Faces[i].Render();
        }

        STATEMANAGER.RestoreSamplerState(0, D3DSAMP_ADDRESSU);
        STATEMANAGER.RestoreSamplerState(0, D3DSAMP_ADDRESSV);
    }
    else
    {
        for (unsigned int i = 0; i < 6; ++i)
        {
            m_Faces[i].Render();
        }
    }

    STATEMANAGER.RestoreRenderState(D3DRS_LIGHTING);
    STATEMANAGER.RestoreRenderState(D3DRS_ZENABLE);
    STATEMANAGER.RestoreRenderState(D3DRS_ZWRITEENABLE);
    STATEMANAGER.RestoreRenderState(D3DRS_FOGENABLE);
    STATEMANAGER.RestoreRenderState(D3DRS_ALPHABLENDENABLE);

    STATEMANAGER.RestoreTextureStageState(0, D3DTSS_COLOROP);
    STATEMANAGER.RestoreTextureStageState(0, D3DTSS_COLORARG1);
    STATEMANAGER.RestoreTextureStageState(0, D3DTSS_COLORARG2);
}
#else
// BURAYA ORJINAL Render FONKSIYON KOD BLOĞUNU YAPIŞTIRIN !!!!!!!!!!
#endif

GameLib/MapOutdoor.cpp:
Bulun:
C++:
Genişlet Daralt Kopyala
    for( int i = 0; i < 6; ++i )
    {
        if (!mc_pEnvironmentData->strSkyBoxFaceFileName[i].empty())
            m_SkyBox.SetFaceTexture( mc_pEnvironmentData->strSkyBoxFaceFileName[i].c_str(), i );
    }
Değiştirin:
C++:
Genişlet Daralt Kopyala
#ifdef REWORK_SKYBOX
    if (!mc_pEnvironmentData->strSkyBoxFaceFileName.empty())
        m_SkyBox.SetFaceTexture(mc_pEnvironmentData->strSkyBoxFaceFileName.c_str());
#else
    for( int i = 0; i < 6; ++i )
    {
        if (!mc_pEnvironmentData->strSkyBoxFaceFileName[i].empty())
            m_SkyBox.SetFaceTexture( mc_pEnvironmentData->strSkyBoxFaceFileName[i].c_str(), i );
    }
#endif

GameLib/MapType.h:
Bulun ve değiştirin:
C++:
Genişlet Daralt Kopyala
#ifdef REWORK_SKYBOX
    std::string strSkyBoxFaceFileName; // AIO
#else
    std::string strSkyBoxFaceFileName[6]; //order
#endif
GameLib/MapUtil.cpp:
Bulun:
C++:
Genişlet Daralt Kopyala
        textLoader.GetTokenString("frontfacefilename", &envData.strSkyBoxFaceFileName[0]);
        textLoader.GetTokenString("backfacefilename", &envData.strSkyBoxFaceFileName[1]);
        textLoader.GetTokenString("leftfacefilename", &envData.strSkyBoxFaceFileName[2]);
        textLoader.GetTokenString("rightfacefilename", &envData.strSkyBoxFaceFileName[3]);
        textLoader.GetTokenString("topfacefilename", &envData.strSkyBoxFaceFileName[4]);
        textLoader.GetTokenString("bottomfacefilename", &envData.strSkyBoxFaceFileName[5]);

Değiştirin:
C++:
Genişlet Daralt Kopyala
#ifdef REWORK_SKYBOX
        textLoader.GetTokenString("setskyboximage", &envData.strSkyBoxFaceFileName);
#else
        textLoader.GetTokenString("frontfacefilename", &envData.strSkyBoxFaceFileName[0]);
        textLoader.GetTokenString("backfacefilename", &envData.strSkyBoxFaceFileName[1]);
        textLoader.GetTokenString("leftfacefilename", &envData.strSkyBoxFaceFileName[2]);
        textLoader.GetTokenString("rightfacefilename", &envData.strSkyBoxFaceFileName[3]);
        textLoader.GetTokenString("topfacefilename", &envData.strSkyBoxFaceFileName[4]);
        textLoader.GetTokenString("bottomfacefilename", &envData.strSkyBoxFaceFileName[5]);
#endif


Tüm değişiklikler bu kadar. Yukarıda bahsettiğim küçük ve önemli detay ise, kullanacağınız gökyüzü dokusunda +Y konumunu(en üst) 90° derece sağ döndürmeniz gerek. Sebebini anlamadım fakat Metin2 bu koordinattaki dokuyu bu şekilde işliyor. Aksi halde gökyüzünde en tepe noktasının dokusu ters olacaktır.
Görsel:
ans.webp

.msenv Dosyasında Örnek kullanım:
Kod:
Genişlet Daralt Kopyala
Group SkyBox
{
    bTextureRenderMode    1
    Scale                 1500.000000 3000.000000 1500.000000
    GradientLevelUpper    4
    GradientLevelLower    1
    SetSkyBoxImage       "D:\ymir work\environment\Skybox\vanilia\test1.dds"
 
    CloudScale            0.000000 0.000000
    CloudHeight           30000.000000
    CloudTextureScale     0.000000 0.000000
    CloudSpeed            0.000000 0.000000
    CloudTextureFileName  ""
    List CloudColor
    {
        0.000000 0.000000 0.000000 0.000000
        0.000000 0.000000 0.000000 0.000000
    }
    List Gradient
    {
        0.764706 0.792157 0.823529 0.000000
        0.000000 0.000000 0.000000 0.000000
    
        0.796078 0.835294 0.874510 0.000000
        0.000000 0.000000 0.000000 0.000000
    }
}

Dosya formatı PNG ve DDS olarak tercih edilebilir.
Alpha kanalı olmadan DDS formatı: DXT1
Alpha kanalı varsa DDS formatı: DXT5 (Dosya boyutu artabilir.)

Final:
Ekran görüntüsü 2025-04-16 190934.webp
 
hocam elinize sağlık world editorda skybox işlerken bende cross skyboxları parçalara bölüp kullanıyordum ayrı ayrı dosyalar olarak. cross kullanmanın ekstra faydası nedir bilmediğimden dolayı soruyorum bir de eski tip skyboxlar bu eklentiyle kullanılabilir mi
 
hocam elinize sağlık world editorda skybox işlerken bende cross skyboxları parçalara bölüp kullanıyordum ayrı ayrı dosyalar olarak. cross kullanmanın ekstra faydası nedir bilmediğimden dolayı soruyorum bir de eski tip skyboxlar bu eklentiyle kullanılabilir mi
Teoride ikisinin de çalışma mantığı aynıdır, bir küpün 6 yüzünü de giydirerek çalışırlar. Avantajlı ve dezavantajlı olması durumu ise kullanıcının bilgisiyle orantılı bir şey açıkçası. Yani klasik yöntemle daha iyi çalışan birisi, bunda zorlanabilir. Veya bu şekilde çalışıp düzenlemeler yapmak bazılarının daha kolayına gelebilir. Teknik olarak bakıldığında ise dosya/bellek açısından doğru işlemler yapıldığında bu yöntem daha kullanışlıdır.

Örnek: Kaliteli bir görseli 6 eş parçaya bölüp küp(gökyüzü) olarak kullanabilmek için, en oranı, boy oranının 2 katı olmak zorundadır. 4096x2048 gibi. Bu boyutlarda bir görseli 6 parçaya bölüp PNG veya DDS olarak kullandığında her biri 1024x1024 boyutunda ve her biri yaklaşık 1mb olan dokular oluşacaktır.
Bu senaryoya göre: 6 doku = 6mb.

Ancak küp haritalarında durum birazcık farklı. Metin2 4:3 ölçülerde bir harita kullandığından, hazır cross görsellerinin boyutu da aşağıdakiler gibi olmalıdır:
  • 640x480
  • 800x600
  • 1024x768
  • 1280x960
  • 1600x1200
  • 4096x3072

Burada 4096x3072 boyutlarında bir harita bile PNG olarak kullanıldığında (ortalama 2-3MB) ile gökyüzü giydirilmiş olur.
Ayrıca kaynak kodlarında da 6 farklı dokuyu işlemekle, 1 dokuyu 6 şekilde işlemek bellek/grafik apisi açısından farklıdır.

Bu söylediklerime JPG'i dahil edersek işler değişebilir fakat kalite kaybı sebebiyle JPG'i tercih etmiyorum. Bu yüzden kalite kaybı olmayan diğer uzantılar üzerinden açıkladım.

Şahsen benim için tek dosya üzerinden düzenleme yapmak daha pratik. Hangi dokunun nereyi temsil ettiğini bildikten sonra daha da kullanışlı oluyor.

d.webp

Cross haritası dediğimiz şey, gökyüzü için kullanılan 6 farklı dokunun mükemmel bir hizalamayla birleşmiş halidir aslında. Metin2 için de aynı şey geçerlidir.
Tabii en nihayetinde bunu kullanıp kullanmamak bir tercih meselesi.

Son olarak benim verdiğim kodlar "UYARI" kısmında da belirttiğim gibi her iki yapıyı kullanmaya müsait değil. Bunun için kodlarda birkaç ufak değişiklikler gerekiyor.
 
Emeğin için teşekkürler. Final görseli dx9 mu yoksa gökyüzüyle alakalı mı grafikler?
 
Geri
Üst