Jump to content


Photo

Bump mapping


  • Please log in to reply
41 replies to this topic

#1 slayer 64

slayer 64

    Slayer of gingers

  • GMC Member
  • 3864 posts
  • Version:GM8.1

Posted 28 October 2010 - 11:34 PM

- made in game maker 8 pro
- uses surface fix extension package

version 1
Normal mapping using grids and surface fix. load a heightmap image. get it's color values. calculate the normal vector for each point in the heightmap. take the dot product of each normal vector in the normal map and the light direction vector using ds_grid_multiply and ds_grid_add_region. create light and dark pixels and draw them over a texture using surface fix. use a multiply blend mode when drawing the pixels over the texture: draw_set_blend_mode_ext(bm_dest_color,bm_zero).

normal mapping version 2
i used a colorized model instead of ds grids. much faster than looping and drawing each pixel.

bump mapping version 3
i draw a model to a surface using lighting. i use surface textures all over the place for floor and walls. there's 1 floor and 4 walls. 5 different faces. 5 heightmaps need to be drawn to get the bump mapping effect for each face. i define each face using 3 vectors. i use the 3 vectors to convert the light direction vector into a faces space. i draw a model to a surface using the calculated light direction vector. i draw the surface to the walls and floor. everything is wrapped up in some scripts for easy use! =)

Bump Mapping Host-A

bump mapping version 3
Posted Image

normal mapping version 1
Posted Image

Edited by slayer 64, 02 November 2010 - 01:00 AM.

  • 3

#2 link3000

link3000

    Link3000

  • GMC Member
  • 1130 posts
  • Version:GM8

Posted 29 October 2010 - 01:43 AM

Beautiful. Great work, Slayer64!
  • 0

#3 amd42

amd42

    GMC Member

  • GMC Member
  • 269 posts
  • Version:GM8

Posted 29 October 2010 - 02:25 AM

I see that you got it working. Good job!
  • 0

#4 slayer 64

slayer 64

    Slayer of gingers

  • GMC Member
  • 3864 posts
  • Version:GM8.1

Posted 29 October 2010 - 02:33 AM

I see that you got it working. Good job!


thanks
and thanks Link3000 =)

but it's not fast enough for me :( it runs at 20 fps and i wanted to add more polygons.
this is the slowest point:
for(ay=0;ay<ds_grid_height(gridDot);ay+=1)
{
    for(ax=0;ax<ds_grid_width(gridDot);ax+=1)
    {
        draw_point_color(ax,ay,merge_color(c_black,c_white,-min(0,ds_grid_get(gridDot,ax,ay))))
    }
}
those dam draw_point_colors! making the normal mapping area smaller; like 32x32 is better, meh :/
of course, i am writing low level code in high level game maker :S
this was still a fun project and learning experience =)
  • 0

#5 amd42

amd42

    GMC Member

  • GMC Member
  • 269 posts
  • Version:GM8

Posted 29 October 2010 - 03:07 AM

I've found a way to quickly compute the dot product in hardware by using a special texture blending option, but you can't access it normally from GM. I'll work on an update.
  • 0

#6 Phantom107

Phantom107

    Graphics Enthusiast

  • GMC Member
  • 2665 posts
  • Version:GM:Studio

Posted 29 October 2010 - 11:19 AM

Looks great for native GM, although it runs very slow on this laptop: 20 fps. Runs 40-42 fps on my desktop.

The following optimization increased fps from 20 to 23-24:

Replace this:

for(ay=0;ay<ds_grid_height(gridDot);ay+=1)
{
    for(ax=0;ax<ds_grid_width(gridDot);ax+=1)
    {
        draw_point_color(ax,ay,merge_color(c_black,c_white,-min(0,ds_grid_get(gridDot,ax,ay))))
    }
}
With this:

ay = -1;
repeat ds_grid_height(gridDot)
begin
    ay += 1;
    ax = -1;
    repeat ds_grid_width(gridDot)
    begin
        ax += 1;
        
        draw_point_color(ax,ay,merge_color(c_black,c_white,-min(0,ds_grid_get(gridDot,ax,ay))))
    end;
end;
Luckily I have shader-based hardware powered normal mapping, hehehe.

Edited by Phantom107, 31 October 2010 - 01:23 PM.

  • 0

#7 Docopoper

Docopoper

    You are observant!

  • GMC Member
  • 1287 posts
  • Version:GM:Studio

Posted 29 October 2010 - 10:10 PM

for(ay=0;ay<ds_grid_height(gridDot);ay+=1) { for(ax=0;ax<ds_grid_width(gridDot);ax+=1) {
draw_point_color
(ax,ay,merge_color(c_black,c_white, -min(0,ds_grid_get(gridDot,ax,ay)))) } }

--------------------------------------------

why don't you try writing all the points in a surface fix's saved surface format type file, and then just load that in as a surface.

Edited by Docopop.co.uk, 29 October 2010 - 10:11 PM.

  • 0

#8 Newly Discovered

Newly Discovered

    Harmonious Genius

  • GMC Member
  • 2475 posts
  • Version:GM8

Posted 31 October 2010 - 04:31 AM

Great example! I sure hope to see you put up some walls.
Mine ran at 26-27 fps and it looked beautiful.
  • 0

#9 brett14

brett14

    GMC Member

  • GMC Member
  • 1151 posts
  • Version:GM8

Posted 31 October 2010 - 06:19 PM

Very nice effect, but too slow for realtime - I was getting {27~ fps}. Anyways, a further optimization that doubles my framerate to {51~ fps}.

ay = -1;
repeat ds_grid_height(gridDot)
begin
draw_primitive_begin(pr_pointlist);
    ay += 1;
    ax = -1;
    repeat ds_grid_width(gridDot)
    begin
        ax += 1;
        draw_vertex_color(ax,ay,merge_color(c_black,c_white,-min(0,ds_grid_get(gridDot,ax,ay))),1);
    end;
    draw_primitive_end();
end;


Then there's the option to DECREASE QUALITY to increase performance. Using this method I was getting {220~ fps}

Create rectangles 4x4 in size, and draw them with the color of the verticies of the color the pixels are. Then it will interpolate between them. I couldn't quite get it to draw correctly, which is why I'm not posting the code for it, but you could probably pull it off. If you get this working (with rectangles), I might transfer it to c++ in the form of a dll, to increase the framerates to a possibly acceptable fps.

Cheers
~~Brett14;

Edited by brett14, 31 October 2010 - 06:37 PM.

  • 0

#10 gm_user_tronic

gm_user_tronic

    GMC Member

  • GMC Member
  • 48 posts
  • Version:GM7

Posted 31 October 2010 - 08:31 PM

Looks pretty, can't wait for an update
  • 0

#11 slayer 64

slayer 64

    Slayer of gingers

  • GMC Member
  • 3864 posts
  • Version:GM8.1

Posted 02 November 2010 - 01:08 AM

brett14, you caused me to make the code more efficient. now the example has enough speed for drawing walls and a floor at a minimum of 30 fps =)

my realization was to use models and heightmaps. i create a heightmap, use gm lighting, draw it to a surface and now we have bump mapping/normal mapping.

i feel like i've seen this technique somewhere on the gmc...

if someone was to use this in a game, they might want to make the heightmaps smaller. they are 64x64 right now. i think the example can still be more efficient. somebody take a look. =D
  • 0

#12 brett14

brett14

    GMC Member

  • GMC Member
  • 1151 posts
  • Version:GM8

Posted 02 November 2010 - 01:13 AM

brett14, you caused me to make the code more efficient

I have a bad tendency to do that XD. I like to see code as optimized as possible.

i think the example can still be more efficient. somebody take a look

Will do. If I can find any more optimizations I'll post them. (Downloading right now) I will edit it after.

Cheers
~~Brett14;

Edited by brett14, 02 November 2010 - 01:22 AM.

  • 0

#13 Docopoper

Docopoper

    You are observant!

  • GMC Member
  • 1287 posts
  • Version:GM:Studio

Posted 02 November 2010 - 10:19 PM

you should add point lights, and attempt triangles (should be easy enough)
  • 0

#14 michael pw

michael pw

    GMC Member

  • GMC Member
  • 1488 posts
  • Version:GM8.1

Posted 02 November 2010 - 10:32 PM

Damn Slayer how are you so good with Gm???? it boggles me?

anyway amazing effect, will probably use this at some point. :)
  • 0

#15 YellowAfterlife

YellowAfterlife

    GMC Member

  • Global Moderators
  • 3984 posts
  • Version:GM:Studio

Posted 03 November 2010 - 12:03 AM

To improve perfomance, you *could* try to make system array-based.
According to the following script-test, 2d array works not less than 25% faster than ds_grid (at last at my machine).
loops = 100
cycles = 10000
modval = 1024
mulval = 10000
io = "Output:"
//1d Array:
o = 0
for (j = 0; j < loops; j += 1)
{
t = date_current_time()
for (i = 0; i < cycles; i += 1) a1d[i mod modval] = i mod modval
v = date_current_time()
o += date_second_span(t,v)
}
o /= loops
io += "#1dArray: " + string(o * mulval)
//2d Array:
o = 0
for (j = 0; j < loops; j += 1)
{
t = date_current_time()
for (i = 0; i < cycles; i += 1) a1d[i mod modval,(i + 64) mod modval] = i mod modval
v = date_current_time()
o += date_second_span(t,v)
}
o /= loops
io += "#2dArray: " + string(o * mulval)
//DS Grid:
g = ds_grid_create(1024,1024)
o = 0
for (j = 0; j < loops; j += 1)
{
t = date_current_time()
for (i = 0; i < cycles; i += 1) ds_grid_set(g,i mod modval,(i + 64) mod modval,i mod modval)
v = date_current_time()
o += date_second_span(t,v)
}
o /= loops
ds_grid_destroy(g)
io += "#DS Grid: " + string(o * mulval)
show_message(io);
(code may be executed from anywhere, and may take a couple of seconds to execute under default configuration. Will show a messagebox with median execution time for 1d array, 2d array, and ds_grid)
  • 0

#16 slayer 64

slayer 64

    Slayer of gingers

  • GMC Member
  • 3864 posts
  • Version:GM8.1

Posted 03 November 2010 - 01:06 AM

that code looks to be one-sided. the part that tests the 1d array has fewer calculations in it than the 2d and grid tests. it might be better to actually test the access time for 1d arrays, 2d arrays, and grids. and not include a bunch of extra math calculations to skew the results.
output="Output:"
loops=1000

//test 1d array
    time=current_time
    repeat loops a[0]=5
    output+="#1d array "+string(current_time-time)
    
//test 2d array
    time=current_time
    repeat loops a[0,0]=5
    output+="#2d array "+string(current_time-time)

//test grid
    time=current_time
    repeat loops ds_grid_set(grid,0,0,5)
    output+="#grid       "+string(current_time-time)

show_message(output)

the bump map example doesn't loop through 1000's of indexes. just 5. let's not get into what has better access time. if "loops" is set to 5, they all take 0 time to execute.
  • 0

#17 brett14

brett14

    GMC Member

  • GMC Member
  • 1151 posts
  • Version:GM8

Posted 03 November 2010 - 05:57 AM

I have found that arrays are slightly faster than grids (long time ago). It isn't noticeable (like only a few percent) but there is some speed advantages.
HOWEVER - It takes ALOT longer to change values inside of an array on a mass scale (aka: multiply everything), so the system you're using at the moment is actually the fastest way (that I can think of) to do things.
  • 0

#18 brett14

brett14

    GMC Member

  • GMC Member
  • 1151 posts
  • Version:GM8

Posted 03 November 2010 - 05:59 AM

I have found that arrays are slightly faster than grids (long time ago). It isn't noticeable (like only a few percent) but there is some speed advantages.
HOWEVER - It takes ALOT longer to change values inside of an array on a mass scale (aka: multiply everything, sort the array, etc.), so the system you're using at the moment is actually the fastest way (that I can think of) to do things.
  • 0

#19 Docopoper

Docopoper

    You are observant!

  • GMC Member
  • 1287 posts
  • Version:GM:Studio

Posted 03 November 2010 - 06:23 PM

http://gmc.yoyogames...1

what about ds_bin - I don't know if it is actually faster though
  • 0

#20 slayer 64

slayer 64

    Slayer of gingers

  • GMC Member
  • 3864 posts
  • Version:GM8.1

Posted 03 November 2010 - 11:49 PM

http://gmc.yoyogames...1

what about ds_bin - I don't know if it is actually faster though


yes arrays are faster; says so in the manual.
it doesn't matter. the bump mapping example doesn't lag from accessing lots of numbers in a ds grid. it lags if you draw models with lots of triangles in them. i was thinking of making more efficient models by removing triangles. but if someone wanted to make a bump map with lots of little details, you couldn't remove triangles. how can we achieve the same bump mapping effect with less cost? in gml :S
  • 0

#21 brett14

brett14

    GMC Member

  • GMC Member
  • 1151 posts
  • Version:GM8

Posted 04 November 2010 - 12:22 AM

Simple: You can't at the moment, unless Mark improves Gamemaker like he needs to.
I would suggest compiling it. However, this is unlikely and it is hard to program a compiler - and most people stop there. Instead of prgramming a compiler, I world parse gml to a different language (such as c++, or delphi) and use a compiler on that code (such as one from the GCC - GNU Compiler Collection)

Edited by brett14, 04 November 2010 - 12:25 AM.

  • 0

#22 slayer 64

slayer 64

    Slayer of gingers

  • GMC Member
  • 3864 posts
  • Version:GM8.1

Posted 04 November 2010 - 02:09 AM

but brett, you must think outside the box! we could all just give up game maker and go write super efficient assembly code, yes? i want to do challenging stuff.

a week ago the bump mapping example could barely display a bump map on the floor. now it can do the floor and walls. bam! thinking outside the box; it's what i did. maybe the community can help by provoking me to think outside the box again =)
  • 0

#23 brett14

brett14

    GMC Member

  • GMC Member
  • 1151 posts
  • Version:GM8

Posted 04 November 2010 - 04:16 AM

There comes a point where you can't improve it anymore. For example, how do you optimize

if(a==0){
enemy.hp-=1;
}
?

You can't.

Edited by brett14, 04 November 2010 - 04:20 AM.

  • 0

#24 Phantom107

Phantom107

    Graphics Enthusiast

  • GMC Member
  • 2665 posts
  • Version:GM:Studio

Posted 04 November 2010 - 09:49 AM

I hope you guys realize that this would be totally inefficient using normal code no matter what, even in C++, dephi and whatnot. The CPU still has to calculate it all that way. No, what it really needs is shader acceleration on the GPU so you could use nVidia-CG shaders to handle this at super high speeds. The GPUs shaders are many times more powerful than CPUs, even Core i7s.
  • 0

#25 e_barroga

e_barroga

    ES Studios Leader

  • GMC Member
  • 2449 posts

Posted 04 November 2010 - 01:50 PM

Normal mapping and bump mapping is the same thing.
  • 0

#26 Phantom107

Phantom107

    Graphics Enthusiast

  • GMC Member
  • 2665 posts
  • Version:GM:Studio

Posted 04 November 2010 - 03:11 PM

Normal mapping and bump mapping is the same thing.

No, there is a difference. The technique in this topic is 1D bump mapping; it's not normal mapping as that takes 3D information into account.
Take a look at this:

Bumpmaps:
Single axis hieght information maps that the renderer can use to "shade"
the surface it is applied to. (1D Bump Maps). The hieght info is usually
stored as a grey scale 8 or 16 bits per pixel image file where the low
values (black) represent the low areas (valleys) and the high vlaues
(white) are used to represent the the high areas (peeks).

Normalmaps:
Three axis hieght information maps that the renderer can use to "shade"
the surface it is applied to. (3D Bump Maps). The X, Y, or Z axis specific
hieght info is usually stored as a 8 or 16 bits per pixel color image file
where the low values for the x axis (black) represent the low areas
(x-axis-dents) and the high vlaues (RED) are used to represent the
high areas (x-axis-protrusions). Green is used for the y axis in the
same way and blue for the z axis. Because normal maps contain
hieght information for all three axis (x, y, z) it is posible to discribe
a complete 360 degree curvature on all 3 axis in the shaded surface.


Source http://www.spinquad....s-vs.-Bump-maps
  • 0

#27 Docopoper

Docopoper

    You are observant!

  • GMC Member
  • 1287 posts
  • Version:GM:Studio

Posted 04 November 2010 - 08:39 PM

There comes a point where you can't improve it anymore. For example, how do you optimize

if(a==0){
enemy.hp-=1;
}
?

You can't.


ha! what about:
enemy.hp-=(a==0);

lol, fail - think outside the box!
  • 0

#28 slayer 64

slayer 64

    Slayer of gingers

  • GMC Member
  • 3864 posts
  • Version:GM8.1

Posted 04 November 2010 - 11:50 PM

There comes a point where you can't improve it anymore. For example, how do you optimize

if(a==0){
enemy.hp-=1;
}
?

You can't.


you optimize it by not using it at all. use a completely different technique to achieve an overall goal.
why would you check "a" at all? maybe "a" should be the value to be subtracted.
  • 0

#29 amd42

amd42

    GMC Member

  • GMC Member
  • 269 posts
  • Version:GM8

Posted 05 November 2010 - 03:54 AM

I hope you guys realize that this would be totally inefficient using normal code no matter what, even in C++, dephi and whatnot. The CPU still has to calculate it all that way. No, what it really needs is shader acceleration on the GPU so you could use nVidia-CG shaders to handle this at super high speeds. The GPUs shaders are many times more powerful than CPUs, even Core i7s.


You actually can compute the dot product in hardware with C++ and without any fancy pixel shaders. All you do is set a special texture blending operation (I forget the name) which computes a 3D dot product, pass in the light direction, and then draw the normal map to a surface. Then you just multiply the result over the screen and you're set.

I'm just too busy to implement anything right now though.
  • 0

#30 brett14

brett14

    GMC Member

  • GMC Member
  • 1151 posts
  • Version:GM8

Posted 07 November 2010 - 05:59 PM

that wasn't my point. I'm saying that not everything can be optimized (I know using other methods is faster, but there comes a point where you can't optimize.
  • 0




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users