SRL Archive - SRL Snippets

3D engine


zmon

2012-05-25 17:38:54

not sure if anyone cares for low angle, which is the one that i'm currently testing but this is from my libraries that i'm getting ready for a project of sorts

the numbers in constants are not yet exact and i'll update them and add high angle as well when i have tuned it exactly


relevant code:

ShowcaseMiniMap - just to see it in action.

CHANGE - minimap projection is now ordered (X, Y, Elevation); rather than (X, Y, Z) because Y on minimap is Z in 3d and could have been very confusing.


{$include_once SRL/SRL/core/globals.simba}
{$include_once SRL/SRL/misc/paintsmart.simba}

// general constants
const DDD_ANGLE_LOW = 0.0;
const DDD_ANGLE_HIGH = 1.0;

// used by Y transform
const DDD_LOW_ANGLE_SQUARE = 16; // explicit value
const DDD_CAMERA_CHAMBER_DEPTH = 2; // explicit value
const DDD_TRANSFORM_DEPTH = 1; // explicit value
// distance of camera, every grid square is 4x4 on minimap so multiply by 4
const DDD_LOW_CAMERA_Z = 28; // can be obtained from getcamerapos
const DDD_HIGH_CAMERA_Z = 24; // can be obtained from getcamerapos
// center of the screen is somewhere above ground - this is explicit value
const DDD_LOW_FLOOR_OFFSET = 1.5625; // explicit 200/128
const DDD_HIGH_FLOOR_OFFSET = 2.34375; // explicit 300/128
// can be obtained from getcamerapos - height/128 but subtract floor offset
const DDD_LOW_CAMERA_Y = 13.9609375 - DDD_LOW_FLOOR_OFFSET;
const DDD_HIGH_CAMERA_Y = 46.71875 - DDD_HIGH_FLOOR_OFFSET;

// calculated values for current projection
var DDD_MAP_SQUARE_DIMENSION : Extended;
var DDD_CAMERA_Z : Extended;
var DDD_CAMERA_Y : Extended;
var DDD_FLOOR_OFFSET : Extended;
var DDD_ANGLE_TRANSFORM : Extended;
var DDD_ZERO_CAMERA_DISTANCE : Extended;

procedure InitializeAngle(Angle: Extended);
var LowCameraDistance : Extended;
begin
// assume linear - pretty good approximation
DDD_CAMERA_Z := DDD_LOW_CAMERA_Z + Angle * (DDD_HIGH_CAMERA_Z - DDD_LOW_CAMERA_Z);
DDD_CAMERA_Y := DDD_LOW_CAMERA_Y + Angle * (DDD_HIGH_CAMERA_Y - DDD_LOW_CAMERA_Y);
DDD_FLOOR_OFFSET := DDD_LOW_FLOOR_OFFSET + Angle * (DDD_HIGH_FLOOR_OFFSET - DDD_LOW_FLOOR_OFFSET);
// get low angle distance
LowCameraDistance := Sqrt(Sqr(DDD_LOW_CAMERA_Z) + Sqr(DDD_LOW_CAMERA_Y));
DDD_ZERO_CAMERA_DISTANCE := Sqrt(Sqr(DDD_CAMERA_Z) + Sqr(DDD_CAMERA_Y));
DDD_MAP_SQUARE_DIMENSION := DDD_LOW_ANGLE_SQUARE *
(LowCameraDistance + DDD_TRANSFORM_DEPTH + DDD_CAMERA_CHAMBER_DEPTH) /
(DDD_ZERO_CAMERA_DISTANCE + DDD_TRANSFORM_DEPTH + DDD_CAMERA_CHAMBER_DEPTH);
DDD_ANGLE_TRANSFORM := ArcCos(DDD_CAMERA_Z / DDD_ZERO_CAMERA_DISTANCE);
end;

// based on minimap offsets
function GetPerspectivePointExactMM(X,Y,Z : Extended) : TPoint;
var CAMERA_Z_DISTANCE : Extended;
var CAMERA_Y_DISTANCE : Extended;
var CAMERA_Z_DISTANCE2 : Extended;
var CAMERA_Y_DISTANCE2 : Extended;
var CAMERA_X_DISTANCE2 : Extended;
var CAMERA_XZ_DISTANCE2 : Extended;
var CAMERA_YZ_DISTANCE2 : Extended;
var CAMERA_XZ_DISTANCE : Extended;
var CAMERA_YZ_DISTANCE : Extended;
var IntegralX : Extended;
var IntegralY : Extended;
var ModZ : Extended;
begin
Result.X := MSCX;
Result.Y := MSCY;
CAMERA_Z_DISTANCE := DDD_CAMERA_Z - Z;
CAMERA_Y_DISTANCE := Y;
if (CAMERA_Z_DISTANCE < 1) then Exit;

CAMERA_Z_DISTANCE2 := Sqr(CAMERA_Z_DISTANCE);
CAMERA_Y_DISTANCE2 := Sqr(CAMERA_Y_DISTANCE);
CAMERA_X_DISTANCE2 := Sqr(X);
CAMERA_XZ_DISTANCE2 := CAMERA_X_DISTANCE2 + CAMERA_Z_DISTANCE2;
CAMERA_YZ_DISTANCE2 := CAMERA_Y_DISTANCE2 + CAMERA_Z_DISTANCE2;
CAMERA_XZ_DISTANCE := Sqrt(CAMERA_XZ_DISTANCE2);
CAMERA_YZ_DISTANCE := Sqrt(CAMERA_YZ_DISTANCE2);
// calculate shift
IntegralX := CAMERA_YZ_DISTANCE * ArcSinh(X / CAMERA_YZ_DISTANCE);
IntegralY := CAMERA_XZ_DISTANCE * ArcSinh(Y / CAMERA_XZ_DISTANCE);
// this one is the simple one
ModZ := (DDD_ZERO_CAMERA_DISTANCE + DDD_CAMERA_CHAMBER_DEPTH) /
(CAMERA_Z_DISTANCE + DDD_CAMERA_CHAMBER_DEPTH);
Result.X := MSCX + Round(DDD_MAP_SQUARE_DIMENSION * IntegralX * ModZ);
Result.Y := MSCY - Round(DDD_MAP_SQUARE_DIMENSION * IntegralY * ModZ);
end;

function GetPerspectivePoint(X,Y,Z : Extended) : TPoint;
var Y1, Z1 : Extended;
var PLAYERSHIFTEDY : Extended;
var DistanceZ : Extended;
var DistanceYZ : Extended;
var POINTEXACT : TPoint;
var ANGLE : Extended;
begin
// make runescape transform
DistanceZ := DDD_CAMERA_Z - Z;
PLAYERSHIFTEDY := (Y - DDD_FLOOR_OFFSET);
DistanceYZ := Sqrt(Sqr(DDD_CAMERA_Y - PLAYERSHIFTEDY) + Sqr(DistanceZ));
ANGLE := ArcCos(DistanceZ / DistanceYZ);
Y1 := Sin(DDD_ANGLE_TRANSFORM - ANGLE) * DistanceYZ;
Z1 := DDD_CAMERA_Z - Cos(DDD_ANGLE_TRANSFORM - ANGLE) * DistanceYZ;
POINTEXACT := GetPerspectivePointExactMM(X,Y1,Z1);
Result.x := POINTEXACT.x;
Result.y := POINTEXACT.y;
end;

function GetPerspectivePointMM(X, Y, Elevation : Extended) : TPoint;
var PPoint : TPoint;
begin
// use straight transform
PPoint := GetPerspectivePoint(X, Elevation, Y);
Result.x := PPoint.x;
Result.y := PPoint.y;
end;

procedure ProjectMiniMap(Angle : Extended);
var mmy, mmx : integer;
var mmp : TPoint;
var mmc : integer;
var UP : Integer;
begin
InitializeAngle(Angle);
MMP := GetPerspectivePointMM(0, DDD_FLOOR_OFFSET, 0);
SMART_DrawBoxEx(false, inttobox(mscx-3, mscy-3, mscx+3, mscy+3), clGreen);
for mmy := -80 to 20 do
begin
for mmx := -30 to 30 do
begin
mmc := GetColor(MMCX + mmx, MMCY + mmy);
if SimilarColors(mmc, clWhite, 14) or SimilarColors(mmc, $0008E8, 30) or SimilarColors(mmc, $ECECEC, 30)
or SimilarColors(mmc, clYellow, 30) then
begin
//if SimilarColors(mmc, clWhite, 14) or SimilarColors(mmc, $ECECEC, 20) then
for UP := 0 to 16 do
begin
mmp := GetPerspectivePointMM(mmx, mmy, UP/2.0);
SMART_DrawBoxEx(false, IntToBox(mmp.x -2, mmp.y - 2, mmp.x + 2, mmp.y + 2), mmc);
end;
end;
end;
end;
end;

procedure ShowcaseMiniMap();
begin
while true do
begin
sleep(2000);
SMART_ClearCanvas();
if (RandomE > 0.5) then
begin
ProjectMiniMap(1);
SetAngle(SRL_ANGLE_HIGH);
end
else
begin
ProjectMiniMap(0);
SetAngle(SRL_ANGLE_LOW);
end;
end;
end;

YoHoJo

2012-05-25 17:45:24

WHOA! That is pretty damn ballin!
We can find objects/npcs/items etc though the MM basically using that, or at least get a good guess on where they are!

That is really cool!

Home

2012-05-25 17:51:31

Looks awsome mate!

~Home

YoHoJo

2012-05-25 17:53:08

You should def add high angle.
There can probably be a lot of neat uses for this!!!
Like fighters and seeing NPC dot on MM and then waking over to them, or picking up items and stuff. NEATO!

zmon

2012-05-25 18:01:29

From: YoHoJo
You should def add high angle.
There can probably be a lot of neat uses for this!!!
Like fighters and seeing NPC dot on MM and then waking over to them, or picking up items and stuff. NEATO!


i have rough numbers in the other script (albeit based off 8x8 not 1x1 transform) but yes i will fine tune both high and low angle, point being that in certain situations (such as looking for resources in dung or trying to figure out what boss is on other side) you do need low angle.

ideally i will have ways of detecting angle in places such as dung and return angle 0-1 (0 being low) so we can get away from only low/high angle approach, but clearly i need pretty well defined walls to be able to guess the angle :P

xtrapsp

2012-05-25 18:07:42

This is just wow o.o

momotron

2012-05-25 18:08:02

Hey mate, great work here, i must say. I'm not going to pretend that I understood much from trying to read your code, but it's nice.

Kyle Undefined

2012-05-25 18:09:43

Wow, this is brilliant! Great work!

818181

2012-05-25 18:20:06

From: zmon
not sure if anyone cares for low angle, which is the one that i'm currently testing but this is from my libraries that i'm getting ready for a project of sorts

the numbers in constants are not yet exact and i'll update them and add high angle as well when i have tuned it exactly


relevant code:

{$include_once SRL/SRL/core/globals.simba}
{$include_once SRL/SRL/misc/paintsmart.simba}

const PERSPECTIVE_MM_MAP_SQUARE = 21;
const PERSPECTIVE_MM_CAMERA_Y = 10.25;
const PERSPECTIVE_MM_CAMERA_Z = 20;
const PERSPECTIVE_MM_DEPTH_Z = 5.5;
const RUNESCAPE_MM_PLAYER_HALF_HEIGHT = 4.0;

var RUNESCAPE_MM_ANGLE_HIGH_TRANSFORM : Extended;
procedure CalculateTransformAngleMM;
begin
RUNESCAPE_MM_ANGLE_HIGH_TRANSFORM := ArcCos(PERSPECTIVE_MM_CAMERA_Z /
Sqrt(Sqr(PERSPECTIVE_MM_CAMERA_Y) + Sqr(PERSPECTIVE_MM_CAMERA_Z)));
end;

// based on minimap offsets
function GetPerspectivePointExactMM(X,Y,Z : Extended) : TPoint;
var CAMERA_Z_DISTANCE : Extended;
var CAMERA_Y_DISTANCE : Extended;
var CAMERA_Z_DISTANCE2 : Extended;
var CAMERA_Y_DISTANCE2 : Extended;
var CAMERA_X_DISTANCE2 : Extended;
var CAMERA_XZ_DISTANCE2 : Extended;
var CAMERA_YZ_DISTANCE2 : Extended;
var CAMERA_XZ_DISTANCE : Extended;
var CAMERA_YZ_DISTANCE : Extended;
var IntegralX : Extended;
var IntegralY : Extended;
var ModZ : Extended;
begin
Result.X := MSCX;
Result.Y := MSCY;
CAMERA_Z_DISTANCE := PERSPECTIVE_MM_CAMERA_Z - Z;
CAMERA_Y_DISTANCE := Y;
if (CAMERA_Z_DISTANCE < 1) then Exit;

CAMERA_Z_DISTANCE2 := Sqr(CAMERA_Z_DISTANCE);
CAMERA_Y_DISTANCE2 := Sqr(CAMERA_Y_DISTANCE);
CAMERA_X_DISTANCE2 := Sqr(X);
CAMERA_XZ_DISTANCE2 := CAMERA_X_DISTANCE2 + CAMERA_Z_DISTANCE2;
CAMERA_YZ_DISTANCE2 := CAMERA_Y_DISTANCE2 + CAMERA_Z_DISTANCE2;
CAMERA_XZ_DISTANCE := Sqrt(CAMERA_XZ_DISTANCE2);
CAMERA_YZ_DISTANCE := Sqrt(CAMERA_YZ_DISTANCE2);

// THIS would be ideal but somehow we don't have asinh?
//IntegralX := CAMERA_YZ_DISTANCE * asinh(X / CAMERA_YZ_DISTANCE);
//IntegralY := CAMERA_XZ_DISTANCE * asinh(Y / CAMERA_XZ_DISTANCE);

// do not fret, asinh(x) = ln(x + sqrt(sqr(x) + 1))
IntegralX := CAMERA_YZ_DISTANCE * ln((X + sqrt(CAMERA_X_DISTANCE2 + CAMERA_YZ_DISTANCE2))/CAMERA_YZ_DISTANCE);
IntegralY := CAMERA_XZ_DISTANCE * ln((Y + sqrt(CAMERA_Y_DISTANCE2 + CAMERA_XZ_DISTANCE2))/CAMERA_XZ_DISTANCE);
// this one is the simple one
ModZ := PERSPECTIVE_MM_CAMERA_Z * CAMERA_YZ_DISTANCE / CAMERA_Z_DISTANCE2;
Result.X := MSCX + Round(PERSPECTIVE_MM_MAP_SQUARE * IntegralX * ModZ);
Result.Y := MSCY - Round(PERSPECTIVE_MM_MAP_SQUARE * IntegralY * ModZ);
end;

function GetPerspectivePointMM(X,Y,Z : Extended) : TPoint;
var Y1, Z1 : Extended;
var PLAYERSHIFTEDY : Extended;
var DistanceZ : Extended;
var DistanceYZ : Extended;
var POINTEXACT : TPoint;
var ANGLE : Extended;
begin
// make runescape transform
DistanceZ := PERSPECTIVE_MM_CAMERA_Z - Z + PERSPECTIVE_MM_DEPTH_Z;
PLAYERSHIFTEDY := Y - RUNESCAPE_MM_PLAYER_HALF_HEIGHT;
DistanceYZ := Sqrt(Sqr(PERSPECTIVE_MM_CAMERA_Y - PLAYERSHIFTEDY) + Sqr(DistanceZ));
ANGLE := ArcCos(DistanceZ / DistanceYZ);
Y1 := Sin(RUNESCAPE_MM_ANGLE_HIGH_TRANSFORM - ANGLE) * DistanceYZ;
Z1 := PERSPECTIVE_MM_CAMERA_Z - Cos(RUNESCAPE_MM_ANGLE_HIGH_TRANSFORM - ANGLE) * DistanceYZ;
POINTEXACT := GetPerspectivePointExactMM(X,Y1,Z1);
Result.x := POINTEXACT.x;
Result.y := POINTEXACT.y;
end;

procedure ProjectMiniMap();
var mmy, mmx : integer;
var mmp : TPoint;
var mmc : integer;
var UP : Integer;
begin
CalculateTransformAngleMM();
MMP := GetPerspectivePointMM(0, 0, 0);
SMART_DrawBoxEx(false, inttobox(mscx-3, mscy-3, mscx+3, mscy+3), clGreen);
for mmy := -50 to 20 do
begin
for mmx := -30 to 30 do
begin
mmp := GetPerspectivePointMM(mmx, 0, mmy);
mmc := GetColor(MMCX + mmx, MMCY + mmy);
SMART_DrawBoxEx(false, IntToBox(mmp.x -2, mmp.y - 2, mmp.x + 2, mmp.y + 2), mmc);
if SimilarColors(mmc, clWhite, 14) or SimilarColors(mmc, $0008E8, 30) or SimilarColors(mmc, $ECECEC, 20)
or SimilarColors(mmc, clYellow, 30) then
begin
for UP := 1 to 15 do
begin
mmp := GetPerspectivePointMM(mmx, UP/2.0, mmy);
SMART_DrawBoxEx(false, IntToBox(mmp.x -2, mmp.y - 2, mmp.x + 2, mmp.y + 2), mmc);
end;
end;
end;
end;


holy crap man…
these codes even hurt my brain …

HOW THE fuzz DO YOU GUYS DO THIS…

epic man ;)

i hope we can see the next Idung ;p;p

YoHoJo

2012-05-25 18:25:05

^ Edited your post, don't cuss.

repahu

2012-05-25 20:43:48

Wow, great job. I have some experience in opengl basics and i also tried to figure out the transformation matrices, camera offset and perspective of rs, i have not finished it yet. I hope something like this will be embedded in the srl core soon.

zmon

2012-05-25 21:16:08

just realized couple of problems :P

the total distance is what makes z axis multiplier modification not just distance in z and y axis (i blame it on my original drawings and lack of common sense :garfield: ) and

the depth of camera is not only in z axis, because i am projecting onto a screen which is flat so when i project in center it is z axis but towards the edges it is augmented by overall distance including x and y coords (current depth calculation projects onto a sphere around camera which is not correct and will make edges of screen slightly distorted)

i don't know how much time i'll get to work on it in next few days, big release at work but i'll post the code with modifications when i have it, and i will include the init based on angle of camera

Sin

2012-05-25 21:43:03

This looks absolutely brilliant!

anonymity

2012-05-25 22:48:15

This is phenomenal.

I Am Legend

2012-05-26 00:50:59

make this dude a member already ;P

bg5

2012-05-26 01:05:21

Awesome math !

From: zmon
// THIS would be ideal but somehow we don't have asinh?


ArcSinh ? :P

btw.
From: Yohoyo
You should def add high angle.
There can probably be a lot of neat uses for this!!!
Like fighters and seeing NPC dot on MM and then waking over to them, or picking up items and stuff


You can already do it using SRL function.

zmon

2012-05-26 02:12:42

ok i have fixed the spherical projection, which actually ended up simplifying the math a tad bit (not very much but should make it a hair faster)

i have edited the post and now there are two option for low and high (low is commented out but working as well)

also some of the parameters were not normalized and so i have modified a few things and did a floor adjustment.

so every point in runescape map has X, and Y (edit: x offset from mmcx, and y is offset from mmcy, center of minimap is 0,0)

but i am projecting map with Y=0 for floor, so you need to calculate the call with (X, 0, Y) to get floor projection - and as you can see at the bottom, the wall is about 8 points high (the loop goes to 15 but i didvide by 2 so i get (x,0,y) through about (x,8,y) when doing vertical column of colors

Edit: i have a feeling that size of projected minimap pixel (PERSPECTIVE_MM_MAP_SQUARE) is a function of pixel size and distance of zero point from camera and so it should really be calculated from constant and camera position…

and this is what it looks like now without the spherical mess:


J J

2012-05-26 05:43:05

Looks extremely amazing! Keep it up!

litoris

2012-05-26 06:23:09

Seems promising!
From: YoHoJo
(…)Like fighters and seeing NPC dot on MM and then waking over to them,(…)


Narcle already does that in his fighter.

mormonman

2012-05-26 06:39:56

From: litoris
Seems promising!


Narcle already does that in his fighter.


Lots of people already do that.

zmon

2012-05-26 12:06:48

yes i have seen few different mm to ms projections, but those that i have seen all lack perspective adjustment, which at high angle isn't as critical, but with low angle it is absolutely crucial to have perspective correct

but here is something to think about - imagine that i take block of wall and reverse adjust the projection (that might need GDI+, if the support functions aren't readily available, because this could really use some hardware assist) - then i would get an actual flat 2d image of wall surface, i could find resources such as, for example, bovistrangler tree, then project back onto wall to get exact location - no more guessing and adjusting for deformed angles :)

so then i could keep track of all resources in every room


another example that might resonate with more people: undeform molly random - get a nice head on picture and compare with nice head on pictures of possible sister targets… i know that this one in particular may be of some interest…

Sin

2012-05-26 12:12:39

Zmon, this is absolutely amazing.
Im aware that you have a life outside of computers (Whats a life btw?) and are busy, but if you have a Skype/MSN, i'd be more than happy to learn from you :)

Sir Ducksworthy

2012-05-26 18:33:23

Your right about the molly random it's exactly what I've been dwelling on.

NotReligious

2012-05-31 04:57:26

Wow.. your coding abilities are pretty much genius level. Amazing work.


PS. Make this guy a member. Now.

sm321

2012-05-31 05:07:21

This looks good :) It seems that a few people are edging towards the DirectX/OpenGL side of things.

NCDS

2012-05-31 09:33:49

Everything looks great so far with this!

From: zmon

another example that might resonate with more people: undeform molly random - get a nice head on picture and compare with nice head on pictures of possible sister targets… i know that this one in particular may be of some interest…

I would like to elaborate on this a little bit; The main problem with molly (last time I attempted to solve a few months back) is compensating for the "low angle perspective" when working the "claw" to pickup the evil twin.

May as well consider it solved if you get accurate finding from a 'low perspective' (to an exact rs tile).

Sir R. M8gic1an

2012-05-31 09:51:21

Very Impressive Indeed.

~RM

Flight

2012-05-31 11:02:50

You're doing an amazing job here, zmon. It sounds like you have quite a bit of knowledge from what I've and to see it first-hand in such examples is just writing it in stone; you have potential here to do lots of good.

Believe me when I say I'm really truly looking forward to seeing more from you, I will keep my eyes open. :)

[XoL]

2012-05-31 12:40:56

I want to be like you when I grow up, inspired.