2011-12-07 30 views
2

我想創建地形映射的子游標。gluDisk旋轉映射

的代碼基礎:(舊形象,但旋轉相同)

image http://www.sdilej.eu/pics/274a90360f9c46e2eaf94e095e0b6223.png

這是我測試的改變glRotate斧頭我的號碼:

image2 http://www.sdilej.eu/pics/146bda9dc51708da54b9249706f874fc.png

我想要什麼:

image3 http://www.sdilej.eu/pics/69721aa237608b423b635945d430e561.png

我的代碼:

void renderDisk(float x1, float y1, float z1, float x2, float y2, float z2, float radius, int subdivisions, GLUquadricObj* quadric) 
{ 
    float vx = x2 - x1; 
    float vy = y2 - y1; 
    float vz = z2 - z1; 

    //handle the degenerate case of z1 == z2 with an approximation 
    if(vz == 0.0f) 
    vz = .0001f; 

    float v = sqrt(vx*vx + vy*vy + vz*vz); 
    float ax = 57.2957795f * acos(vz/v); 
    if(vz < 0.0f) 
    ax = -ax; 

    float rx = -vy * vz; 
    float ry = vx * vz; 

    glPushMatrix(); 

    glTranslatef(x1, y1, z1); 
    glRotatef(ax, rx, ry, 0.0); 

    gluQuadricOrientation(quadric, GLU_OUTSIDE); 
    gluDisk(quadric, radius - 0.25, radius + 5.0, subdivisions, 5); 

    glPopMatrix(); 
} 
void renderDisk_convenient(float x, float y, float z, float radius, int subdivisions) 
{ 
    // Mouse opacity 
    glColor4f(0.0f, 7.5f, 0.0f, 0.5f); 
    GLUquadricObj* quadric = gluNewQuadric(); 
    gluQuadricDrawStyle(quadric, GLU_LINE); 
    gluQuadricNormals(quadric, GLU_SMOOTH); 
    gluQuadricTexture(quadric, GL_TRUE); 
    renderDisk(x, y, z, x, y, z, radius, subdivisions, quadric); 
    gluDeleteQuadric(quadric); 
} 

renderDisk_convenient(posX, posY, posZ, radius, 20); 

回答

1

這是一個簡單的問題。在對renderDisk()的調用中,您提供的參數很糟糕。看起來你從一些教程中複製了這個功能,卻不知道它是如何工作的。前三個參數控制中心位置,其他三個參數使用磁盤始終面對的第二個位置控制旋轉。如果兩個位置相等(這是您的情況下),這條線被執行:

//handle the degenerate case of z1 == z2 with an approximation 
if(vz == 0.0f) 
    vz = .0001f; 

和設置Z到非零使盤垂直於XZ平面,這也是爲您的地形水平面。所以......使其沒關係,你需要修改你的函數是這樣的:

void renderDisk_convenient(float x, float y, float z, float radius, int subdivisions) 
{ 
    // Mouse opacity 
    glColor4f(0.0f, 7.5f, 0.0f, 0.5f); 
    GLUquadricObj* quadric = gluNewQuadric(); 
    gluQuadricDrawStyle(quadric, GLU_LINE); 
    gluQuadricNormals(quadric, GLU_SMOOTH); 
    gluQuadricTexture(quadric, GL_TRUE); 
    float upX = 0, upY = 1, upZ = 0; // up vector (does not need to be normalized) 
    renderDisk(x, y, z, x + upX, y + upY, z + upZ, radius, subdivisions, quadric); 
    gluDeleteQuadric(quadric); 
} 

這應該把光盤放入XZ平面所以這將是好的,如果地勢平坦。但在其他地方,您實際上需要修改法線方向((upX,upY,upZ)矢量)。如果您的地形是從高度圖生成,則可以正常使用代碼來計算,如本:

const char *p_s_heightmap16 = "ps_height_1k.png"; 
const float f_terrain_height = 50; // terrain is 50 units high 
const float f_terrain_scale = 1000; // the longer edge of terrain is 1000 units long 

TBmp *p_heightmap; 
if(!(p_heightmap = p_LoadHeightmap_HiLo(p_s_heightmap16))) { 
    fprintf(stderr, "error: failed to load heightmap (%s)\n", p_s_heightmap16); 
    return false; 
} 
// load heightmap 

TBmp *p_normalmap = TBmp::p_Alloc(p_heightmap->n_width, p_heightmap->n_height); 
// alloc normalmap 

const float f_width_scale = f_terrain_scale/max(p_heightmap->n_width, p_heightmap->n_height); 
// calculate the scaling factor 

for(int y = 0, hl = p_normalmap->n_height, hh = p_heightmap->n_height; y < hl; ++ y) { 
    for(int x = 0, wl = p_normalmap->n_width, wh = p_heightmap->n_width; x < wl; ++ x) { 
     Vector3f v_normal(0, 0, 0); 
     { 
      Vector3f v_pos[9]; 
      for(int yy = -1; yy < 2; ++ yy) { 
       for(int xx = -1; xx < 2; ++ xx) { 
        int sx = xx + x; 
        int sy = yy + y; 
        float f_height; 
        if(sx >= 0 && sy >= 0 && sx < wh && sy < hh) 
         f_height = ((const uint16_t*)p_heightmap->p_buffer)[sx + sy * wh]/65535.0f * f_terrain_height; 
        else 
         f_height = 0; 

        v_pos[(xx + 1) + 3 * (yy + 1)] = Vector3f(xx * f_width_scale, f_height, yy * f_width_scale); 
       } 
      } 
      // read nine-neighbourhood 

      /* 
       0   1   2 
       +----------+----------+ 
       |\   |   /| 
       | \  |  /| 
       | \  | / | 
       |  \ | / | 
       3|_________\|/_________|5 
       |  4/|\   | 
       |  /| \  | 
       | / |  \ | 
       |/  |  \ | 
       |/   |   \| 
       +----------+----------+ 
       6   7   8 

      */ 

      const int p_indices[] = { 
       0, 1, //4, 
       1, 2, //4, 
       2, 5, //4, 
       5, 8, //4, 
       8, 7, //4, 
       7, 6, //4, 
       6, 3, //4, 
       3, 0 //, 4 
      }; 

      for(int i = 0; i < 8; ++ i) { 
       Vector3f a = v_pos[p_indices[i * 2]]; 
       Vector3f b = v_pos[p_indices[i * 2 + 1]]; 
       Vector3f c = v_pos[4]; 
       // triangle 

       Vector3f v_tri_normal = (a - c).v_Cross(b - c); 
       v_tri_normal.Normalize(); 
       // calculate normals 

       v_normal += v_tri_normal; 
      } 
      v_normal.Normalize(); 
     } 
     // calculate normal from the heightmap (by averaging the normals of eight triangles that share the current point) 

     uint32_t n_normalmap = 
      0xff000000U | 
      (max(0, min(255, int(v_normal.z * 127 + 128))) << 16) | 
      (max(0, min(255, int(v_normal.y * 127 + 128))) << 8) | 
      max(0, min(255, int(-v_normal.x * 127 + 128))); 
     // calculate normalmap color 

     p_normalmap->p_buffer[x + wl * y] = n_normalmap; 
     // use the lightmap bitmap to store the results 
    } 
} 

(注意,這包含一些結構和功能未包括在內,所以你將無法使用這個代碼直接,但基本概念是存在的)

一旦你有了法線,你需要在位置(x,z)下取樣並在你的函數中使用它。這仍然會使圓盤與平坦表面(二階導數高的地方)之間存在陡坡的地形相交。爲了解決這個問題,你可以將光標向上擡起(沿着法線),或者禁用深度測試。

如果你的地形是多邊形的,你也可以使用頂點法線,只需要在(x,y,z)下面的三角形並插入它的頂點法線就可以得到光盤的法線。

我希望這可以幫助,隨時評論,如果您需要進一步的建議...