Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Yes. Well, sort of. Normal maps can be accurately made from height-maps. Generally, you can also put a regular texture through and get decent results as well. Keep in mind there are other methods of making a normal map, such as taking a high-resolution model, making it low resolution, then doing ray casting to see what the normal should be for the low-resolution model to simulate the higher one.</p> <p>For height-map to normal-map, you can use the <a href="http://en.wikipedia.org/wiki/Sobel_operator" rel="noreferrer">Sobel Operator</a>. This operator can be run in the x-direction, telling you the x-component of the normal, and then the y-direction, telling you the y-component. You can calculate z with <code>1.0 / strength</code> where strength is the emphasis or "deepness" of the normal map. Then, take that x, y, and z, throw them into a vector, normalize it, and you have your normal at that point. Encode it into the pixel and you're done.</p> <p>Here's some older incomplete-code that demonstrates this:</p> <pre><code>// 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&amp; pPixel) { const double r = static_cast&lt;double&gt;(pPixel.red); const double g = static_cast&lt;double&gt;(pPixel.green); const double b = static_cast&lt;double&gt;(pPixel.blue); const double average = (r + g + b) / 3.0; return average / 255.0; } const int clamp(int pX, int pMax) { if (pX &gt; pMax) { return pMax; } else if (pX &lt; 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&amp; 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&lt;int&gt;(pTexture.size()); for (size_t row = 0; row &lt; textureSize; ++row) { for (size_t column = 0; column &lt; 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; } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload