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