2010-03-03 18 views
5

यदि मेरे पास बनावट है, तो क्या इस बनावट के लिए सामान्य मानचित्र बनाना संभव है, इसलिए इसका उपयोग टक्कर-मैपिंग के लिए किया जा सकता है?क्या बनावट से सामान्य मानचित्र उत्पन्न किए जा सकते हैं?

या आमतौर पर सामान्य मानचित्र कैसे बनाए जाते हैं?

उत्तर

21

हां। अच्छी तरह की। सामान्य मानचित्र ऊंचाई-मानचित्र से सटीक रूप से बनाए जा सकते हैं। आम तौर पर, आप एक नियमित बनावट भी डाल सकते हैं और अच्छे परिणाम भी प्राप्त कर सकते हैं। ध्यान रखें कि एक सामान्य मानचित्र बनाने के अन्य तरीके हैं, जैसे कि उच्च-रिज़ॉल्यूशन मॉडल लेना, इसे कम रिज़ॉल्यूशन बनाना, फिर रे कास्टिंग करना, यह देखने के लिए कि कम-रिज़ॉल्यूशन मॉडल के लिए उच्चतम अनुकरण करने के लिए सामान्य होना चाहिए।

सामान्य मानचित्र पर ऊंचाई-मानचित्र के लिए, आप Sobel Operator का उपयोग कर सकते हैं। इस ऑपरेटर को एक्स-दिशा में चलाया जा सकता है, जो आपको सामान्य के एक्स-घटक बताता है, और फिर वाई-दिशा, आपको वाई-घटक बताता है। आप z12 की गणना 1.0/strength के साथ कर सकते हैं जहां ताकत सामान्य मानचित्र की जोर या "गहराई" है। फिर, उस एक्स, वाई, और जेड को ले जाएं, उन्हें एक वेक्टर में फेंक दें, इसे सामान्य करें, और उस बिंदु पर आपका सामान्य हो। इसे पिक्सेल में एन्कोड करें और आप कर चुके हैं।

यहाँ कुछ पुराने अधूरा-कोड है कि इस दर्शाता है:

// 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

एक चीज जिसे इस उत्तर में जोड़ा जाना चाहिए कि अंतिम सामान्य को 0..1 स्थान में परिवर्तित किया जाना चाहिए (यह -1.1 स्थान में है): रंग = रंग * 0.5 + 0.5; –

1

मुझे नहीं लगता कि सामान्य मानचित्र बनावट से उत्पन्न होते हैं। वे एक मॉडल से उत्पन्न होते हैं।

सिर्फ बनावट के रूप में

आप

एक सामान्य नक्शा आप जटिल परिभाषित करने के लिए अनुमति देता है (के रूप में सिर्फ अपने जाल पर रंग को परिभाषित करने और ploys के लाखों सिर्फ शिखर रंगों का उपयोग करने का विरोध किया) कम से कम polys के साथ जटिल रंग विस्तार को परिभाषित करने के लिए अनुमति देता है न्यूनतम polys के साथ सामान्य विवरण।

मेरा मानना ​​है कि सामान्य मानचित्र आमतौर पर उच्च रेज जाल से उत्पन्न होते हैं, और फिर कम रेस जाल के साथ उपयोग किया जाता है।

मुझे यकीन है कि 3 डी उपकरण, जैसे कि 3 डीएस अधिकतम या माया, साथ ही साथ अधिक विशिष्ट टूल आपके लिए भी ऐसा करेंगे। बनावट के विपरीत, मुझे नहीं लगता कि वे आमतौर पर हाथ से किए जाते हैं।

लेकिन वे जाल से उत्पन्न होते हैं, न कि बनावट।

+2

आप समझते हैं कि बनावट में है कि प्रत्येक पिक्सेल के लिए तीव्रता स्तर की ऊंचाई का गठन किया, एक मॉडल का प्रतिनिधित्व करता है और उस बिंदु ऊंचाइयों की इस श्रृंखला एक जाल के रूप में व्याख्या की जा सकती, Normals एक बनावट से उत्पन्न किया जा सकता है। विधि उल्लिखित उत्तर में उल्लिखित है। –

2

शायद कई मायनों एक सामान्य नक्शा उत्पन्न करने के लिए XSI की तरह 3 डी संकुल है, लेकिन दूसरों की तरह कहा, आप इसे एक ऊंचाई मानचित्र से कर सकते हैं, और/3dsmax/ब्लेंडर/उनमें से कोई भी छवि के रूप में आपके लिए एक आउटपुट कर सकता है।

आप आउटपुट और आरजीबी छवि को फ़ोटोशॉप के लिए एनवीडिया प्लगइन के साथ कर सकते हैं, इसे बदलने के लिए एक एल्गोरिदम या आप इसे सीधे 3 डी पैकेजों से तीसरे पक्ष के प्लगइन से आउटपुट करने में सक्षम हो सकते हैं।

ध्यान रखें कि किसी मामले में, आपको जेनरेट किए गए सामान्य मानचित्र से चैनल (आर, जी या बी) को उलटा करने की आवश्यकता हो सकती है।

यहां कुछ संसाधन उदाहरण और अधिक पूर्ण विवरण के साथ लिंक है:

  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

मैं एल्गोरिदम में अपनी समृद्धि की वजह से OpenCV के साथ शुरू करने का सुझाव,।यहां एक ऐसा लिखा गया है जो मैंने लिखा है कि सामान्य रूप से सामान्य मानचित्र को धुंधला करता है और समग्र मूल्य के लिए वजन कम करता है, अनिवार्य रूप से एक स्थलीय मानचित्र बनाते हैं।

#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; 
} 
संबंधित मुद्दे