# GMLscripts.com

Discuss and collaborate on GML scripts

You are not logged in.

## #1 2009-08-04 15:06:17

xot
Registered: 2007-08-18
Posts: 1,077

### NAILS prototype - raster-based light and shadow engine

Oh No!

Not Another Idiotic Light and Shadow prototype!

Yep.

I had a major brainstorm last night for an entirely new shadow engine. I've finally figured out a way to do raster-based shadows at practical speeds.

I've tried something like this before. I mentioned it in my first shadow engine topic. That was work that came out of the initial development of the range_finder script. The idea was to cast 2D shadow volumes from point light sources using the contours of shadow casting sprites. The problem was the range_finder script is costly, and to get any kind of remotely decent quality required at least 360 calls per light (1 degree of angular precision). It was hopeless. Two lights and 30 on-screen instances ran at a crushing 15 fps on a 2GHz CPU. It was clearly not the answer and that was the end of the raster-based shadow project.

Until now.

This thing is wild. I love the way it works. It's all on the GPU hardware which makes it literally 100 times faster than the clunky range_finder system. I've been calling this the "raster-transform" technique, but "raster-warp-feedback" might be closer to the mark. The germ of the idea popped into my head last night as I lay in bed and by this afternoon it had borne its first fruit.

The raster-transform technique depends on three things: UV map warping, surfaces, and blend modes. I won't be going into the exact implementation details just yet, but I'll do my best to explain how it works in simple visual terms.

First observe a marvelously exploitable feature of the polar-to-rectangular transform. In the first image, we see a scene with a point light source in middle, and some arrows indicating light rays radiating out in all directions. The letters F and X will be our shadow casters. In the next image, we see what happens when we warp the image using a polar coordinates filter similar to the one in Photoshop. Notice anything interesting about the light rays?

The warped light rays are axis-aligned and parallel. Parallel light means parallel shadows.

We can construct shadows from the shadow casters if we imagine them being wet paint that we've smeared downward. Once we've done that, we apply the inverse polar coordinate transform and Ka-Powza! there's our radial point light source shadows.

That's the basic premise. I'll follow-up soon with details about how it can be done in Game Maker, and most importantly, how it's done quickly.

Last edited by xot (2012-02-24 13:29:44)

Abusing forum power since 1986.

Offline

## #2 2009-08-04 21:13:31

icuurd12b42
Member
Registered: 2008-12-11
Posts: 303

### Re: NAILS prototype - raster-based light and shadow engine

Hmmm. I hate it when you leave us hanging like that But I am willing to be patient

Offline

## #3 2009-08-05 05:05:36

xot
Registered: 2007-08-18
Posts: 1,077

### Re: NAILS prototype - raster-based light and shadow engine

I've got it up and running, I just need to iron out some wrinkles in the rectangular-to-polar warp.

You can see a weird glitch on the left side (a few black lines). That's actually a reflection of sorts caused by some faulty UV mapping on my part. I need to construct the filter a little differently. I think it will improve over quality as well.

I'm also still trying to figure out some blending options. There are a lot of interesting effects you can get with this basic technique. Right now I'm using bm_src_alpha_sat as one of my blend factors. It solved some strange blending problems I was having (and I still don't understand what the problem is). I've never used that blend factor before, I only tried it out of desperation. Amazingly, it worked perfectly the first time. It was a Hallelujah moment. I still don't really get how it works. The equation is simple enough, but visualizing it in my mind gives me difficulty.

The other thing that still needs to be addressed is the shading. Unfortunately, I haven't figured out how to shadow the shadow-casting sprites themselves without self-shadowing (making all of them unlit because they're each standing in their own shadow). I can get around the problem, but not without breaking most of the things that make this fast. It still might be practical, but it might also be a bit complicated. I'll worry about that later. For now I'll be happy just to color the sprites correctly.

Abusing forum power since 1986.

Offline

## #4 2009-08-05 14:47:12

icuurd12b42
Member
Registered: 2008-12-11
Posts: 303

### Re: NAILS prototype - raster-based light and shadow engine

Neet. I would suggest you put up the gmk file(s) for us to look at. Incrementaly as you progressively add to it. That way it would be easier to follow the concept.

And the blend modes... Join the club. I have yet to figure the right one myself. I even made mine to use globals for blend mode ex and used another object to change the 2 bms when I press the arrow keys. I went though all the blend mode combinations and I still did not find the rigth one. I dont think the solution lies in the blend mode only but in combination with the draw color, the surface prep and final draw.

Offline

## #5 2009-08-05 20:09:26

xot
Registered: 2007-08-18
Posts: 1,077

### Re: NAILS prototype - raster-based light and shadow engine

OK. Let's take a look at the prototype.

A        Add some shadow castersD        Destroy some shadow castersG        Toggle gravity effectS        Toggle shadow effect1        Display warped shadow surfaceShift    Alter room speed

This is a proof-of-concept demonstration of technology that could be used to build a high-speed raster-based shadow system. It's primary advantages are its simplicity, its scalability, and the fact that it is almost entirely executed on GPU hardware. Virtually no calculations are made in the GML interpreter. For a single light with a radius 256 pixels, no more than 11 adds and 11 multiplies are required for a scene of any complexity. In addition to these meager mathematical requirements: two surfaces of arbitrary size (512 x 512 pixels in this demo), two models of arbitrary complexity (~2400 triangles each in this demo), the willingness to draw your shadow casting sprites once for any number of lights. Support for multiple lights requires two more surfaces, ideally the size of the view. Shading and multiple lights are not demonstrated here.

Taking this apart, here's the code to go with the conjecture.

1. Draw shadow casting instances in black to a white surface. Instances are draw relative to light placed in center of surface (polar origin).

        // Paint Shadows
surface_set_target(work);
draw_clear_alpha(c_white,1);
d3d_transform_set_identity();
draw_set_blend_mode_ext(bm_src_alpha_sat,bm_inv_src_alpha);
draw_set_blend_mode(bm_normal);
surface_reset_target();

Very straight-forward.

2. Warp the surface using a specially prepared UV mapped model to perform a polar-to-rectangular transform.

        // Warp Shadows
surface_set_target(surf);
d3d_transform_stack_push();
draw_clear_alpha(c_white,1);
texture_set_repeat(true);
draw_set_color(c_white);
draw_set_alpha(1);
d3d_model_draw(modelP2R,0,0,0,surface_get_texture(work));
d3d_transform_stack_pop();
surface_reset_target();

The magic here is certainly the model.

3. Smear the resulting warped shadows straight downward and off of the edge of the image using a multiplicative blend and a feedback loop coupled with image shifting.

        // Smear Shadows
surface_set_target(surf);
draw_set_blend_mode_ext(bm_src_alpha_sat,bm_src_color);
var i,j,temp;
j = 0.5;
k = 1.77; // nearly 2, ceil(logn(k,512)) = 11 passes
for (i=0; i<h; i+=j)
{
j *= k;
draw_surface(surf,0,i);
}
draw_set_blend_mode(bm_normal);
surface_reset_target();

There's some magic going on here too. Naively doing what this describes could be a costly operation. What it does is take a white image with black shadow caster sprites painted on it and smear it downward. The smear is accomplished by drawing the image on top of itself, one row lower, and repeating this process until it covers the length of the image. By using a multiplicative blend, we have what is essentially a kind of "darken" filter. White-on-white stays white, but any other combination (white-on-black, black-on-white, black-on-black) becomes black. As we repeat the drawing, the shapes extrude into shadow volumes. If we repeat this for every row, top to bottom, we'll create a long streak starting with the shadow casting sprite and stretching all the way to the bottom. For a 512 pixel tall texture, that's would be 512 rows of overdrawing, or 512 passes. That's obviously far too many.

Fortunately, we can take advantage of the fact the same initial image is constantly repeating. For the first pass, we draw the image to itself, one row lower. The smear is only 2 pixel long at this point. We shift the image 2 rows and overdraw. The smear is now 4 pixels long. Double the amount of the shift to 4 and on the next pass the smear is 8 pixels long. Repeat, doubling the offset each pass, until the offset exceeds the height of the texture. This provides us significant savings. For a 512 pixel tall image, instead of 512 passes, we reduce it to a theoretical log2(512) passes, or 9 passes. In practice, precision problems mean we can't double the offset without introducing small gaps in the shadow volume. This is a particular problem if the shadow caster is only 1 or 2 pixels in thickness in the direction of the light, which can happen frequently along sprite contours. By not being so greedy, we can increase our stride by 87% instead of the full 100% to get a cleaner result at the cost of only one extra pass. In this example, the scaling factor of 1.77 means 11 passes are performed. Alternatively, a larger scaling factor could be used with a smaller initial stride, 1/2 pixel instead of a full pixel. The number of passes performed works out to be the same.

4.  Un-warp the warped surface using a specially prepared UV mapped model to perform a rectangular-to-polar transform.

        d3d_transform_stack_push();
draw_clear(c_black);
draw_circle_color(w/2,h/2,w/2,c_white,c_black,false);
texture_set_repeat(true);
draw_set_color(c_white);
draw_set_blend_mode_ext(bm_dest_color,bm_zero);
d3d_model_draw(modelR2P,0,0,0,surface_get_texture(surf));
draw_set_blend_mode(bm_normal);
d3d_transform_stack_pop();

Another magic model, this one is the inverse of the first. Lighting is drawn separately here, but it could be built into the model if lit areas are disc-shaped and of a single color.

Known Problems

This prototype has a problem with the rect-to-polar model. The model is constructed using a Cartesian lattice for its structure. Although some of the artifacts caused by this have been minimized, shadows cast from near the light have some unacceptable distortions. It is expected that this can be corrected by using a polar lattice structure for the rect-to-polar model.

Abusing forum power since 1986.

Offline

## #6 2009-08-06 00:50:18

icuurd12b42
Member
Registered: 2008-12-11
Posts: 303

### Re: NAILS prototype - raster-based light and shadow engine

Hmm that is interesting, yet confusing LOL... The multiple draws to generate the "smear" is only done with the surface that holds all the data which is good. It reminded me of another system that did that per caster sprite (more costly) so I opened up mine and added that (more costly one) in. I doubt I can add your method to my engine as a caster script as it relies on drawing the model with all the data (in the surface texture) arround (at) the light coords (yes!??) but it gave me another idea for yet another caster which I'll try out tomorow I think.

Offline

## #7 2009-08-06 06:29:21

xot
Registered: 2007-08-18
Posts: 1,077

### Re: NAILS prototype - raster-based light and shadow engine

I doubt I can add your method to my engine as a caster script as it relies on drawing the model with all the data (in the surface texture) arround (at) the light coords (yes!??)

Right. Because this uses a model, the UV coordinates are not computed per-frame. That's one of the main reasons it's fast. That also means the shadow "seeds" must be drawn onto a texture/surface relative to the light. The light is at the polar coordinate space origin which we place in the center of the texture.

Drawing the shadow seeds (I like that) is the most costly operation in the system if you have a lot of instances. If done simply, you have to draw every sprite once for each light in the scene. That runs in roughly O(n^2) time; draws = casters * lights. Shadow seed drawing gets expensive as the scene becomes more complex. Even if you only draw the casters that are within the range of a light, it's still expensive. You've merely replaced drawing time with time spent on visibility calculations. If you end up drawing everything anyway, it's even more wasted time.

A way to drastically speed up the process, if you are willing to commit the texture memory, is to draw every shadow seed only once to a single cache texture as big as the room (or as big as the view+2*r, where r is the radius of the largest light). With this master texture we can create other textures by copying sections of it. That only takes two triangles and a tiny bit of math to calculate the four UV coordinates for the region within the master texture. If your textures are always axis-aligned, you could use the surface_copy_part function to accomplish the same thing. Now it runs in O(n) time, which allows for a massive improvement in speed for complex scenes. The YAILASE system uses this and similar caching tricks to minimize repeated drawing and keep speeds up.

Abusing forum power since 1986.

Offline

## #8 2009-08-06 10:35:49

xot
Registered: 2007-08-18
Posts: 1,077

### Re: NAILS prototype - raster-based light and shadow engine

I've updated the demo a bit. The only changes are a status display and some controls for adding/destroying instances and toggling the gravity and shadows.

EDIT:

This runs about 15% faster under GM8 beta 2.

Last edited by xot (2009-08-09 17:01:02)

Abusing forum power since 1986.

Offline

## #9 2009-09-07 01:18:28

xot
Registered: 2007-08-18
Posts: 1,077

### Re: NAILS prototype - raster-based light and shadow engine

Here's an update from three weeks ago that I forgot to post. This version largely corrects the weird artifacts that appears in shadows that are near the center of the light.

As expected, constructing the lattice with polar coordinates more or less solved the problem. It also simplified the creation of the inverse transform. It turns out, because I built the model as a unit square, all I needed to do to create an inverse transform is to replace (x,y) with (u,v) and vice versa.

The change hasn't completely solved the problem. It's been replaced by a different artifact but it's only a single pixel. Hopefully, I can iron this out without resorting to painting over the troubled pixel to hide the problem -- although that's not a horrible solution.

Abusing forum power since 1986.

Offline

## #10 2011-06-12 18:21:58

xot
Registered: 2007-08-18
Posts: 1,077

### Re: NAILS prototype - raster-based light and shadow engine

I stumbled across something interesting today. This guy Catalin Zima (apparently a hotshot in the XNA Community) came up with an almost identical way of doing shadows. He uses XNA and shaders and his transforms are a little bit different, but it is very much the same idea. Neat!

Abusing forum power since 1986.

Offline

## #11 2012-02-07 11:09:22

NeatWolf
Member
From: Oristano, Sardinia, Italy
Registered: 2012-02-07
Posts: 4

### Re: NAILS prototype - raster-based light and shadow engine

I have to say, your solution is brilliant! ...and sorry about resurrecting a 3 years old post, it's a solution with no time
I'm trying to revamp your code as a full featured lightning system but I stumbled upon a problem: since I'm blending the colored light with bm_add, there are visible seams of the transformation solid (that is, radial and concentrical lines). Simply put, the polygons overlap, and they form brightened points.
Since I'm using a few detailed backgrounds in my project it's not a big problem, with multiple light sources it could be easily considered "light noise":
http://img189.imageshack.us/img189/9467 … gine02.jpg
But on a solid dark background it is:
http://img833.imageshack.us/img833/4803 … gine03.jpg

I tried every possible blending combination, but the seams persist in the very few combinations that gave the desired result.
So I thought it was probably a good idea to have a third surface where to render the opaque (and seamless) final light casting, and then blend it again in bm_add or another similar blend.

The fact is, for some reason I'm not getting the rendered solid on that surface, but for some strange reason only the non-transformed texture that you called "surf".

In the shadows_build script you wrote I appended this code (called in the EndStep Event):

        surface_set_target(surfFinal);
d3d_transform_stack_push();

texture_set_repeat(true);
draw_set_color(c_white);
draw_set_blend_mode_ext(bm_dest_color,bm_zero);

d3d_model_draw(modelR2P,0,0,0,surface_get_texture(surf));
d3d_transform_stack_pop();
surface_reset_target();

But when I try to draw surfFinal, I always get a result identical to surf.

Since I'm not very practical with 3D transformations in GameMaker, am I missing something?
I'm using GameMaker Standard v8.1.141.
Are you still working with this code, or have an improved version of it? (I think I'll probably smudge the shadow borders a bit since with using low_res light maps creates a few artifacts during the transformation process)

EDIT: my fault! For some reason I was fiddling with the numbers to see if I could get some neat effect... and I left a y1 = (j + 1.01) / argument1; in the model_polar_rect script. The original value was 1, not 1.01.

Still, I don't get why I can't render on a surface though

Last edited by NeatWolf (2012-02-07 17:43:10)

Offline

## #12 2012-02-08 15:08:09

xot
Registered: 2007-08-18
Posts: 1,077

### Re: NAILS prototype - raster-based light and shadow engine

Hi, NeatWolf, welcome to the forums!

I'm always pleased whenever someone finds interest in one of my examples; no apologies for resurrecting the topic are necessary.

I'm not sure I understand the problem you are having with the surface drawing, at least not the way you describe it, but I do see a couple of potential problems. It looks like you are using basically the same drawing code that the example uses, except you are directing it to a surface.

The first difference I see is that you are not setting the blend mode back to normal, which might interfere with any drawing that follows.

The second possible problem has to do with the blend mode itself and what it expects of the surface being drawn to. The surface needs to be opaque (alpha > 0) and it needs to be something other than black. When drawn to with the code you've given, a white opaque surface should display the shadows completely. I've tested it here and it seems to work. Without knowing more about the contents of surfFinal, it is difficult to say what the problems might be.

I should also point out that this demo uses feedback loop which draws a surface to itself. This is a not officially supported by DirectX and could result in artifacts (eg. blockiness, "random" data, color shifting) or even crashing. The feedback loop should be redesigned to alternate between two surfaces so that the target is never the same as the source. Unfortunately, that also means it requires more drawing and possibly memory to achieve the same effect.

If that information doesn't help, perhaps you could create a simple demonstration of the problem that I can look at.

I have not really worked on this since I posted the topic beyond trying (and failing) to create a version that worked with views and multiple lights. I've been distracted by other things and have never gotten back to it.

I just watched your A.D.O.N. Project videos. Absolutely stunning work in all respects.

Last edited by xot (2012-02-08 15:45:30)

Abusing forum power since 1986.

Offline

## #13 2012-02-08 18:35:08

NeatWolf
Member
From: Oristano, Sardinia, Italy
Registered: 2012-02-07
Posts: 4

### Re: NAILS prototype - raster-based light and shadow engine

Well, what you call a mere "example" is beyond comprehension for many, and I find that your intuition about using polar coordinates for solving the problem is unrivaled among the 2D shadow casting techniques!

xot wrote:

I should also point out that this demo uses feedback loop which draws a surface to itself. This is a not officially supported by DirectX and could result in artifacts (eg. blockiness, "random" data, color shifting) or even crashing. The feedback loop should be redesigned to alternate between two surfaces so that the target is never the same as the source. Unfortunately, that also means it requires more drawing and possibly memory to achieve the same effect.

Yes, I used the same technique for the bloom effect, but ended up in using 2 surfaces as well.

xot wrote:

I have not really worked on this since I posted the topic beyond trying (and failing) to create a version that worked with views and multiple lights.
I just watched your A.D.O.N. Project videos. Absolutely stunning work in all respects.

Aw, I saw your YouTube video with that 3D overhead lightcasting engine and was crossing my fingers it was the same light engine.

Anyway, I extended the example a bit, and was about to ask if I could use the example as a base for a complementary light engine for Adon.
It now works with multiple lights (as in the previous screenshot I posted), rooms and a has a few tweaks on the mapping (I still have to blur it a bit tho) like soft shadows and animated noise (useful for fireplaces).
I wish I could light-dodge with that map, the result is nice, but the background seems a bit flat (and I tried all the possibile blend combinations :-/ Using a temporary surface would increase the chances of finding the proper blending)
(and, well, I'm already experimenting it on Adon as well: http://img826.imageshack.us/img826/425/ … gine04.jpg)
Thanks for your compliments, I was pretty surprised as well on finding it on indiegames.com this morning!

xot wrote:

If that information doesn't help, perhaps you could create a simple demonstration of the problem that I can look at.

Drawing it on a surface is not mandatory, but helps with optimization (using a single surface for all the visible lights in the view, instead of instancing several surfaces for each light).
But... maybe I didn't explain it properly. When I draw my finalSurf (a simple temporary surface), I actually *do* get something... but it's the unwrapped, non-transformed original surf!

I'll try to isolate the code, I have to rollback a few versions. I'll repost as soon as possible.

Last edited by NeatWolf (2012-02-08 21:32:54)

Offline

## #14 2012-02-09 16:42:03

xot
Registered: 2007-08-18
Posts: 1,077

### Re: NAILS prototype - raster-based light and shadow engine

You are certainly welcome to use whatever you wish from the example. I don't require credit, but a thank you is always nice.

It seems I didn't understand your surface problem at all. I'm not sure where things might be going wrong but if you post something with the problem I'm happy to help. A guess would be mixed up resource IDs or creating the models with the wrong arguments. If you don't want to post anything publicly, I can be reached by email via xot at this domain.

http://dunnbypaul.net/blends/

As for the videos I posted on YouTube, that is a different lighting system. You can read about its evolution in the topic linked below. The topic is quite long and even more confusing than this one. A demo is linked near the bottom of the first post, but it is probably something that would be very difficult to re-use. It's not a lighting "engine" by any means, just a tech demo.

http://www.gmlscripts.com/forums/viewtopic.php?id=1574

I believe many of the difficulties I encountered while developing it can be resolved using the SurfaceFix DLL created by amd42 or the current version of GameMaker 8.1. I have not worked on it in a long time nor have I tried adapting it for these newer tools.

Abusing forum power since 1986.

Offline

## #15 2012-02-15 12:59:10

xot
Registered: 2007-08-18
Posts: 1,077

### Re: NAILS prototype - raster-based light and shadow engine

NeatWolf, you've been busy!

It's really nice to see a practical application of the technique I described in this topic. Of course it's the creative application of it that makes it shine and I had nothing to do with that. I must say it inspires me to get back to work on this.

By the way, I enjoy the commentary you put on your videos. More developers should do this.

Abusing forum power since 1986.

Offline

## #16 2012-02-15 16:33:14

NeatWolf
Member
From: Oristano, Sardinia, Italy
Registered: 2012-02-07
Posts: 4

### Re: NAILS prototype - raster-based light and shadow engine

xot wrote:

NeatWolf, you've been busy!

*cough* sorry if it took a while, but I rewrote a few parts hoping to improve the overall performance but... well, somehow I failed, or reached the limit.
That is: I now make only 1 draw per shadowable object, get a global occlusion mask, and every light source refers to it. Added the required translations/transforms to make everything run with view support and with the possibility to deactivate them to improve performance. In the recent build of Adon I also made the light accomodate their update frequency to mantain an acceptable frame rate.

*BUT*

somehow when I set the "scale" factor to a value less than 1 (always trying to keep the texture size a power of 2. So I'm talking about scale values of 0.5, 0.25, 0.125 and so on with initial light Radius of 256-512), the performance drops.
That's... weird, but probably the d3d_set_scale is less efficient than I thought. Or probably there's something in the math that I'm missing. Probably something like something that scales in an inverse proportion (thus if I set a scale resolution factor of 0.5 I'm actually drawing something 2 times bigger, or 4 times less efficiently since we're in 2D).

Even in your example it's noticeable how the cost in drawing many scaled objects to the shadow map severely decreases the framerate.
That is, using a 0.1 scale factor and 31 objects the frame rate was about 240, that dropped to 100 when I increased the number to 337 shadowcasters.
On the other side, using a scale factor of 1, the frame rate is obviously lower, but even adding >500 shadowcasters it was still about 53-54 fps, it only lost a few frames per second (1-3) in respect of the same test with only 31 objects.

My question is: is it normal? Is the cost of sprite scaling so high, or is it because of the algorithm?
Now that I'm writing... maybe I can just use a 1:1 scaled occlusion mask, resize it once, and use it in the local and scaled maps of each spotlight... I have to try it.

Yes, I know, I could use/write a DLL but... I'm trying to do everything without it for now. It's part of the fun, and somehow using something external makes it feel less... genuine

xot wrote:

I must say it inspires me to get back to work on this.

Let me know if I can be of help with some of the code I wrote (taking in account views, common mask drawing), I'll be deeply grateful if you could manage to improve the performance of the example while still keeping some flexibility.
For what I saw in your code, well, it's hard to improve it, it's really well written, I could just apply a few optimization to accomodate the way GML works but... I'll definitely lose something in readability

xot wrote:

By the way, I enjoy the commentary you put on your videos. More developers should do this.

Again, I'm glad you enjoyed it, I've been criticized for putting too much developer commentary... but I think it adds an extra value, it's not a trailer afterall!

Btw: I solved the surface problem. I really don't know what it was, but rewriting almost everything from scratch solved the issue
About the blend modes: I added a small filter to restore some of the contrast, but it requires an entire redraw of the scene at the moment.
It also gives a nice incandescent look to the brightest parts
Here are a few pics of it, respectively with the filter OFF and ON. The "5 fps" was forced to take the screenshots
[spoiler]http://img444.imageshack.us/img444/2743 … gine08.jpg
http://img100.imageshack.us/img100/3898 … gine06.jpg[/spoiler]
EDIT: duh, seems like the spoiler tag is not working, I'm putting a link instead of directly embedding the pics.

Last edited by NeatWolf (2012-02-16 02:05:54)

Offline

## #17 2012-02-15 22:11:20

icuurd12b42
Member
Registered: 2008-12-11
Posts: 303

### Re: NAILS prototype - raster-based light and shadow engine

WOW. what a game!

Offline

## #18 2012-05-02 09:37:44

NeatWolf
Member
From: Oristano, Sardinia, Italy
Registered: 2012-02-07
Posts: 4

### Re: NAILS prototype - raster-based light and shadow engine

icuurd12b42 wrote:

WOW. what a game!

Hehe, thank you
I'm still working on it, it's 14 months of work right now

xot, are you still working on the example?
I'm still using it as a base for the engine and works smoothly but, you never know, just checking

Last edited by NeatWolf (2012-05-02 14:47:39)

Offline

## #19 2012-05-03 11:31:40

xot
Registered: 2007-08-18
Posts: 1,077

### Re: NAILS prototype - raster-based light and shadow engine

I haven't really done anything new with this, but I did modify it a little. In the first post you'll see new animated illustrations to help explain the process. I made those in GameMaker using the light engine code as a base. The code I added to animate the model just performs a linear interpolation of corresponding points in the normal texture and the warped texture.

Initially, the animations looked really confusing because of the way the model was constructed. It split horizontally and twisted around strangely and was hard to understand visually. I changed the transform around a little to make it more visually pleasing and less confusing. The difference might only be a cosmetic improvement in the illustration, or it may result in higher quality in the practical engine, I just don't know. I suspect it makes absolutely no difference but I still prefer the newer transform. Here is the altered model generation code:

//  Polar/Rectanglar Transformation Model
//
//  model_polar_transform(horiz, vert, inv)
//      horiz   number of knots along x-axis
//      vert    number of knots along y-axis
//      inv     perform inverse transform if true
//
//  returns id of model that transforms texture with
//      polar/rectangular UV warping
//
//  x = r*cos(theta)
//  y = r*sin(theta)
//
//  theta = arctan2(y,x)
//  r = sqrt(sqr(x)+sqr(y))
{
var model,i,j,x0,y0,y1,u0,v0,v1;
model = d3d_model_create();
for (j=0; j<argument1; j+=1)
{
y0 = j / argument1;
y1 = (j + 1) / argument1;
d3d_model_primitive_begin(model, pr_trianglestrip);
for (i=0; i<=argument0; i+=1)
{
x0 = i / argument0;
x1 = x0;

u0 = 0.5 * lengthdir_x(y0, 360 * x0 + 90) + 0.5;
u1 = 0.5 * lengthdir_x(y1, 360 * x1 + 90) + 0.5;
v0 = 0.5 * lengthdir_y(y0, 360 * x0 + 90) + 0.5;
v1 = 0.5 * lengthdir_y(y1, 360 * x1 + 90) + 0.5;

if (argument2) {
d3d_model_vertex_texture(model, u0, v0, 0, x0, y0);
d3d_model_vertex_texture(model, u1, v1, 0, x1, y1);
}else{
d3d_model_vertex_texture(model, x0, y0, 0, u0, v0);
d3d_model_vertex_texture(model, x1, y1, 0, u1, v1);
}
}
d3d_model_primitive_end(model);
}
return model;
}

The change is where u0, u1, v0, and v1 are calculated. By rotating the coordinates 90 degrees, I was able to remove the twist-like effect caused by the linear interpolation used by the animation code. Polar interpolation might have resulted in an even better illustration, but I think what I have now is probably clear enough.

EDIT:

After I posted this, I realized the following would work as well.

            u0 =  0.5 * lengthdir_y(y0, 360 * x0) + 0.5;
u1 =  0.5 * lengthdir_y(y1, 360 * x1) + 0.5;
v0 = -0.5 * lengthdir_x(y0, 360 * x0) + 0.5;
v1 = -0.5 * lengthdir_x(y1, 360 * x1) + 0.5;

Last edited by xot (2012-05-03 15:16:16)

Abusing forum power since 1986.

Offline

## #20 2013-05-31 15:58:12

xot
Registered: 2007-08-18
Posts: 1,077

### Re: NAILS prototype - raster-based light and shadow engine

Neat! Someone cited this topic for their own shadow system. They have implemented the concept using shaders, something I'd like to try when GM:Studio 1.2 finally comes out.