diff --git a/src/nvtt/TexImage.cpp b/src/nvtt/TexImage.cpp index df07777..39a1625 100644 --- a/src/nvtt/TexImage.cpp +++ b/src/nvtt/TexImage.cpp @@ -1593,6 +1593,31 @@ void TexImage::transformNormals(NormalTransform xform) n.y = n.y * t; n.z = 0.0f; } + else if (xform == NormalTransform_DualParaboloid) { + // Use Newton's method to solve equation: + // f(t) = 1 - zt - (x^2+y^2)t^2 + x^2y^2t^4 = 0 + // f'(t) = - z - 2(x^2+y^2)t + 4x^2y^2t^3 + + // Initial approximation: + float a = (n.x * n.x) + (n.y * n.y); + float b = n.z; + float c = -1.0f; + float discriminant = b * b - 4.0f * a * c; + float t = (-b + sqrtf(discriminant)) / (2.0f * a); + + float d = fabs(n.z * t - (1 - n.x*n.x*t*t) * (1 - n.y*n.y*t*t)); + + while (d > 0.0001) { + float ft = 1 - n.z * t - (n.x*n.x + n.y*n.y)*t*t + n.x*n.x*n.y*n.y*t*t*t*t; + float fit = - n.z - 2*(n.x*n.x + n.y*n.y)*t + 4*n.x*n.x*n.y*n.y*t*t*t; + t -= ft / fit; + d = fabs(n.z * t - (1 - n.x*n.x*t*t) * (1 - n.y*n.y*t*t)); + }; + + n.x = n.x * t; + n.y = n.y * t; + n.z = 0.0f; + } x = n.x; y = n.y; @@ -1632,6 +1657,12 @@ void TexImage::reconstructNormals(NormalTransform xform) n.z = 1.0f - nv::clamp(n.x * n.x + n.y * n.y, 0.0f, 1.0f); n = normalizeSafe(n, Vector3(0.0f), 0.0f); } + else if (xform == NormalTransform_DualParaboloid) { + n.x = n.x; + n.y = n.y; + n.z = nv::clamp((1 - n.x * n.x) * (1 - n.y * n.y), 0.0f, 1.0f); + n = normalizeSafe(n, Vector3(0.0f), 0.0f); + } x = n.x; y = n.y; diff --git a/src/nvtt/nvtt.h b/src/nvtt/nvtt.h index 2530cbc..743a02c 100644 --- a/src/nvtt/nvtt.h +++ b/src/nvtt/nvtt.h @@ -391,6 +391,7 @@ namespace nvtt NormalTransform_Orthographic, NormalTransform_Stereographic, NormalTransform_Paraboloid, + NormalTransform_DualParaboloid, }; /// A texture mipmap. diff --git a/src/nvtt/tests/testsuite.cpp b/src/nvtt/tests/testsuite.cpp index 9bc6c03..adfa7cb 100644 --- a/src/nvtt/tests/testsuite.cpp +++ b/src/nvtt/tests/testsuite.cpp @@ -185,6 +185,7 @@ enum Mode { Mode_BC5_Normal, Mode_BC5_Normal_Stereographic, Mode_BC5_Normal_Paraboloid, + Mode_BC5_Normal_DualParaboloid, Mode_Count }; static const char * s_modeNames[] = { @@ -201,6 +202,7 @@ static const char * s_modeNames[] = { "BC5-Normal", // Mode_BC5_Normal, "BC5-Normal-Stereographic", // Mode_BC5_Normal_Stereographic, "BC5-Normal-Paraboloid", // Mode_BC5_Normal_Paraboloid, + "BC5-Normal-DualParaboloid", // Mode_BC5_Normal_DualParaboloid, }; nvStaticCheck(NV_ARRAY_SIZE(s_modeNames) == Mode_Count); @@ -213,7 +215,7 @@ static Test s_imageTests[] = { {"Color", 3, {Mode_BC1, Mode_BC3_YCoCg, Mode_BC3_RGBM, Mode_BC3_LUVW}}, {"Alpha", 3, {Mode_BC1_Alpha, Mode_BC2_Alpha, Mode_BC3_Alpha}}, //{"Normal", 3, {Mode_BC1_Normal, Mode_BC3_Normal, Mode_BC5_Normal}}, - {"Normal", 3, {Mode_BC5_Normal, Mode_BC5_Normal_Stereographic, Mode_BC5_Normal_Paraboloid}}, + {"Normal", 4, {Mode_BC5_Normal_DualParaboloid, Mode_BC5_Normal, Mode_BC5_Normal_Stereographic, Mode_BC5_Normal_Paraboloid}}, {"Lightmap", 4, {Mode_BC1, Mode_BC3_YCoCg, Mode_BC3_RGBM, Mode_BC3_RGBS}}, }; const int s_imageTestCount = ARRAY_SIZE(s_imageTests); @@ -404,7 +406,7 @@ int main(int argc, char *argv[]) printf(" -dec x \tDecompressor.\n"); printf(" 0: \tReference (D3D10).\n"); printf(" 1: \tReference (D3D9).\n"); - printf(" 1: \tNVIDIA.\n"); + printf(" 2: \tNVIDIA.\n"); printf("Compression options:\n"); printf(" -fast \tFast compression.\n"); @@ -551,7 +553,7 @@ int main(int argc, char *argv[]) else if (mode == Mode_BC3_Normal) { format = nvtt::Format_BC3n; } - else if (mode == Mode_BC5_Normal) { + else if (mode == Mode_BC5_Normal || mode == Mode_BC5_Normal_Stereographic || mode == Mode_BC5_Normal_Paraboloid || mode == Mode_BC5_Normal_DualParaboloid) { format = nvtt::Format_BC5; } @@ -661,6 +663,9 @@ int main(int argc, char *argv[]) else if (mode == Mode_BC5_Normal_Paraboloid) { tmp.transformNormals(nvtt::NormalTransform_Paraboloid); } + else if (mode == Mode_BC5_Normal_DualParaboloid) { + tmp.transformNormals(nvtt::NormalTransform_DualParaboloid); + } printf("Compressing: \t'%s'\n", set.fileNames[i]); @@ -735,6 +740,9 @@ int main(int argc, char *argv[]) else if (mode == Mode_BC5_Normal_Paraboloid) { img_out.reconstructNormals(nvtt::NormalTransform_Paraboloid); } + else if (mode == Mode_BC5_Normal_DualParaboloid) { + img_out.reconstructNormals(nvtt::NormalTransform_DualParaboloid); + } nvtt::TexImage diff = nvtt::diff(img, img_out, 1.0f);