2010-03-03 21 views

cevap

21

Evet. İyi sıralama. Normal haritalar yükseklik haritalarından doğru bir şekilde yapılabilir. Genel olarak, düzenli bir doku ekleyebilir ve iyi sonuçlar alabilirsiniz. Yüksek çözünürlüklü bir model almak, düşük çözünürlük yapmak, daha sonra düşük çözünürlüklü model için normalin ne olması gerektiğini görmek için ışın dökümü yapmak gibi normal bir harita oluşturmanın başka yöntemleri de vardır.

normal haritaya yüksekliği-haritası için size Sobel Operator kullanabilirsiniz. Bu operatör x-yönünde çalışarak, normalin x bileşenini ve ardından y-bileşenini size bildiren y-yönünü söyler. Z'nin 1.0/strength ile z'yi hesaplayabilirsiniz, burada kuvvet normal haritanın vurgusu veya "derinliği" dir. Sonra, x, y ve z'yi alın, onları bir vektöre atın, normalleştirin ve bu noktada normalin var. Onu piksele kodlayın ve işiniz bitti.

İşte bu gösteriyor bazı eski tamamlanmamış-kod:

// pretend types, something like this 
struct pixel 
{ 
    uint8_t red; 
    uint8_t green; 
    uint8_t blue; 
}; 

struct vector3d; // a 3-vector with doubles 
struct texture; // a 2d array of pixels 

// determine intensity of pixel, from 0 - 1 
const double intensity(const pixel& pPixel) 
{ 
    const double r = static_cast<double>(pPixel.red); 
    const double g = static_cast<double>(pPixel.green); 
    const double b = static_cast<double>(pPixel.blue); 

    const double average = (r + g + b)/3.0; 

    return average/255.0; 
} 

const int clamp(int pX, int pMax) 
{ 
    if (pX > pMax) 
    { 
     return pMax; 
    } 
    else if (pX < 0) 
    { 
     return 0; 
    } 
    else 
    { 
     return pX; 
    } 
} 

// transform -1 - 1 to 0 - 255 
const uint8_t map_component(double pX) 
{ 
    return (pX + 1.0) * (255.0/2.0); 
} 

texture normal_from_height(const texture& pTexture, double pStrength = 2.0) 
{ 
    // assume square texture, not necessarily true in real code 
    texture result(pTexture.size(), pTexture.size()); 

    const int textureSize = static_cast<int>(pTexture.size()); 
    for (size_t row = 0; row < textureSize; ++row) 
    { 
     for (size_t column = 0; column < textureSize; ++column) 
     { 
      // surrounding pixels 
      const pixel topLeft = pTexture(clamp(row - 1, textureSize), clamp(column - 1, textureSize)); 
      const pixel top = pTexture(clamp(row - 1, textureSize), clamp(column, textureSize)); 
      const pixel topRight = pTexture(clamp(row - 1, textureSize), clamp(column + 1, textureSize)); 
      const pixel right = pTexture(clamp(row, textureSize), clamp(column + 1, textureSize)); 
      const pixel bottomRight = pTexture(clamp(row + 1, textureSize), clamp(column + 1, textureSize)); 
      const pixel bottom = pTexture(clamp(row + 1, textureSize), clamp(column, textureSize)); 
      const pixel bottomLeft = pTexture(clamp(row + 1, textureSize), clamp(column - 1, textureSize)); 
      const pixel left = pTexture(clamp(row, textureSize), clamp(column - 1, textureSize)); 

      // their intensities 
      const double tl = intensity(topLeft); 
      const double t = intensity(top); 
      const double tr = intensity(topRight); 
      const double r = intensity(right); 
      const double br = intensity(bottomRight); 
      const double b = intensity(bottom); 
      const double bl = intensity(bottomLeft); 
      const double l = intensity(left); 

      // sobel filter 
      const double dX = (tr + 2.0 * r + br) - (tl + 2.0 * l + bl); 
      const double dY = (bl + 2.0 * b + br) - (tl + 2.0 * t + tr); 
      const double dZ = 1.0/pStrength; 

      math::vector3d v(dX, dY, dZ); 
      v.normalize(); 

      // convert to rgb 
      result(row, column) = pixel(map_component(v.x), map_component(v.y), map_component(v.z)); 
     } 
    } 

    return result; 
} 
+0

Bu cevaba eklenecek bir şey, son normalin 0..1 alana dönüştürülmesi gerektiğidir (-1.1 alanı): renk = renk * 0.5 + 0.5; –

1

Normal haritaların bir dokudan üretildiğini düşünmüyorum. bir modelden üretilirler. Sadece dokulandırma olarak

Normal bir harita kompleksi tanımlamanızı sağlar (sadece ağ üzerindeki renk tanımlamak için ploys milyonlarca ve sadece köşe renkler kullanarak aksine) en az sayıda polys karmaşık renk detayını tanımlamanızı sağlar minimal polys ile normal detay.

Normal haritaları genellikle daha yüksek bir çözünürlük örgü elde edilir ve daha sonra ağ, düşük res kullanılır inanıyoruz.

Böyle 3ds max veya maya, hem de sizin için yapacak daha özel araçlar olarak emin 3D araçlarını, değilim. Dokulardan farklı olarak, genellikle elle yapıldığını sanmıyorum.

ancak ağ değil, doku oluşturulur.

+2

Texturbutton'a her bir piksel için yoğunluk seviyesi yüksekliği oluşturması ile, bir modeli temsil eder ve noktadan yükseklikleri bu dizi örgü olarak yorumlanabilir, normaller bir doku elde edilebilir düşünün. Metoda verilen cevapta özetlenmiştir. –

2

3d paketleri XSI gibi Orada bir normal harita üretmek için muhtemelen birçok yolu var, ama diğerleri dediğim gibi, bir Yükseklik Haritası yapabilirsin, ve/3dsmax/Blender/herhangi biri sizin için bir görüntü olarak çıktı verebilir.

Ardından photoshop için Nvidia eklentisi ile çıkış ve RGB görüntü, bir algoritma dönüştürmek edebilir veya çıkış mümkün olabilir doğrudan 3. parti eklentileri ile bu 3d paketlerden.

bazı durumda, oluşturulan normal haritadan kanalları (R, G veya B) ters gerekebilir unutmayın.

İşte bazı kaynaklar örnekler ve daha tam açıklama ile bağlantı var: nedeniyle algoritmaları kendi zenginliği için, OpenCV ile başlamanızı öneririz

  1. http://developer.nvidia.com/object/photoshop_dds_plugins.html
  2. http://en.wikipedia.org/wiki/Normal_mapping
  3. http://www.vrgeo.org/fileadmin/VRGeo/Bilder/VRGeo_Papers/jgt2002normalmaps.pdf
0

.İşte, normal haritayı yinelemeli olarak bulanıklaştıran ve bunları topolojik haritadan daha çok yaratan genel değere indirgeyen bir yazdım.

#define ROW_PTR(img, y) ((uchar*)((img).data + (img).step * y)) 
cv::Mat normalMap(const cv::Mat& bwTexture, double pStrength) 
{ 
    // assume square texture, not necessarily true in real code 
    int scale = 1.0; 
    int delta = 127; 

    cv::Mat sobelZ, sobelX, sobelY; 
    cv::Sobel(bwTexture, sobelX, CV_8U, 1, 0, 13, scale, delta, cv::BORDER_DEFAULT); 
    cv::Sobel(bwTexture, sobelY, CV_8U, 0, 1, 13, scale, delta, cv::BORDER_DEFAULT); 
    sobelZ = cv::Mat(bwTexture.rows, bwTexture.cols, CV_8UC1); 

    for(int y=0; y<bwTexture.rows; y++) { 
     const uchar *sobelXPtr = ROW_PTR(sobelX, y); 
     const uchar *sobelYPtr = ROW_PTR(sobelY, y); 
     uchar *sobelZPtr = ROW_PTR(sobelZ, y); 

     for(int x=0; x<bwTexture.cols; x++) { 
      double Gx = double(sobelXPtr[x])/255.0; 
      double Gy = double(sobelYPtr[x])/255.0; 

      double Gz = pStrength * sqrt(Gx * Gx + Gy * Gy); 

      uchar value = uchar(Gz * 255.0); 

      sobelZPtr[x] = value; 
     } 
    } 

    std::vector<cv::Mat>planes; 

    planes.push_back(sobelX); 
    planes.push_back(sobelY); 
    planes.push_back(sobelZ); 

    cv::Mat normalMap; 
    cv::merge(planes, normalMap); 

    cv::Mat originalNormalMap = normalMap.clone(); 

    cv::Mat normalMapBlurred; 

    for (int i=0; i<3; i++) { 
     cv::GaussianBlur(normalMap, normalMapBlurred, cv::Size(13, 13), 5, 5); 
     addWeighted(normalMap, 0.4, normalMapBlurred, 0.6, 0, normalMap); 
    } 
    addWeighted(originalNormalMap, 0.3, normalMapBlurred, 0.7, 0, normalMap); 

    return normalMap; 
} 
İlgili konular