POV-Ray : Newsgroups : povray.advanced-users : Using POV-Ray to generate an RGB normal map? Server Time
31 Oct 2024 10:22:24 EDT (-0400)
  Using POV-Ray to generate an RGB normal map? (Message 1 to 4 of 4)  
From: Fingers
Subject: Using POV-Ray to generate an RGB normal map?
Date: 6 Sep 2006 19:30:01
Message: <web.44ff58fa2b7d3f2b26c7adc80@news.povray.org>
Hello,

Has anybody experimented with creating RGB normal maps in POV-Ray? Is it
possible?

It should be straightforward to take the normal of a surface where the ray
hits, then quantize the XYZ components of the normal to produce values
ranging from 0 to 255 and store in an RGB image file (i.e. R = (Nx+1)*127+1
). But does POV-Ray, or any unofficial version of it have a way to do this?
It'd be a special pigment/pattern type, right? Alternatively, could this be
simulated with slope patterns?

The application would be "bump maps" used as textures in a real-time
renderer. One could render, say, a wall using just ambient light to get the
colors; and render again with the "normal map pigment" to get the normal for
each pixel... Then the real-time app combines the two like Pixel = Colormap
* (Normalmap dot Lightdirection) to allow changes in the illumination.


Post a reply to this message

From: Slime
Subject: Re: Using POV-Ray to generate an RGB normal map?
Date: 7 Sep 2006 00:03:38
Message: <44ff9a1a$1@news.povray.org>
> Has anybody experimented with creating RGB normal maps in POV-Ray? Is it
> possible?

Yes, I've been finding POV-Ray quite useful for the task. I have the
following in an include file:

#macro DisplayTexture(Texture)
 camera {
  orthographic
  location <.5,.5,-1>
  right x
  up y
  direction z
 }

 light_source {
  <-.7,1,-.7>*999
  rgb 1
 }

 sky_sphere {
  pigment {checker rgb 0 rgb 1}
  scale .1
 }

 plane {
  -z,0
  texture {
   Texture
  }
 }
#end

#macro DisplayPig(Pigment)
 camera {
  orthographic
  location <.5,.5,-1>
  right x
  up y
  direction z
 }

 plane {
  -z,0
  pigment {
   Pigment
  }
  finish {ambient 1 diffuse 0}
 }
#end

#macro Normal(BasePigment, ZScale, Accuracy)
 #local PigmentBase = function {pigment{BasePigment}}
 #local Base = function {PigmentBase(x,y,z).grey}

 #local acc = Accuracy;

 #local BaseX = function // dx
 {
  (Base(x + acc,y,z) - Base(x - acc,y,z)) / (2*acc) * ZScale
 }
 #local BaseY = function // dy
 {
  (Base(x,y + acc,z) - Base(x,y - acc,z)) / (2*acc) * ZScale
 }
 #local BaseXY = function // full horizontal derivative
 {
  sqrt(pow(BaseX(x,y,z),2) + pow(BaseY(x,y,z),2))
 }
 #local XYCalc = function(x)
 {
  ((-x/sqrt(1+x*x)) + 1)/2 // take slope and convert to horizontal component
of normal; then scale to the range 0 to 1
 }
 #local Red = function
 {
  XYCalc(BaseX(x,y,z))
 }
 #local Green = function
 {
  //Base(x,y,z)
  XYCalc(BaseY(x,y,z))
 }
 #local ZCalc = function(x)
 {
  sqrt(1-x*x) // take slope and convert to vertical component of normal
 }
 #local Blue = function
 {
  ZCalc(
   BaseXY(x,y,z)
  )
  //Base(x,y,z)
 }

 DisplayPig (
  pigment {
   average
   pigment_map {
    [1 function {Red(x,y,z)  } color_map{[0 rgb 0] [1 rgb 3*x]}]
    [1 function {Green(x,y,z)} color_map{[0 rgb 0] [1 rgb 3*y]}]
    [1 function {Blue(x,y,z) } color_map{[0 rgb 0] [1 rgb 3*z]}]
   }
  }
 )
#end

#macro Normalize(BasePigment)
 #local PigmentBase = function {pigment{BasePigment}}

 #local Len = function {sqrt(x*x+y*y+z*z)}

 #local Magnitude = function {

Len(PigmentBase(x,y,z).x*2-1,PigmentBase(x,y,z).y*2-1,PigmentBase(x,y,z).z)
 }

 #local Red = function {(PigmentBase(x,y,z).x*2-1)/Magnitude(x,y,z) * .5 +
.5}
 #local Green = function {(PigmentBase(x,y,z).y*2-1)/Magnitude(x,y,z) * .5 +
.5}
 #local Blue = function {PigmentBase(x,y,z).z/Magnitude(x,y,z)}

 DisplayPig (
  pigment {
   average
   pigment_map {
    [1 function {Red(x,y,z)  } color_map{[0 rgb 0] [1 rgb 3*x]}]
    [1 function {Green(x,y,z)} color_map{[0 rgb 0] [1 rgb 3*y]}]
    [1 function {Blue(x,y,z) } color_map{[0 rgb 0] [1 rgb 3*z]}]
   }
  }
 )
#end




I use it like this:

#declare bumpy = pigment {bumps scale .1}
Normal(bumpy, .1, .0001) // height of .1, sample width of .0001

Also handy is the Normalize function, which takes an existing normal map
(possibly from an external texture) and normalizes each pixel.

 - Slime
 [ http://www.slimeland.com/ ]


Post a reply to this message

From: Fingers
Subject: Re: Using POV-Ray to generate an RGB normal map?
Date: 7 Sep 2006 16:00:01
Message: <web.450076e75dce606226c7adc80@news.povray.org>
"Slime" <fak### [at] emailaddress> wrote:
> > Has anybody experimented with creating RGB normal maps in POV-Ray? Is it
> > possible?
>
> Yes, I've been finding POV-Ray quite useful for the task. I have the
> following in an include file:
>

Thanks for your response! Using functions hadn't crossed my mind. Your
method is very cool, although not quite what I was thinking of. What I'm
looking for is getting the actual normal of the surface... Say you want a
wall texture with a bunch of pipes on it; you could make the pipes out of
(3D) cylinders, toruses and such, then render in an orthogonal view with a
routine that takes the surface normal at each pixel and turns it into RGB.

Your idea is going in the right direction though, as I could use a two-pass
system to first render a heightfield using gradient z and then make a
normal map with your macros. It'd have interpolation errors at the edges of
"protruding" elements but texture filtering would cause those anyway in the
OpenGL app. I'll have to experiment with this.

Thinking further, can you set the Red, Green and Blue outputs of a function
separately? If I could just use three different slope patterns, one for
each channel, this'd be a piece of cake.


Post a reply to this message

From: Fingers
Subject: Re: Using POV-Ray to generate an RGB normal map?
Date: 7 Sep 2006 16:45:00
Message: <web.4500845a5dce606226c7adc80@news.povray.org>
OK, now I feel really stupid... All I kept thinking was, "average is going
to make it all 1/3 the brightness and that'll destroy the accuracy if I
just blend three slopes together". Just putting "ambient 3" in the final
texture makes it work perfectly and I can render any shapes into a normal
map just like I wanted.

Here's a sphere with a "normal map" pigment. It produces <128,128,255> in
the +Z direction.

#declare RedX = pigment
{
  slope x
  color_map
  {
    [ 0 color rgb <0, 0, 0> ]
    [ 1 color rgb <1, 0, 0> ]
  }
}

#declare GreenY = pigment
{
  slope y
  color_map
  {
    [ 0 color rgb <0, 0, 0> ]
    [ 1 color rgb <0, 1, 0> ]
  }
}

#declare BlueZ = pigment
{
  slope z
  color_map
  {
    [ 0 color rgb <0, 0, 0> ]
    [ 1 color rgb <0, 0, 1> ]
  }
}


sphere
{
 <0, 0, 0>, .25
  texture
  {
    pigment
    {
      average
      pigment_map
      {
        [1 RedX ]
        [1 GreenY ]
        [1 BlueZ ]
      }
    }

    finish { ambient 3 diffuse 0 }
  }
}


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.