0% found this document useful (0 votes)
105 views7 pages

Awesomebump V1.0: 1 Height To Normal Conversion

This document summarizes key algorithms and methods used in the AwesomeBump (AB) tool. It describes how AB converts between height maps and normal maps in both directions. For height to normal conversion, AB calculates tangent vectors to derive the normal vector. For normal to height conversion, AB solves the gradient equation iteratively using a multi-grid method with varying scale parameters to improve convergence. It also discusses normalizing the height map and generating a normal map from a diffuse base texture using Sobel filtering.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
105 views7 pages

Awesomebump V1.0: 1 Height To Normal Conversion

This document summarizes key algorithms and methods used in the AwesomeBump (AB) tool. It describes how AB converts between height maps and normal maps in both directions. For height to normal conversion, AB calculates tangent vectors to derive the normal vector. For normal to height conversion, AB solves the gradient equation iteratively using a multi-grid method with varying scale parameters to improve convergence. It also discusses normalizing the height map and generating a normal map from a diffuse base texture using Sobel filtering.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 7

AwesomeBump v1.

0
K. Kolasiski
January 18, 2015

Abstract

This paper explains most important methods and algorithms used in AwesomeBump (AB) tool in version v2.0.
I assumed that reader has some mathematical background about derivatives, dierential operators, numerical
methods and iterative solvers. Note that in v2.0 some of algorithms was modied.

Height to normal conversion

This is the simplest problem which I will describe in this text. We can calculate normal vector of surface
at some point

r 0 = (x0 , y 0 )

using the cross product of tangent vectors of this surface at point

z = f (r)

r0 .

n
b
r'
t

z=f(r)

Figure 1: Schematic representation of the surface


point

z = f (r)

with normal

n,

tangent

and bitangent

vector at

r0 .

In order to calculate tangent vector

we use the following formula

t = (1, 0,


f
),
x r=r0

numerically (using the nite dierence method wikipedia) this will have following form

t = (1, 0,

f (x + x, y) f (x, y)
).
x

In order to have control on the amplitude of the normal I introduced the depth parameter

t = (1, 0,
For

=0

(see Figure 2):

f (x + x, y) f (x, y)
).
x

the surface will be completely at and for

After this step

1

surface will be stepper.

vector is normalized

t := normalize(t).
The process of calculation of the

vector is analogical. Normal vector is calculated from the cross product of

the tangent and bitangent vector

n = t b = cross(t, b)
Here is the full code of the GLSL shader which converts the height map to normal texture.

Figure 2: Height to normal depth parameter control slider.

1
2
3
4
5
6
7
8
9
10
11
12
13

s u b r o u t i n e ( f i l t e r M o d e T y p e ) v ec4 mode_height_to_normal ( ) {
c o n s t ve c2 s i z e = v ec2 ( 1 . 0 , 0 . 0 ) ;
c o n s t i v e c 3 o f f = i v e c 3 ( 1 ,0 ,1) ;
v ec 2 t e x _ c o o r d = v2QuadCoords . s t ;
v ec 4
hc = t e x t u r e ( l a y e r A , t e x _ c o o r d ) ;
f l o a t s 1 1 = hc . x ;
f l o a t s 2 1 = t e x t u r e O f f s e t ( l a y e r A , tex_coord , o f f . z y ) . x ;
f l o a t s 1 2 = t e x t u r e O f f s e t ( l a y e r A , tex_coord , o f f . y z ) . x ;
v ec 3 va
= n o r m a l i z e ( v ec3 ( s i z e . xy , 1 0 g u i _ h n _ c o n v e r s i o n _ d e p t h ( s21 s 1 1 ) ) ) ;
v ec 3 vb
= n o r m a l i z e ( v ec3 ( s i z e . yx , 1 0 g u i _ h n _ c o n v e r s i o n _ d e p t h ( s12 s 1 1 ) ) ) ;
v ec 3 bump = n o r m a l i z e ( c r o s s ( va , vb ) ) ;
r e t u r n v ec 4 ( clamp ( bump 0 . 5 + 0 . 5 , ve c3 ( 0 ) , v ec 3 ( 1 ) ) , 1 ) ;
}

Note that I used here dierent notation than before e.g.

= 10 gui_hn_conversion_depth,

and here

x = 1.

Additionally at the end of the shader the normal map is converted to standard textures values i.e. components have
values from 0 to 1. This approach of calculating the normal texture from height map can be found in many places
in the internet.

Normal to height conversion

This problem is more complicated. As it was in previous section we dene a surface function of form

z = h(x, y),
where

is the height eld in our case described by the bump texture which we want to nd, and

coordinates. Mathematically, normal vector

(x, y) are UV
on a new

can be calculated by acting with the gradient operator

function

g(x, y, z) = z h(x, y),


thus we have

n(x, y, z) = g = (z h(x, y)) = (


where

h
H = ( h
x , y , 1).

h h
, , 1) H,
x y

(1)

Now we act with the divergence operator on the Eq.(1), which gives following partial

dierential equation

n
ny
nx
+
x
y
From Eq. (1) we have

nz
z

= 0,

2
z
+ n
z = H = (

2h 2h
+ 2 + 0).
x2
y

which lead to nal formula

nx
ny
+
=
x
y

2h 2h
+ 2
x2
y


.

(2)

In order to solve this equation numerically I used nite dierence approximation, which give following equation
(assuming that

x = y = 1,

where 1 is texture oset - nearest neighbors)

nx (x + x, y) nx (x x, y) ny (x, y + x) ny (x, y x)
+
2x
2x


H(x + x, y) + H(x x, y) 2H(x, y) H(x, y + x) + H(x, y x) 2H(x, y)

+
x2
x2
2

=
.

n1 number
k = 1.

Figure 3: Normal to height control sliders. Huge slider corresponds to


sets the

n6

number of iterations in MGI solver which corresponds to

The equation above is reordered in such way that we can calculate

H(x, y)

=
+

in which unknown is

H(x, y)
H

from it, thus we have

H(x + 1, y) + H(x 1, y) + H(x, y + 1) + H(x, y 1)


,
4
nx (x + 1, y) nx (x 1, y) + ny (x, y + 1) ny (x, y 1)
8

(3)
(4)

function.

This equation can be solve iteratively by calculating


again until the solution for

H(x, y)

of iterations, very small slider

H(x, y)

for each pixel, then calculating it again, again, and

stop to change. One thing we need to do is to assume proper boundary conditions,

which I assumed for simplicity to be periodic boundary conditions. This is quite natural because usually we want to
have seamless textures, and additionally periodicity is build-in feature of UV coordinates which simplify many things
in GLSL. If you know a little bit of numerical methods you should notice that scheme (3) is the simplest solution
in case of iterative solvers but the convergence of it is very poor. Strictly speaking you may need even thousand of
iterations to reach the convergence and proper solution thus proper form of

H(x, y)

texture. Fortunately, we can

improve the algorithm above using a simple trick which is called multi-grid iteration (MGI) approach. The MGI
method which I will describe in this text will be quite dierent than it is normally used in engineering problems.
We introduce a scale parameter

k = x = y , which means basically that we will


1), which leads to new form of equation

calculate derivatives in (2) for

further distances (k is usually an integer

H(x, y)

=
+

(3):

H(x + k, y) + H(x k, y) + H(x, y + k) + H(x, y k)


,
4
nx (x + k, y) nx (x k, y) + ny (x, y + k) ny (x, y k)
.
8

(5)

H(x, y) is obtained for after


k = 32. This H is used as an initial image for k = 16 which again is iterated n2 times,
k = 4, k = 2 and nally k = 1 with n6 number of iterations. Note that the case for k = 1 in (5)

I will not go into details of multi-grid medthods, but in AB the algorithm is following:

n1

number of iterations for

then

k = 8,

then

restores the equation (3). One may check that this approach lead to convergence after around hundred of iterations.
Of course this will depend on the size of the input image. The number of iterations

n1 , n2 , ..., n6

for each value of

scale parameter can be changed in program with horizontal sliders in normal to height conversion tool (see Fig. 3).
The shader which solves Eq. (2) using MGI method is following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

s u b r o u t i n e ( f i l t e r M o d e T y p e ) v ec4 mode_normal_to_height ( ) {
float scale
= hn_min_max_scale . z ; // s c a l e p a r a m e t e r
v ec 3 o f f
= s c a l e v ec3 ( ve c2 ( 1 ,1) dxy , 0 ) ;
v ec 2 t e x _ c o o r d = v2QuadCoords . s t ;

float
float
float
float

hxp
hxm
hyp
hym

=
=
=
=

texture ( layerA
texture ( layerA
texture ( layerA
texture ( layerA

float
float
float
float

nxp
nxm
nyp
nym

=
=
=
=

2( t e x t u r e ( layerB
2( t e x t u r e ( layerB
2( t e x t u r e ( layerB
2( t e x t u r e ( layerB

, tex_coord
, tex_coord
, tex_coord
, tex_coord

+
+
+
+

, tex_coord
, tex_coord
, tex_coord
, tex_coord

off
off
off
off
+
+
+
+

. yz ) . x ;
. xz ) . x ;
. zy ) . x ;
. zx ) . x ;
off
off
off
off

. yz
. xz
. zy
. zx

) . x 0.5) ;
) . x 0.5) ;
) . y 0.5) ;
) . y 0.5) ;

f l o a t h = ( nxpnxm+nypnym ) / 8 . 0 s c a l e + ( hxp + hxm + hyp + hym ) / 4 . 0 ;


r e t u r n v ec 4 ( h ) ;

// Main e q u a t i o n

In above, the hn_min_max_scale is an uniform variable which in z-th component contains the value of
After the iterations for all values of

normalization the maximal and minimal value of the

H(x, y) is calculated.

This part of calculation is done on CPU

side:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

...
GLint textureWidth , t e x t u r e H e i g h t ;
g l G e t T e x L e v e l P a r a m e t e r i v (GL_TEXTURE_2D, 0 , GL_TEXTURE_WIDTH, &t e x t u r e W i d t h ) ;
g l G e t T e x L e v e l P a r a m e t e r i v (GL_TEXTURE_2D, 0 , GL_TEXTURE_HEIGHT, &t e x t u r e H e i g h t ) ;
f l o a t img = new f l o a t [ t e x t u r e W i d t h t e x t u r e H e i g h t 4 ] ;
g l G e t T e x I m a g e ( GL_TEXTURE_2D, 0 , GL_RGBA, GL_FLOAT, img ) ;
f l o a t min [ 3 ] = { img [ 0 ] , img [ 1 ] , img [ 2 ] } ;
f l o a t max [ 3 ] = { img [ 0 ] , img [ 1 ] , img [ 2 ] } ;
f o r ( i n t i = 0 ; i < t e x t u r e W i d t h t e x t u r e H e i g h t ; i ++){
f o r ( i n t c = 0 ; c < 3 ; c++){
i f ( max [ c ] < img [ 4 i+c ] ) max [ c ] = img [ 4 i+c ] ;
i f ( min [ c ] > img [ 4 i+c ] ) min [ c ] = img [ 4 i+c ] ;
}
}
...
program >s e t U n i f o r m V a l u e ( " m i n _ c o l o r " , QVector3D ( min [ 0 ] , min [ 1 ] , min [ 2 ] ) ) ;
program >s e t U n i f o r m V a l u e ( " max_color " , QVector3D ( max [ 0 ] , max [ 1 ] , max [ 2 ] ) ) ;
...

Then normalization shader is applied:

1
2
3
4
5
6

s u b r o u t i n e ( f i l t e r M o d e T y p e ) v ec4 m o d e _ n o r m a l i z e _ f i l t e r ( ) {
v ec 4 c o l o r = t e x t u r e ( l a y e r A , v2QuadCoords . xy ) ;
c o l o r . r g b = ( c o l o r . r g b m i n _ c o l o r ) / ( max_color m i n _ c o l o r ) ;
color . a = 1;
return color ;
}

k.

the heightmap is normalized to be in range from 0 to 1. In order to do the

Basemap to normal map

In order to calculate normal map from diuse texture the sobel lter is applied on gray scaled diuse image:

Figure 4: Base map conversion sliders.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

c o n s t mat3 s o b e l _ k e r n e l =
mat3 ( 1.0 , 0 . 0 , +1.0 ,
2.0 , 0 . 0 , +2.0 ,
1.0 , 0 . 0 , +1.0) ;
s u b r o u t i n e ( f i l t e r M o d e T y p e ) v ec4 m o d e _ s o b e l _ f i l t e r ( ) {
f l o a t sobel_x = 0;
f l o a t sobel_y = 0;
v ec 4 o c o l o r= v ec4 ( 0 ) ;
f o r ( i n t i = 0 ; i < 3 ; i ++){
f o r ( i n t j = 0 ; j < 3 ; j ++){
sobel_x
+= t e x t u r e ( l a y e r A , v2QuadCoords . xy+v ec2 ( i 1, j 1) dxy ) . r s o b e l _ k e r n e l [ i ] [ j ] ;
sobel_y
= t e x t u r e ( l a y e r A , v2QuadCoords . xy+v ec 2 ( i 1, j 1) dxy ) . r s o b e l _ k e r n e l [ j ] [ i ] ;
}}
v ec 3 n = n o r m a l i z e ( v ec3 ( gui_basemap_amp v ec 2 ( sobel_y , s o b e l _ x ) , 1 ) ) ;
o c o l o r . r g b = clamp ( n 0 . 5 + 0 . 5 , v ec3 ( 0 ) , ve c3 ( 1 ) ) ; // c o n v e r t t o v a l u e s from 0 t o 1
o c o l o r . r g b = v ec 3 (1 o c o l o r . r , o c o l o r . gb ) ;
return ocolor ;
}

The parameter gui_basemap_amp is responsible for the amplitude of the calculated normals (Amplitude slider
in Fig. 4). Note that if gui_basemap_amp=0 then the image will be completely at. After this step image can be
presmoothed using the two-pass guassian blur lter (Presmooth slider, where the value of slider corresponds to the
width of the Gaussian mask i.e. standard deviation of the gaussian distribution function).
After this step normals are manipulated by normal expansion lter, which is executed n-times, where
controlled by the Iters slider:

is

Figure 5: Normal extraction lter example outputs. From left: a) input image, b) image obtained from sobel lter
(case when the parameter Iters is equal 0), c) the same but normal lter is applied (case when Iters

1).

d) Large

number of iterations leads to blurred image.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

s u b r o u t i n e ( f i l t e r M o d e T y p e ) v ec4 m o d e _ n o r m a l _ e x p a n s i o n _ f i l t e r ( ) {
v ec 3 f i l t e r = v ec3 ( 0 ) ;
f l o a t wtotal = 0.0;
int radius
= gui_filter_radius ;
// n o r m a l e x p a n s i o n
i f ( gui_combine_normals == 0 ) {

f o r ( i n t i = r a d i u s ; i <= r a d i u s ; i ++){
f o r ( i n t j = r a d i u s ; j <= r a d i u s ; j ++){
v ec 2 c o o r d s = v ec2 ( v2QuadCoords . xy+v ec 2 ( i , j ) dxy ) ;
v ec3 n o r m a l = n o r m a l i z e (2 t e x t u r e ( l a y e r A , c o o r d s ) . xyz 1) ;
f l o a t w = mix ( l e n g t h ( n o r m a l . xy ) ,
1/(20 g a u s s i a n ( v ec 2 ( i , j ) , g u i _ f i l t e r _ r a d i u s ) l e n g t h ( n o r m a l . xy ) +1) ,
g u i _ n o r m a l _ f l a t t i n g +0.001) ;
w t o t a l += w ;
f i l t e r += n o r m a l w ;

}}
f i l t e r /= ( w t o t a l ) ; // n o r m a l i z a t i o n

r e t u r n v ec 4 ( 0 . 5 n o r m a l i z e ( f i l t e r ) + 0 . 5 , 1 ) ;
} else { . . .
...
}

Basically this code calculates the weighted arithmetic mean of normal vector where the weights are obtained
from the slope of the normal at given point. For example when the value of expression length(normal.xy) is big
then the slope is big. This lter makes that the edges become extruded along the edges. See example below:
The obtained image from the previous step is then mixed with the normal image obtained from sobel operator.
There are two type of blending: a) slope-based (Mixing slider) and b) standard blending (Blending). See the code
below:

1
2
3
4
5
6
7
8
9
10
11

s u b r o u t i n e ( f i l t e r M o d e T y p e ) v ec4 m o d e _ n o r m a l _ e x p a n s i o n _ f i l t e r ( ) {
i f ( gui_combine_normals == 0 ) {
....
} e l s e { // b l e n d i n g and s l o p e b a s e d m i x i n g
v ec 3 n
= n o r m a l i z e ( t e x t u r e ( l a y e r A , v2QuadCoords . xy ) . x y z 2 1) ; // g e t n o r m a l
f l o a t s l o p e = ( 1 . 0 / ( exp (+10 gui_mix_normals l e n g t h ( n . xy ) ) +1) ) ; // s l o p e b a s e d b l e n d i n g param
v ec 4 a = t e x t u r e ( l a y e r A , v2QuadCoords . xy ) ; // p r o c e s s e d n o r m a l image
v ec 4 b = t e x t u r e ( l a y e r B , v2QuadCoords . xy ) ; // n o r m a l image o b t a i n e d from s o b e l f i l t e r
r e t u r n mix ( mix ( a , b , s l o p e ) , a , g u i _ b l e n d _ n o r m a l s ) ;
}
}

Finally, when the Convert to NH button is pressed, the image visible in the right window is copied to the
Normal texture tab, then Height texture is calculated using the algorithm presented in (3).

Specularity texture calculation

In order to calculate specularity from the diuse texture the dierence of gaussian (DOG) lters is applied. For
more information see wikipedia and elsewhere in the internet.

Ambient occlusion texture

In AB ambient occlusion is calculated using well known Screen Space Ambient Occlusion approximation. For more
information see wikipedia and elsewhere in the internet.

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy