Discuss and collaborate on GML scripts

You are not logged in.

- Topics: Active | Unanswered

**BlueMoonProductions****Member**- Registered: 2010-08-25
- Posts: 22

Hey,

You've got only one script in your 3d Graphics section. A few month's ago I wrote some (5) scripts that could be used in 3D. 4 of them are nog 'graphics'-scripts, but I guess '3D graphics' means 3d-mode-related, and not the graphics.

I think some of the scripts are found before(especially d3d_point_distance , maybe d3d_draw_line), but some of the other, like d3d_instance_nearest/-furthest, I've never seen before.

Just some small scripts, but they could be useful. I allow you to place them on your site.

The original scripts can be found on the tutorials-board of the Dutch Gamemaker Community(NGMC): http://www.game-maker.nl/forums/topic,54774.0

These are the scripts(explanation translated from dutch to english):

**d3d_instance_nearest(x,y,z,obj)**

(NOTE: the 'obj' must have the variable 'z')

```
///BlueMoonProductions///
///d3d_instance_nearest(x,y,z,obj)///
///Returns the id of the nearest instance of obj in 3d space///
var nearest_distance, object_distance, nearestobj;
nearest_distance = 0;
nearestobj = noone;
with argument3 {
object_distance = sqr(x-argument0)+sqr(y-argument1)+sqr(z-argument2);
if object_distance<nearest_distance or nearestobj=noone {
nearest_distance = object_distance;
nearestobj = id;
}
}
return nearestobj;
```

**d3d_instance_furthest**

(almost equal)

```
///BlueMoonProductions///
///d3d_instance_furthest(x,y,z,obj)///
///Returns the id of the furthest instance of obj in 3d space///
var furthest_distance, object_distance, furthestobj;
furthest_distance = 0;
furthestobj = noone;
with argument3 {
object_distance = sqr(x-argument0)+sqr(y-argument1)+sqr(z-argument2);
if object_distance>furthest_distance or furthestobj=noone {
furthest_distance = object_distance;
furthestobj = id;
}
}
return furthestobj;
```

**d3d_point_distance(x1,y1,z1,x2,y2,z2)**

(very basic)

```
///BlueMoonProductions///
///d3d_point_distance(x1,y1,z1,x2,y2,z2)///
///Returns the distance between (x1,y1,z1) and (x2,y2,z2)///
return sqrt(sqr(argument0-argument3)+sqr(argument1-argument4)+sqr(argument2-argument5));
```

**d3d_draw_line**

Using primitives:

```
///BlueMoonProductions///
///d3d_draw_line(x1,y1,z1,x2,y2,z2)///
///Draws a 3D-line between (x1,y1,z1) and (x2,y2,z2)///
d3d_primitive_begin(pr_linelist)
d3d_vertex(argument0,argument1,argument2)
d3d_vertex(argument3,argument4,argument5)
d3d_primitive_end()
```

**point_zdirection**

Returns a zdirection, like pitch (normal direction = yaw)

```
///BlueMoonProductions///
///point_zdirection(x1,y1,z1,x2,y2,z2)///
///Returns the pitch between (x1,y1,z1) and (x2,y2,z2)///
return radtodeg(arctan2(argument5-argument2,point_distance(argument0,argument1,argument3,argument4)));
```

I´ve had some help from Matrebatre with the d3d_instance_nearest-script, maybe you should include his name as well? (and of course the _furthest script is based on d3d_instance_nearest)

Blue

Offline

**xot****Administrator**- Registered: 2007-08-18
- Posts: 1,240

Those are all very nice. It will be good to get some more scripts in that section. Thanks, Blue!

*Abusing forum power since 1986.*

Offline

**BlueMoonProductions****Member**- Registered: 2010-08-25
- Posts: 22

Thank you

I'm new here, if you are going to add them, when?

Offline

**paul23****Member**- Registered: 2007-10-17
- Posts: 110

(NOTE: the 'obj' must have the variable 'z')

Uhm isn't it usual to take "depth" as z-axis variable? (since it in 2d kind of is already)

Offline

**BlueMoonProductions****Member**- Registered: 2010-08-25
- Posts: 22

Yes, but I think it's still good to make that clear, because it's not a build-in. And some people only use zmin and zmax.

Offline

**xot****Administrator**- Registered: 2007-08-18
- Posts: 1,240

I don't think using "depth" for "z" is a good idea since it has special meaning to the Draw Event. It should only be used to control drawing order. If you are using "depth" for "z" and are looking "backwards" all of your objects will be drawn in the wrong order. The z-buffer can take care of that, but it's not always desirable to rely on it to fix out-of-order drawing (eg. painter's algorithm). For some tasks the z-buffer may not even be available, or you may want to draw objects in a specific order regardless of their spatial properties (eg. skyboxes, post-processing). If you are using the z-buffer, you may still want to draw things in front-to-back order because it improves drawing speed by reducing overdraw, or because your game requires it (eg. portal-based / BSP graphics engines).

*Abusing forum power since 1986.*

Offline

**BlueMoonProductions****Member**- Registered: 2010-08-25
- Posts: 22

Okay, and 'some other 3d scripts':

Maybe you know some people use lengthdir_y as lengthdir_z script. Well, that doesn't work when using it in combination with lengthdir_x and -y for the x and y coordinates.

That's because lengthdir_x and -y use the 'yaw'(: direction), and pitch is an important factor as well.

I hope this image explains what I mean:

**EDIT:** z-factor should be z-vector xD

(it's very hard for me to explain this because i'm Dutch )

As you can see, the length of the 3D-vector(Color: bordeaux, bold) is the same as the 2D-vector which only uses lengthdir_x and -_y. If you now use lengthdir_y as -_z, the 'position' of the end of the vector, will be at the end of the 2D vector (which uses _x and _y), and the z-position it should have.

I hope you understand what i'm trying to say, lengthdir_x and -_y aren't affected by the pitch. These lengthdir_x/-_y (and _z) scripts do this correctly:"

**lengthdir_x_3d**:

```
// lengthdir_x_3d(len,yaw,pitch)
// yaw = direction
return argument0*(cos(degtorad(argument1))*cos(degtorad(argument2)));
```

**lengthdir_y_3d**:

```
// lengthdir_y_3d(len,yaw,pitch)
// yaw = direction
return argument0*(-sin(degtorad(argument1))*cos(degtorad(argument2)));
```

**lengthdir_z_3d**:

```
// lengthdir_z_3d(len,pitch)
// pitch only!!
return argument0*(sin(degtorad(argument1)));
```

You should place the scripts together (not all 3 as seperate scripts), there **very** usefull.

Offline

**paul23****Member**- Registered: 2007-10-17
- Posts: 110

hmm not too sure these are the fastest methods: you could also use 2 times lengthdir_* which might be a lot faster?

ie the lengthdir_x_3d would then be:

`return lengthdir_x(lengthdir_x(argument0,argument2),argument1);`

for y:

`return lengthdir_y(lengthdir_x(argument0,argument2),argument1);`

and z:

`return lengthdir_y(argument0,argument1);`

This is from top of my head though, untested =/.

Offline

**xot****Administrator**- Registered: 2007-08-18
- Posts: 1,240

Yeah, something like that is almost certainly much faster.

Blue, when you say "place them together" you mean three scripts on one page and collecting them into a single *.gml file download, correct? The current system doesn't support that, but I plan to be able to do this sort of thing with the next version.

*Abusing forum power since 1986.*

Offline

**BlueMoonProductions****Member**- Registered: 2010-08-25
- Posts: 22

Hm, never thought about that..

Well, with 'place them together' I don't necessarily mean one page, but you should at least make clear that the scripts should be used together.

Offline

**brac37****Member**- Registered: 2010-02-12
- Posts: 18

paul23 wrote:

hmm not too sure these are the fastest methods: you could also use 2 times lengthdir_* which might be a lot faster?

ie the lengthdir_x_3d would then be:

`return lengthdir_x(lengthdir_x(argument0,argument2),argument1);`

for y:

`return lengthdir_y(lengthdir_x(argument0,argument2),argument1);`

and z:

`return lengthdir_y(argument0,argument1);`

This is from top of my head though, untested =/.

In the same manner and equally untested:

point_zdirection:

`return point_direction(0,argument5,point_distance(argument0,argument1,argument3,argument4),argument2);`

Offline

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

I think for zdirection, the point distance is the fastest If I remember right from a discussion on the gmc followed by the lenghtdir version, and the sin cos solution if alreay in radiants, then using the GML version of radian

(cos(argument1*180/pi)*cos(argument2*180/pi));

Finaly your original version.

You have to count how many GM functions you call, the less the better. And if you can skip a call, replace it with simple math, the better... For 3d point distance

return sqrt((argument0-argument3)*(argument0-argument3)+(argument1-argument4)*(argument1-argument4)+(argument2-argument5)*(argument2-argument5));

Offline

**xot****Administrator**- Registered: 2007-08-18
- Posts: 1,240

I'd normally agree with what you're saying, but you are replacing one function with two math operations. My benchmarks say that's false economy. I ran 10000 iterations of 100 pairs of preselected random coordinates.

**Expanded form:**`sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2))`

GM7: 10954 ms (100.0%)

GM8: 10203 ms (100.0%)

**Standard form:**`sqrt(sqr(x1-x2)+sqr(y1-y2)+sqr(z1-z2))`

GM7: 9500 ms (86.7%)

GM8: 8703 ms (85.3%)

**Super-Deluxe Cheater form:**`point_distance(x1,0,x2,point_distance(y1,z1,y2,z2))`

GM7: 7437 ms (67.9%)

GM8: 6797 ms (66.6%)

Standard form is about 17% faster than the expanded form. Cheater form is about 28% faster than the standard form. Interestingly, relative performance gains were greater with GM8 than with GM7. That may only be due to reduced overhead of for-loop operations.

*Abusing forum power since 1986.*

Offline

**paul23****Member**- Registered: 2007-10-17
- Posts: 110

This just shows how slow GM's interpreter is compared to what it could be >.>

Offline

**brac37****Member**- Registered: 2010-02-12
- Posts: 18

Obscurely, the point_distance formula requires an extra squaring, an extra subtraction and an extra square root, compared to standard. It should be faster, it seems that GM optimization is more crap than I thought. Furthermore, attempting to reduce larger arithmetic operations such as sqrt and / compared to + and * appears to be pointless in GM.

Offline

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

that is weird xot... I did benchmarking on gm7 a long time ago and (x1-x2) * (x1-x2) was faster than sqr (x1-x2) at least for me.

At least I'm not a liar when it comes to using the point_distance method... same method for zdirection...

Offline

**xot****Administrator**- Registered: 2007-08-18
- Posts: 1,240

Hmmm. I supposed it could vary based on processor. Linked below is my benchmark. Press spacebar to start the test, 10-30 seconds will pass, then a message box will appear with three values. They are the total test time elapsed in milliseconds for each version: expanded, standard, and cheater (in that order). Check the debugger messages to verify that the calculations produce the same results.

*Abusing forum power since 1986.*

Offline

**BlueMoonProductions****Member**- Registered: 2010-08-25
- Posts: 22

Okay.. My results:

4103 3385 2667

Offline

**xot****Administrator**- Registered: 2007-08-18
- Posts: 1,240

Damn, your computer is fast!

*Abusing forum power since 1986.*

Offline

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

I get similar result to you now. Though at the time I was using another PC. Now it's a m17 alienware laptop, the pother was a hp poc...

8346 6973 5974

Goes to show to never hold on to a truth for too long.

Offline