From 8f77cee77db38eb0b210f77f46793427068855c3 Mon Sep 17 00:00:00 2001 From: jarmonik Date: Mon, 13 Nov 2023 05:43:37 +0200 Subject: [PATCH] Implemented loading of baked sunlight ambient occlusion textures. Implemented pre-bake shader. --- OVP/D3D9Client/D3D9Surface.cpp | 47 ++++---- OVP/D3D9Client/D3D9Surface.h | 3 +- OVP/D3D9Client/Mesh.cpp | 127 +++++++++++++++++++++- OVP/D3D9Client/Mesh.h | 8 +- OVP/D3D9Client/Scene.cpp | 1 + OVP/D3D9Client/VVessel.cpp | 2 + OVP/D3D9Client/shaders/PreBakeLights.hlsl | 14 +++ 7 files changed, 171 insertions(+), 31 deletions(-) diff --git a/OVP/D3D9Client/D3D9Surface.cpp b/OVP/D3D9Client/D3D9Surface.cpp index 349d4ed70..73a0324e6 100644 --- a/OVP/D3D9Client/D3D9Surface.cpp +++ b/OVP/D3D9Client/D3D9Surface.cpp @@ -59,7 +59,7 @@ void NatCheckFlags(DWORD &flags) // =============================================================================================== // Load a simple plain texture // -LPDIRECT3DTEXTURE9 NatLoadTexture(const char* path) +LPDIRECT3DTEXTURE9 NatLoadTexture(const char* path, bool bNoMips) { LPDIRECT3DTEXTURE9 pTex = NULL; D3DXIMAGE_INFO info; @@ -70,6 +70,7 @@ LPDIRECT3DTEXTURE9 NatLoadTexture(const char* path) if (Config->TextureMips == 2) Mips = 0; // Autogen all if (Config->TextureMips == 1 && info.MipLevels == 1) Mips = 0; // Autogen missing + if (bNoMips) Mips = 1; if (S_OK == D3DXCreateTextureFromFileExA(g_client->GetDevice(), path, info.Width, info.Height, Mips, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &pTex)) { @@ -85,11 +86,11 @@ LPDIRECT3DTEXTURE9 NatLoadTexture(const char* path) // =============================================================================================== // Load a simple plain texture with map type extension // -LPDIRECT3DTEXTURE9 NatLoadSpecialTexture(const char* path, const char* ext) +LPDIRECT3DTEXTURE9 NatLoadSpecialTexture(const char* path, const char* ext, bool bNoMips) { char name[MAX_PATH]; NatCreateName(name, ARRAYSIZE(name), path, ext); - return NatLoadTexture(name); + return NatLoadTexture(name, bNoMips); } @@ -98,16 +99,16 @@ LPDIRECT3DTEXTURE9 NatLoadSpecialTexture(const char* path, const char* ext) // void NatLoadMaps(SurfNative *pNat, const char* path) { - pNat->AddMap(MAP_HEAT, NatLoadSpecialTexture(path, "heat")); - pNat->AddMap(MAP_NORMAL, NatLoadSpecialTexture(path, "norm")); - pNat->AddMap(MAP_SPECULAR, NatLoadSpecialTexture(path, "spec")); - pNat->AddMap(MAP_EMISSION, NatLoadSpecialTexture(path, "emis")); - pNat->AddMap(MAP_ROUGHNESS, NatLoadSpecialTexture(path, "rghn")); - pNat->AddMap(MAP_METALNESS, NatLoadSpecialTexture(path, "metal")); - pNat->AddMap(MAP_REFLECTION, NatLoadSpecialTexture(path, "refl")); - pNat->AddMap(MAP_TRANSLUCENCE, NatLoadSpecialTexture(path, "transl")); - pNat->AddMap(MAP_TRANSMITTANCE, NatLoadSpecialTexture(path, "transm")); - pNat->AddMap(MAP_AMBIENT, NatLoadSpecialTexture(path, "bkao")); + pNat->AddMap(MAP_HEAT, NatLoadSpecialTexture(path, "_heat")); + pNat->AddMap(MAP_NORMAL, NatLoadSpecialTexture(path, "_norm")); + pNat->AddMap(MAP_SPECULAR, NatLoadSpecialTexture(path, "_spec")); + pNat->AddMap(MAP_EMISSION, NatLoadSpecialTexture(path, "_emis")); + pNat->AddMap(MAP_ROUGHNESS, NatLoadSpecialTexture(path, "_rghn")); + pNat->AddMap(MAP_METALNESS, NatLoadSpecialTexture(path, "_metal")); + pNat->AddMap(MAP_REFLECTION, NatLoadSpecialTexture(path, "_refl")); + pNat->AddMap(MAP_TRANSLUCENCE, NatLoadSpecialTexture(path, "_transl")); + pNat->AddMap(MAP_TRANSMITTANCE, NatLoadSpecialTexture(path, "_transm")); + pNat->AddMap(MAP_AMBIENT, NatLoadSpecialTexture(path, "_bkao")); } @@ -1067,15 +1068,15 @@ void SurfNative::Reload() if (S_OK == D3DXCreateTextureFromFileExA(g_client->GetDevice(), path, info.Width, info.Height, Mips, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, (LPDIRECT3DTEXTURE9 *)&pResource)) { - AddMap(MAP_HEAT, NatLoadSpecialTexture(name, "heat")); - AddMap(MAP_NORMAL, NatLoadSpecialTexture(name, "norm")); - AddMap(MAP_SPECULAR, NatLoadSpecialTexture(name, "spec")); - AddMap(MAP_EMISSION, NatLoadSpecialTexture(name, "emis")); - AddMap(MAP_ROUGHNESS, NatLoadSpecialTexture(name, "rghn")); - AddMap(MAP_METALNESS, NatLoadSpecialTexture(name, "metal")); - AddMap(MAP_REFLECTION, NatLoadSpecialTexture(name, "refl")); - AddMap(MAP_TRANSLUCENCE, NatLoadSpecialTexture(name, "transl")); - AddMap(MAP_TRANSMITTANCE, NatLoadSpecialTexture(name, "transm")); + AddMap(MAP_HEAT, NatLoadSpecialTexture(name, "_heat")); + AddMap(MAP_NORMAL, NatLoadSpecialTexture(name, "_norm")); + AddMap(MAP_SPECULAR, NatLoadSpecialTexture(name, "_spec")); + AddMap(MAP_EMISSION, NatLoadSpecialTexture(name, "_emis")); + AddMap(MAP_ROUGHNESS, NatLoadSpecialTexture(name, "_rghn")); + AddMap(MAP_METALNESS, NatLoadSpecialTexture(name, "_metal")); + AddMap(MAP_REFLECTION, NatLoadSpecialTexture(name, "_refl")); + AddMap(MAP_TRANSLUCENCE, NatLoadSpecialTexture(name, "_transl")); + AddMap(MAP_TRANSMITTANCE, NatLoadSpecialTexture(name, "_transm")); } } } @@ -1182,7 +1183,7 @@ bool NatCreateName(char* out, int mlen, const char* fname, const char* id) char* p = strrchr(buffe, '.'); if (p != NULL) { *p = '\0'; - sprintf_s(out, mlen, "%s_%s.%s", buffe, id, ++p); + sprintf_s(out, mlen, "%s%s.%s", buffe, id, ++p); } return (p != NULL); } diff --git a/OVP/D3D9Client/D3D9Surface.h b/OVP/D3D9Client/D3D9Surface.h index e96cba5e1..4531ee3b1 100644 --- a/OVP/D3D9Client/D3D9Surface.h +++ b/OVP/D3D9Client/D3D9Surface.h @@ -34,7 +34,8 @@ #define OAPISURF_SKP_GDI_WARN 0x00000001 -LPDIRECT3DTEXTURE9 NatLoadSpecialTexture(const char* fname, const char* ext); +LPDIRECT3DTEXTURE9 NatLoadTexture(const char* path, bool bNoMips = false); +LPDIRECT3DTEXTURE9 NatLoadSpecialTexture(const char* fname, const char* ext, bool bNoMips = false); SURFHANDLE NatLoadSurface(const char* file, DWORD flags, bool bPath = false); bool NatSaveSurface(const char* file, LPDIRECT3DRESOURCE9 pResource); SURFHANDLE NatCreateSurface(int width, int height, DWORD flags); diff --git a/OVP/D3D9Client/Mesh.cpp b/OVP/D3D9Client/Mesh.cpp index 0a89f00ee..94be8c03a 100644 --- a/OVP/D3D9Client/Mesh.cpp +++ b/OVP/D3D9Client/Mesh.cpp @@ -204,6 +204,8 @@ void D3D9Mesh::Null(const char *meshName /* = NULL */) bMtrlModidied = false; bMustRebake = true; + bli = BakedLights.begin(); + Locals = new LightStruct[Config->MaxLights()]; for (int i = 0; i < SHM_CASCADE_COUNT; i++) { @@ -399,6 +401,13 @@ void D3D9Mesh::Release() SAFE_DELETEA(pGrpTF); if (pBuf) if (pBuf->IsLocalTo(this)) delete pBuf; + + for (auto x : BakedLights) { + for (auto y : x.second.pMap) SAFE_RELEASE(y); + for (auto y : x.second.pSunAO) SAFE_RELEASE(y); + SAFE_RELEASE(x.second.pCombined); + SAFE_RELEASE(x.second.pSunAOComb); + } } @@ -465,6 +474,40 @@ void D3D9Mesh::ReLoadMeshFromHandle(MESHHANDLE hMesh) pBuf->Map(pDev); } +// =========================================================================================== +// +const char* D3D9Mesh::GetDirName(int i, int v) +{ + static const char* names[] = { "up", "down", "left", "right", "fwd", "aft" }; + static const char* named[] = { "+y", "-y", "-x", "+x", "+z", "-z" }; + if (v == 0) return names[i]; + return named[i]; +} + +// =========================================================================================== +// +FVECTOR3 D3D9Mesh::GetDir(int i) +{ + switch (i) { + case 0: return FVECTOR3(0, 1, 0); // Up + case 1: return FVECTOR3(0, -1, 0); // Down + case 2: return FVECTOR3(-1, 0, 0); // Left + case 3: return FVECTOR3( 1, 0, 0); // Right + case 4: return FVECTOR3(0, 0, 1); // Fwd + case 5: return FVECTOR3(0, 0, -1); // Aft + } + return FVECTOR3(0, 0, 1); +} + +// =========================================================================================== +// +void D3D9Mesh::ClearBake(int i) +{ + for (int k = 0; k < 16; k++) BakedLights[i].pMap[k] = NULL; + for (int k = 0; k < 6; k++) BakedLights[i].pSunAO[k] = NULL; + BakedLights[i].pCombined = NULL; + BakedLights[i].pSunAOComb = NULL; +} // =========================================================================================== // @@ -473,7 +516,7 @@ void D3D9Mesh::LoadBakedLights() if (BakedLights.size()) return; // Already Loaded, skip the rest bMustRebake = true; - char id[8]; + char id[32]; for (int i = 0; i < nTex; i++) { @@ -481,24 +524,45 @@ void D3D9Mesh::LoadBakedLights() for (int j = 0; j < 16; j++) { - sprintf_s(id, "bkl%d", j); - LPDIRECT3DTEXTURE9 pTex = NatLoadSpecialTexture(Tex[i]->GetPath(), id); + sprintf_s(id, "_bkl%d", j); + LPDIRECT3DTEXTURE9 pTex = NatLoadSpecialTexture(Tex[i]->GetPath(), id, true); if (pTex) { - if (BakedLights.find(i) == BakedLights.end()) for (int k = 0; k < 16; k++) BakedLights[i].pMap[k] = NULL; + if (BakedLights.find(i) == BakedLights.end()) ClearBake(i); BakedLights[i].pMap[j] = pTex; } } + + for (int j = 0; j < 6; j++) + { + sprintf_s(id, " baked sunlight %s", GetDirName(j, 0)); + LPDIRECT3DTEXTURE9 pTex = NatLoadSpecialTexture(Tex[i]->GetPath(), id, true); + if (pTex) { + if (BakedLights.find(i) == BakedLights.end()) ClearBake(i); + BakedLights[i].pSunAO[j] = pTex; + } + else { + sprintf_s(id, "_bs%s", GetDirName(j, 1)); + LPDIRECT3DTEXTURE9 pTex = NatLoadSpecialTexture(Tex[i]->GetPath(), id, true); + if (pTex) { + if (BakedLights.find(i) == BakedLights.end()) ClearBake(i); + BakedLights[i].pSunAO[j] = pTex; + } + } + } } // Construct render surface for all combined maps for (auto& a : BakedLights) { int i = a.first; if (Tex[i]) { - HR(D3DXCreateTexture(pDev, Tex[i]->GetWidth(), Tex[i]->GetHeight(), 1, D3DUSAGE_RENDERTARGET, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &a.second.pCombined)); + HR(D3DXCreateTexture(pDev, Tex[i]->GetWidth(), Tex[i]->GetHeight(), 0, D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_RENDERTARGET, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &a.second.pCombined)); + HR(D3DXCreateTexture(pDev, Tex[i]->GetWidth(), Tex[i]->GetHeight(), 0, D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_RENDERTARGET, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &a.second.pSunAOComb)); } } - for (int i = 0; i < 16; i++) BakedLightsControl[i] = FVECTOR3(0.5, 0.5, 0.5); + for (int i = 0; i < 16; i++) BakedLightsControl[i] = FVECTOR3(1.0f, 1.0f, 1.0f); + + bli = BakedLights.begin(); } @@ -563,6 +627,57 @@ void D3D9Mesh::BakeLights(ImageProcessing* pBaker) } +// =========================================================================================== +// +void D3D9Mesh::BakeAO(ImageProcessing* pBaker, const FVECTOR3 &vSun) +{ + if (!pBaker->IsOK()) return; // Baker not initialized + if (DefShader != SHADER_BAKED_VC) return; // Not supported by shader + if (BakedLights.size() == 0) return; // Nothing to bake + + DWORD flags = IPF_POINT | IPF_CLAMP; + FVECTOR3 control[6]; + bool bSE[6]; + + pBaker->Activate("PSSunAO"); + + for (int i = 0; i < 6; i++) + { + auto y = bli->second.pSunAO[i]; + bSE[i] = (y != NULL); + if (y) + { + pBaker->SetTextureNative(i, y, flags); + control[i] = saturate(dot(GetDir(i), vSun)); + control[i] *= control[i]; + if (i == 4) D3D9DebugLog("Fwd %f", control[i].x); + if (i == 0) D3D9DebugLog("Up %f", control[i].x); + } + else { + control[i] = 0.0f; + } + } + + pBaker->SetFloat("fControl", control, sizeof(control)); + pBaker->SetBool("bEnabled", bSE, sizeof(bSE)); + + LPDIRECT3DSURFACE9 pSrf = NULL; + + if (bli->second.pSunAOComb) + { + if (bli->second.pSunAOComb->GetSurfaceLevel(0, &pSrf) == S_OK) + { + pBaker->SetOutputNative(0, pSrf); + pBaker->Execute(true); + SAFE_RELEASE(pSrf); + } + } + + bli++; + if (bli == BakedLights.end()) bli = BakedLights.begin(); +} + + // =========================================================================================== // LPDIRECT3DTEXTURE9 D3D9Mesh::GetCombinedMap(int tex_idx) diff --git a/OVP/D3D9Client/Mesh.h b/OVP/D3D9Client/Mesh.h index bdca5d2c7..3f57da9e7 100644 --- a/OVP/D3D9Client/Mesh.h +++ b/OVP/D3D9Client/Mesh.h @@ -74,7 +74,9 @@ struct _LightList { struct _BakedLights { LPDIRECT3DTEXTURE9 pMap[16]; + LPDIRECT3DTEXTURE9 pSunAO[6]; LPDIRECT3DTEXTURE9 pCombined; + LPDIRECT3DTEXTURE9 pSunAOComb; }; class MeshShader : public ShaderClass @@ -209,9 +211,10 @@ class D3D9Mesh : private D3D9Effect bool IsOK() const { return pBuf != NULL; } void Release(); - + void ClearBake(int i); void LoadBakedLights(); void BakeLights(ImageProcessing *pBaker); + void BakeAO(ImageProcessing* pBaker, const FVECTOR3 &vSun); void SetBakedLightLevel(int idx, const FVECTOR3 &level); void LoadMeshFromHandle(MESHHANDLE hMesh, D3DXVECTOR3 *reorig = NULL, float *scale = NULL); void ReLoadMeshFromHandle(MESHHANDLE hMesh); @@ -220,6 +223,8 @@ class D3D9Mesh : private D3D9Effect void SetName(const char *name); void SetName(UINT idx); const char * GetName() const { return name; } + const char * GetDirName(int i, int v); + FVECTOR3 GetDir(int i); void SetDefaultShader(WORD shader); WORD GetDefaultShader() const { return DefShader; } @@ -364,6 +369,7 @@ class D3D9Mesh : private D3D9Effect D3D9MatExt *Mtrl; // list of mesh materials SurfNative **Tex; // list of mesh textures std::map BakedLights; + std::map::const_iterator bli; FVECTOR3 BakedLightsControl[16]; D3DXMATRIX mTransform; D3DXMATRIX mTransformInv; diff --git a/OVP/D3D9Client/Scene.cpp b/OVP/D3D9Client/Scene.cpp index 0cc081bc5..5d9276ba8 100644 --- a/OVP/D3D9Client/Scene.cpp +++ b/OVP/D3D9Client/Scene.cpp @@ -338,6 +338,7 @@ Scene::Scene(D3D9Client *_gc, DWORD w, DWORD h) } pBakeLights = new ImageProcessing(pDevice, "Modules/D3D9Client/PreBakeLights.hlsl", "PSMain"); + pBakeLights->CompileShader("PSSunAO"); LogAlw("================ Scene Created ==============="); } diff --git a/OVP/D3D9Client/VVessel.cpp b/OVP/D3D9Client/VVessel.cpp index bd027fd96..1ef43e194 100644 --- a/OVP/D3D9Client/VVessel.cpp +++ b/OVP/D3D9Client/VVessel.cpp @@ -679,7 +679,9 @@ void vVessel::BakeLights(ImageProcessing *pBaker) if (!meshlist[i].mesh) continue; if (meshlist[i].vismode & MESHVIS_VC) { + auto vSun = tmul(FVECTOR4(sundir, 0), oapi::FMATRIX4(mWorld)); meshlist[i].mesh->BakeLights(pBaker); + meshlist[i].mesh->BakeAO(pBaker, vSun.xyz); } } } diff --git a/OVP/D3D9Client/shaders/PreBakeLights.hlsl b/OVP/D3D9Client/shaders/PreBakeLights.hlsl index bd2a26db0..e368392c6 100644 --- a/OVP/D3D9Client/shaders/PreBakeLights.hlsl +++ b/OVP/D3D9Client/shaders/PreBakeLights.hlsl @@ -5,6 +5,7 @@ uniform extern float3 fControl[16]; uniform extern int iCount; +uniform extern bool bEnabled[6]; sampler tMap[16] : register(s0); @@ -27,3 +28,16 @@ float4 PSMain(float x : TEXCOORD0, float y : TEXCOORD1) : COLOR [unroll] for (int i = 0; i < iCount; i++) color += tex2D(tMap[i], float2(x, y)).rgb * fControl[i]; return float4(LightFX(color), 1.0f); } + +// Combine multiple baked lightmaps into a single map +// +float4 PSSunAO(float x : TEXCOORD0, float y : TEXCOORD1) : COLOR +{ + float3 color = 0; + [unroll] for (int i = 0; i < 6; i++) { + if (bEnabled[i]) { + color += tex2D(tMap[i], float2(x, y)).rgb * fControl[i]; + } + } + return float4(LightFX(color), 1.0f); +}