2012-07-26 20 views
1

最近我在看一本名为的书iPhone 3D 3D编程。在它的例子之后,我发现了一个非常令人困惑的问题,即我的代码与“klein bottle”有“光照不当”(或者它有一个正式名称)。单面歧管的正常不匹配

左是正确的照明(从本书的源代码)。 正确的是我的版本。 下面是这个例子和我的区别。

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 任何建议将明白。

Full source code

+0

哇,从来没有见过差异文件作为代码示例,但是再次,一个是绰绰有余。 – 2012-07-26 07:54:44

+0

@ChristianRau因为我复制了书中的代码,但结果不同,所以我发布了一个diff文件以寻求帮助。 – Pikaurd 2012-07-26 13:49:02

+0

我的头顶上,你的问题的一个好名字可能是“正常不匹配”,或“方向问题”。 – comingstorm 2012-07-27 00:03:33

回答

0

与克莱因瓶的问题是它不是orientable:它是一个片面歧管,所以这是不可能在整个表面保持一致的正常。无论您如何选择网格上的法线,总会有一条线从正常的一侧翻转到另一侧。

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

使您的克莱恩瓶无缝最简单的方法是做一个双重封面:每个三角形出现两次,面对相反的方向。这可能比简单地制作三角形更加复杂 - 关键是每个也必须出现两次,指向相反的方向。最方便的方法是复制顶点,并为相对(单面)三角形使用不同的顶点集。 (我没有仔细看过你的代码,但是要做双覆盖的事情,你可能需要扩展你的参数化循环的一个因子2,并可能做一些事情,如区分积极的和负的四元数,不要忘了让所得的三角形单面。)

+0

我有一个'invertNormal()'在超类和子类中使用'InvertNormal()'...我第一次听说'可定向'你能推荐任何书吗?非常感谢你。 – Pikaurd 2012-07-27 02:31:08

+0

对不起,我不知道一本关于拓扑的好书。我建议你使用谷歌关键词,如“可定向”,“多样”,“单面”,“克莱因瓶”和“莫比乌斯带”。 – comingstorm 2012-07-27 17:38:10