1

最近我在读一本名为iPhone 3D Programming的书。按照它的示例,我发现了一个非常令人困惑的问题,即我的代码有“照明错位”(或者它可能有一个正式的名称)和“克莱因瓶”。

克莱因瓶

左边是正确的照明(来自本书的源代码)。正确的是我的版本。这是示例和我的示例之间的区别。

diff --git a/Classes/ApplicationEngine.cpp b/Classes/ApplicationEngine.cpp
index c3ddd05..68f8b36 100644
--- a/Classes/ApplicationEngine.cpp
+++ b/Classes/ApplicationEngine.cpp
@@ -11,8 +11,6 @@
 #include <algorithm>

 using namespace std;
-namespace ParametricViewer {
-  

 static const int Surface_Count = 6;
 static const int Button_Count = Surface_Count - 1;
@@ -54,7 +52,7 @@ private:
   Animation _animation;
 };

-IApplicationEngine* CreateApplicationEngine(IRenderingEngine* renderingEngine) {
+IApplicationEngine* createApplicationEngine(IRenderingEngine* renderingEngine) {
   return new ApplicationEngine(renderingEngine);
 }

@@ -211,4 +209,3 @@ int ApplicationEngine::mapToButton(ivec2 touchpint) const {
   return buttonIndex;
 }

-}
\ No newline at end of file
diff --git a/Classes/GLView.mm b/Classes/GLView.mm
index 0eeedf6..966041b 100644
--- a/Classes/GLView.mm
+++ b/Classes/GLView.mm
@@ -35,10 +35,10 @@ const BOOL ForceES1 = YES;
             m_renderingEngine = SolidES1::createRenderingEngine();
         } else {
             NSLog(@"Using OpenGL ES 2.0");
-            m_renderingEngine = SolidES2::createRenderingEngine();
+            m_renderingEngine = ES2::createRenderingEngine();
         }

-        m_applicationEngine = ParametricViewer::CreateApplicationEngine(m_renderingEngine);
+        m_applicationEngine = createApplicationEngine(m_renderingEngine);

         [m_context
             renderbufferStorage:GL_RENDERBUFFER
diff --git a/Classes/Interfaces.hpp b/Classes/Interfaces.hpp
index 1f9b129..6bbf0d0 100644
--- a/Classes/Interfaces.hpp
+++ b/Classes/Interfaces.hpp
@@ -58,9 +58,7 @@ namespace SolidES1 {
   IRenderingEngine* createRenderingEngine();
 }

-namespace SolidES2 {
+namespace ES2 {
   IRenderingEngine* createRenderingEngine();
 }
-
-namespace ParametricViewer { IApplicationEngine* CreateApplicationEngine(IRenderingEngine*); }
 #endif
diff --git a/Classes/ParametricEquations.hpp b/Classes/ParametricEquations.hpp
index f06a0a3..ec2942a 100644
--- a/Classes/ParametricEquations.hpp
+++ b/Classes/ParametricEquations.hpp
@@ -4,7 +4,7 @@ class Cone : public ParametricSurface {
 public:
   Cone(float height, float radius) : _height(height), _radius(radius)
   {
-    ParametricInterval interval = { ivec2(20, 20), vec2(TwoPi, 1), vec2(30, 20) };
+    ParametricInterval interval = { ivec2(20, 20), vec2(TWO_PI, 1), vec2(30, 20) };
     setInterval(interval);
   }
   vec3 evaluate(const vec2& domain) const
@@ -24,7 +24,7 @@ class Sphere : public ParametricSurface {
 public:
   Sphere(float radius) : _radius(radius)
   {
-    ParametricInterval interval = { ivec2(20, 20), vec2(Pi, TwoPi), vec2(20, 35) };
+    ParametricInterval interval = { ivec2(20, 20), vec2(PI, TWO_PI), vec2(20, 35) };
     setInterval(interval);
   }
   vec3 evaluate(const vec2& domain) const
@@ -45,7 +45,7 @@ public:
   _majorRadius(majorRadius),
   _minorRadius(minorRadius)
   {
-    ParametricInterval interval = { ivec2(20, 20), vec2(TwoPi, TwoPi), vec2(40, 10) };
+    ParametricInterval interval = { ivec2(20, 20), vec2(TWO_PI, TWO_PI), vec2(40, 10) };
     setInterval(interval);
   }
   vec3 evaluate(const vec2& domain) const
@@ -67,7 +67,7 @@ class TrefoilKnot : public ParametricSurface {
 public:
   TrefoilKnot(float scale) : _scale(scale)
   {
-    ParametricInterval interval = { ivec2(60, 15), vec2(TwoPi, TwoPi), vec2(100, 8) };
+    ParametricInterval interval = { ivec2(60, 15), vec2(TWO_PI, TWO_PI), vec2(100, 8) };
     setInterval(interval);
   }
   vec3 evaluate(const vec2& domain) const
@@ -76,7 +76,7 @@ public:
     const float b = 0.3f;
     const float c = 0.5f;
     const float d = 0.1f;
-    float u = (TwoPi - domain.x) * 2;
+    float u = (TWO_PI - domain.x) * 2;
     float v = domain.y;

     float r = a + b * cos(1.5f * u);
@@ -109,7 +109,7 @@ class MobiusStrip : public ParametricSurface {
 public:
   MobiusStrip(float scale) : _scale(scale)
   {
-    ParametricInterval interval = { ivec2(40, 20), vec2(TwoPi, TwoPi), vec2(40, 15) };
+    ParametricInterval interval = { ivec2(40, 20), vec2(TWO_PI, TWO_PI), vec2(40, 15) };
     setInterval(interval);
   }
   vec3 evaluate(const vec2& domain) const
@@ -141,7 +141,7 @@ class KleinBottle : public ParametricSurface {
 public:
   KleinBottle(float scale) : _scale(scale)
   {
-    ParametricInterval interval = { ivec2(20, 20), vec2(TwoPi, TwoPi), vec2(15, 50) };
+    ParametricInterval interval = { ivec2(20, 20), vec2(TWO_PI, TWO_PI), vec2(15, 50) };
     setInterval(interval);
   }
   vec3 evaluate(const vec2& domain) const
@@ -155,19 +155,19 @@ public:
     float y0  = 8 * sin(u) + (2 * (1 - cos(u) / 2)) * sin(u) * cos(v);

     float x1 = 3 * cos(u) * (1 + sin(u)) +
-    (2 * (1 - cos(u) / 2)) * cos(v + Pi);
+    (2 * (1 - cos(u) / 2)) * cos(v + PI);

     float y1 = 8 * sin(u);

     vec3 range;
-    range.x = u < Pi ? x0 : x1;
-    range.y = u < Pi ? -y0 : -y1;
+    range.x = u < PI ? x0 : x1;
+    range.y = u < PI ? -y0 : -y1;
     range.z = (-2 * (1 - cos(u) / 2)) * sin(v);
     return range * _scale;
   }
-  bool invertNormal(const vec2& domain) const
+  bool InvertNormal(const vec2& domain) const
   {
-    return domain.y > 3 * Pi / 2;
+    return domain.y > 3 * PI / 2;
   }
 private:
   float _scale;
diff --git a/mathLib/Matrix.hpp b/mathLib/Matrix.hpp
index 7b73954..fbbb2d4 100644
--- a/mathLib/Matrix.hpp
+++ b/mathLib/Matrix.hpp
@@ -150,7 +150,7 @@ struct Matrix4 {
   }

   static Matrix4<T> rotate(T degrees) {
-    T radians = degrees * Pi / 180.0f;
+    T radians = degrees * PI / 180.0f;
     T s = std::sin(radians);
     T c = std::cos(radians);

@@ -161,7 +161,7 @@ struct Matrix4 {
   }

   static Matrix4<T> rotate(T degrees, const vec3& axis) {
-    T radians = degrees * Pi / 180.0f;
+    T radians = degrees * PI / 180.0f;
     T s = std::sin(radians);
     T c = std::cos(radians);

diff --git a/mathLib/Quaternion.hpp b/mathLib/Quaternion.hpp
index d1a2a0b..e043760 100644
--- a/mathLib/Quaternion.hpp
+++ b/mathLib/Quaternion.hpp
@@ -53,21 +53,21 @@ inline QuaternionT<T>::QuaternionT(T x, T y, T z, T w) : x(x), y(y), z(z), w(w)
 template <typename T>
 inline QuaternionT<T> QuaternionT<T>:: slerp(T t, const QuaternionT<T>& v1) const {
   const T epsilon = 0.0005f;
-  T DotT = dot(v1);
+  T dotT = dot(v1);

-  if (DotT > 1 - epsilon) {
+  if (dotT > 1 - epsilon) {
     QuaternionT<T> result = v1 + (*this - v1).scaled(t);
     result.normalize();
     return result;
   }

-  if (DotT < 0) DotT = 0;
-  if (DotT > 1) DotT = 1;
+  if (dotT < 0) dotT = 0;
+  if (dotT > 1) dotT = 1;

-  T theta0 = std::acos(DotT);
+  T theta0 = std::acos(dotT);
   T theta = theta0 * t;

-  QuaternionT<T> v2 = (v1 - scaled(DotT));
+  QuaternionT<T> v2 = (v1 - scaled(dotT));
   v2.normalize();

   QuaternionT<T> q = scaled(std::cos(theta)) + v2.scaled(std::sin(theta));
@@ -139,12 +139,12 @@ bool QuaternionT<T>::operator != (const QuaternionT<T>& q) const {
   return !(*this == q);
 }

-// Compute the quaternion that Rotates from a to b, avoiding numerical instability.
+// Compute the quaternion that rotates from a to b, avoiding numerical instability.
 // Taken from "The Shortest Arc Quaternion" by Stan Melax in "Game Programming Gems".
 template <typename T>
 inline QuaternionT<T> QuaternionT<T>::createFromVectors(const Vector3<T>& v0, const Vector3<T>& v1) {
   if (v0 == -v1)
-    return QuaternionT<T>::createFromAxisAngle(vec3(1, 0, 0), Pi);
+    return QuaternionT<T>::createFromAxisAngle(vec3(1, 0, 0), PI);

   Vector3<T> c = v0.cross(v1);
   T d = v0.dot(v1);
@@ -187,7 +187,7 @@ inline void QuaternionT<T>::rotate(const QuaternionT<T>& q2)
   q.y = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z;
   q.z = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x;

-  q.Normalize();
+  q.normalize();
   *this = q;
 }

diff --git a/mathLib/Vector.hpp b/mathLib/Vector.hpp
index 781fc64..f43051e 100644
--- a/mathLib/Vector.hpp
+++ b/mathLib/Vector.hpp
@@ -11,15 +11,15 @@

 #include <cmath>

-const float Pi = 4 * std::atan(1.0f);
-const float TwoPi = 2 * Pi;
+const float PI = 4 * std::atan(1.0f);
+const float TWO_PI = 2 * PI;

 template <typename T>
 struct Vector2 {
   Vector2() {}
   Vector2(T x, T y) : x(x), y(y) {}

-  T Dot(const Vector2& v) const {
+  T dot(const Vector2& v) const {
     return x * v.x + y * v.y;
   }

除了字符大小写之外,代码几乎相同。那么我错在哪里?使用 ES1.1 的错误版本任何建议将不胜感激。

完整的源代码

4

1 回答 1

0

克莱因瓶的问题在于它不可定向:它是一个单侧歧管,因此不可能在整个表面上保持一致的法线。无论您如何选择网格上的法线,总会有一条法线从一侧翻转到另一侧的线。

看起来原来的(金)克莱因瓶可能已经过调整,所以方向不匹配就在瓶子的“嘴”内,隐藏了缺陷而不是修复它。请注意,在您的(灰色)版本中,您可以正确地看到嘴内的表面;在金瓶中,它看起来是黑色的。从您的差异来看,我猜他们可能已经调整了InvertNormal()函数中的条件。(不,差异没有显示任何调整——但听起来确实是调整的合乎逻辑的地方......)

让你的克莱因瓶无缝的最简单方法是做一个双盖:每个三角形出现两次,面向相反的方向。这可能比简单地让你的三角形双面更复杂——关键是每个法线也必须出现两次,指向相反的方向。最方便的方法是复制顶点,并为相对的(单边)三角形使用一组不同的顶点。

(我没有详细查看您的代码,但要进行双重覆盖,您可能需要将其中一个参数循环扩展 2 倍,并且可能需要做一些诸如区分正四元数和负四元数之类的事情。不要忘记使生成的三角形单边。)

于 2012-07-26T20:21:58.543 回答