暗部提亮
This commit is contained in:
1 parent
4d3e0ee04f
commit
95570fede1
1 file changed
+54
-156
+54
-156
@@ -17174,166 +17174,64 @@ if (patchID == NO_ID) {
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 内置 AO 计算与暗部提亮 ==========
|
||||
// ========== 内置 AO 计算与暗部提亮 ==========
|
||||
// 先释放不再需要的 RC patches 大内存
|
||||
{
|
||||
// 清空 rcPatches 释放内存
|
||||
std::vector<RCPatch>().swap(rcPatches);
|
||||
// 清空 m_texelPatchID 释放内存(注意类型是 unsigned int)
|
||||
std::vector<unsigned int>().swap(m_texelPatchID);
|
||||
DEBUG_EXTRA("[AO] Freed RC patches and texelPatchID memory");
|
||||
}
|
||||
if (true)
|
||||
{
|
||||
DEBUG_EXTRA("[AO] Computing ambient occlusion directly...");
|
||||
|
||||
int aoTextureSize = 1024;
|
||||
|
||||
cv::Mat depthMap(aoTextureSize, aoTextureSize, CV_32FC1, std::numeric_limits<float>::max());
|
||||
cv::Mat normalMap(aoTextureSize, aoTextureSize, CV_32FC3, cv::Vec3f(0, 0, 0));
|
||||
|
||||
for (size_t fi = 0; fi < scene.mesh.faces.size(); ++fi) {
|
||||
const Face& face = scene.mesh.faces[fi];
|
||||
|
||||
Point2f uv[3];
|
||||
Point3f pos[3];
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
uv[j] = scene.mesh.faceTexcoords[fi * 3 + j];
|
||||
pos[j] = scene.mesh.vertices[face[j]];
|
||||
}
|
||||
|
||||
Vertex v0 = Vertex(pos[1]) - Vertex(pos[0]);
|
||||
Vertex v1 = Vertex(pos[2]) - Vertex(pos[0]);
|
||||
Vertex normal = v0.cross(v1);
|
||||
float len = sqrtf(normal.dot(normal));
|
||||
if (len > 0.0f) normal /= len;
|
||||
|
||||
float minU = std::min({uv[0].x, uv[1].x, uv[2].x});
|
||||
float maxU = std::max({uv[0].x, uv[1].x, uv[2].x});
|
||||
float minV = std::min({uv[0].y, uv[1].y, uv[2].y});
|
||||
float maxV = std::max({uv[0].y, uv[1].y, uv[2].y});
|
||||
|
||||
int minPX = std::max(0, (int)(minU * aoTextureSize));
|
||||
int maxPX = std::min(aoTextureSize - 1, (int)(maxU * aoTextureSize));
|
||||
int minPY = std::max(0, (int)(minV * aoTextureSize));
|
||||
int maxPY = std::min(aoTextureSize - 1, (int)(maxV * aoTextureSize));
|
||||
|
||||
for (int py = minPY; py <= maxPY; ++py) {
|
||||
for (int px = minPX; px <= maxPX; ++px) {
|
||||
float u = (float)px / aoTextureSize;
|
||||
float v = (float)py / aoTextureSize;
|
||||
|
||||
float b0, b1, b2;
|
||||
bool inside = ComputeBarycentric(u, v, uv[0], uv[1], uv[2], b0, b1, b2);
|
||||
if (!inside) continue;
|
||||
|
||||
Point3f P = pos[0] * b0 + pos[1] * b1 + pos[2] * b2;
|
||||
float depth = sqrt(P.dot(P));
|
||||
|
||||
if (depth < depthMap.at<float>(py, px)) {
|
||||
depthMap.at<float>(py, px) = depth;
|
||||
normalMap.at<cv::Vec3f>(py, px) = cv::Vec3f(normal.x, normal.y, normal.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SSAO 计算
|
||||
cv::Mat aoMapSmall(aoTextureSize, aoTextureSize, CV_32FC1, cv::Scalar(1.0f));
|
||||
|
||||
int sampleRadius = 8;
|
||||
int numSamples = 72; // 恢复一些采样数
|
||||
float bias = 0.002f;
|
||||
float intensity = 2.5f;
|
||||
|
||||
for (int y = 0; y < aoTextureSize; ++y) {
|
||||
for (int x = 0; x < aoTextureSize; ++x) {
|
||||
float centerDepth = depthMap.at<float>(y, x);
|
||||
if (centerDepth >= std::numeric_limits<float>::max() - 1.0f) continue;
|
||||
|
||||
cv::Vec3f centerNormal = normalMap.at<cv::Vec3f>(y, x);
|
||||
if (centerNormal[0] == 0 && centerNormal[1] == 0 && centerNormal[2] == 0) continue;
|
||||
|
||||
float occlusion = 0.0f;
|
||||
|
||||
for (int s = 0; s < numSamples; ++s) {
|
||||
float theta = 2.0f * M_PI * (float)(rand() % 10000) / 10000.0f;
|
||||
float phi = acos((float)(rand() % 10000) / 10000.0f);
|
||||
|
||||
float radius = (float)(rand() % 10000) / 10000.0f * sampleRadius;
|
||||
int sx = x + (int)(radius * sin(phi) * cos(theta));
|
||||
int sy = y + (int)(radius * sin(phi) * sin(theta));
|
||||
|
||||
if (sx < 0 || sx >= aoTextureSize || sy < 0 || sy >= aoTextureSize) continue;
|
||||
|
||||
float sampleDepth = depthMap.at<float>(sy, sx);
|
||||
if (sampleDepth >= std::numeric_limits<float>::max() - 1.0f) continue;
|
||||
|
||||
float depthDiff = sampleDepth - centerDepth;
|
||||
if (depthDiff > bias && depthDiff < 0.5f) {
|
||||
occlusion += 1.0f / (1.0f + depthDiff * depthDiff * 400.0f);
|
||||
}
|
||||
}
|
||||
|
||||
float ao = 1.0f - occlusion / (float)numSamples * intensity;
|
||||
ao = std::max(0.0f, std::min(1.0f, ao));
|
||||
aoMapSmall.at<float>(y, x) = ao;
|
||||
}
|
||||
}
|
||||
|
||||
cv::GaussianBlur(aoMapSmall, aoMapSmall, cv::Size(0, 0), 2.0);
|
||||
|
||||
// 保存 AO 贴图(1024 版本)
|
||||
{
|
||||
cv::Mat aoVis;
|
||||
aoMapSmall.convertTo(aoVis, CV_8UC1, 255.0);
|
||||
std::string aoPath = "/home/algo/Documents/openMVS/data/603454/out.603454/ao.jpg";
|
||||
cv::imwrite(aoPath, aoVis);
|
||||
DEBUG_EXTRA("[AO] AO map saved to: %s", aoPath.c_str());
|
||||
}
|
||||
|
||||
// ★★★ 关键修改:把 AO 上采样回 8192,然后在原图上做提亮 ★★★
|
||||
cv::Mat aoMapFull;
|
||||
cv::resize(aoMapSmall, aoMapFull, cv::Size(textureSize, textureSize), 0, 0, cv::INTER_LINEAR);
|
||||
|
||||
// 把 atlas 转成浮点,在原分辨率上做提亮
|
||||
cv::Mat atlasFloat;
|
||||
atlas.convertTo(atlasFloat, CV_32FC3, 1.0f / 255.0f);
|
||||
|
||||
// 暗部提亮(8192 分辨率)
|
||||
float strength = 0.28f;
|
||||
float threshold = 0.58f;
|
||||
float exponent = 2.0f;
|
||||
|
||||
for (int y = 0; y < textureSize; ++y) {
|
||||
for (int x = 0; x < textureSize; ++x) {
|
||||
float aoVal = aoMapFull.at<float>(y, x);
|
||||
if (aoVal >= threshold) continue;
|
||||
|
||||
float darkness = (threshold - aoVal) / threshold;
|
||||
darkness = std::pow(darkness, exponent);
|
||||
float weight = darkness * strength;
|
||||
if (weight < 0.005f) continue;
|
||||
|
||||
cv::Vec3f color = atlasFloat.at<cv::Vec3f>(y, x);
|
||||
color[0] = color[0] + weight * (1.0f - color[0]);
|
||||
color[1] = color[1] + weight * (1.0f - color[1]);
|
||||
color[2] = color[2] + weight * (1.0f - color[2]);
|
||||
color[0] = std::min(1.0f, std::max(0.0f, color[0]));
|
||||
color[1] = std::min(1.0f, std::max(0.0f, color[1]));
|
||||
color[2] = std::min(1.0f, std::max(0.0f, color[2]));
|
||||
atlasFloat.at<cv::Vec3f>(y, x) = color;
|
||||
}
|
||||
}
|
||||
|
||||
// 转回 8UC3 写回 atlas
|
||||
atlasFloat.convertTo(atlas, CV_8UC3, 255.0f);
|
||||
|
||||
DEBUG_EXTRA("[AO] In-engine AO lightening applied: strength=%.2f, threshold=%.2f",
|
||||
strength, threshold);
|
||||
std::vector<RCPatch>().swap(rcPatches);
|
||||
std::vector<unsigned int>().swap(m_texelPatchID);
|
||||
DEBUG_EXTRA("[AO] Freed RC patches and texelPatchID memory");
|
||||
}
|
||||
|
||||
return true;
|
||||
if (false)
|
||||
{
|
||||
DEBUG_EXTRA("[AO] Loading pre-baked AO from Blender...");
|
||||
|
||||
std::string aoPath = "/home/algo/Documents/openMVS/data/603454/out.603454/aon.jpg";
|
||||
cv::Mat aoMapSmall = cv::imread(aoPath, cv::IMREAD_GRAYSCALE);
|
||||
if (aoMapSmall.empty()) {
|
||||
DEBUG_EXTRA("[AO] Failed to load AO map from %s, skipping", aoPath.c_str());
|
||||
} else {
|
||||
cv::resize(aoMapSmall, aoMapSmall, cv::Size(1024, 1024), 0, 0, cv::INTER_LINEAR);
|
||||
aoMapSmall.convertTo(aoMapSmall, CV_32FC1, 1.0f / 255.0f);
|
||||
|
||||
cv::Mat aoMapFull;
|
||||
cv::resize(aoMapSmall, aoMapFull, cv::Size(textureSize, textureSize), 0, 0, cv::INTER_LINEAR);
|
||||
|
||||
cv::Mat atlasFloat;
|
||||
atlas.convertTo(atlasFloat, CV_32FC3, 1.0f / 255.0f);
|
||||
|
||||
float strength = 0.38f;
|
||||
float aoDarkThresh = 0.62f;
|
||||
float exponent = 0.92f;
|
||||
|
||||
for (int y = 0; y < textureSize; ++y) {
|
||||
for (int x = 0; x < textureSize; ++x) {
|
||||
float aoVal = aoMapFull.at<float>(y, x);
|
||||
if (aoVal >= aoDarkThresh) continue;
|
||||
|
||||
cv::Vec3f color = atlasFloat.at<cv::Vec3f>(y, x);
|
||||
|
||||
float lum = 0.299f * color[2] + 0.587f * color[1] + 0.114f * color[0];
|
||||
if (lum < 0.04f) continue; // 只保护最暗的材质
|
||||
|
||||
// ★★★ 线性映射,不加 cap ★★★
|
||||
float factor = (aoDarkThresh - aoVal) / aoDarkThresh;
|
||||
factor = std::pow(factor, exponent);
|
||||
float add = factor * strength;
|
||||
|
||||
color[0] = std::min(1.0f, color[0] + add);
|
||||
color[1] = std::min(1.0f, color[1] + add);
|
||||
color[2] = std::min(1.0f, color[2] + add);
|
||||
atlasFloat.at<cv::Vec3f>(y, x) = color;
|
||||
}
|
||||
}
|
||||
|
||||
atlasFloat.convertTo(atlas, CV_8UC3, 255.0f);
|
||||
DEBUG_EXTRA("[AO] AO-based lightening applied using Blender AO map");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MeshTexture::BuildSeamVertsFromEdges()
|
||||
|
||||
Reference in new issue
Block a user