Jump to content

Vision cone


Rick
 Share

Recommended Posts

Has anyone done a vision cone in LE before? Trying to see if another entity exists in front of an entity inside a cone area? Not interested in attaching a cone csg shape to all entities. If we can get this it would be perfect for the wiki. When looking online people are talking about dot products of forward vectors.

 

Is there a way to get a forward vector in LE?

 

 

 

Added the functions and explanation to the wiki.

 

http://leadwerks.wikidot.com/wiki:vision-cone

  • Upvote 1
Link to comment
Share on other sites

in front of local z axis, with Transform:Point

means vector 0,0,1 transformed with this function if front is z+

i see only Entity:SpherePick,PolygonPick,BoxPick

instead of cone maybe coarse in steps with World:ForEachEntityInAABBDo / World::ForEachVisibleEntityDo

i think some linepicks , Entity:Pick with radius is best. means left middle right, up middle down, 9 intersect tests.

PC : Win 10 Pro 64 Bit , 4x cores ~2 GHz , 8 GB RAM , AMD R7 265

2D : Photoline , Zooner Photo Studio 13 , Art Rage Studio 3.5.4 , Ashampoo Snap 7 , ...

3D : Shade 15 Basic , Carrara 8.5 & DAZ Studio 4.8 , Cheetah 3D 6.3.2 , Via Cad 8

Music : Samplitude Music Studio , Music Creator 7

IDE : Leadwerks Engine 3.x , Unity 5.x , (Unreal 4.8.x) , AGK v2.x , Construct 2 , (Clickteam Fusion 2.5) , ShiVa 1.9 , Game Maker Studio , MS Visual Studio .Net , Android Studio , Monkey , ...

Link to comment
Share on other sites

For the following let's call the "looking" object "A".

You would have to perform checks for every other entity ("B"), whether the angle between the forward-vector of A and the vector from A to B is smaller than a certain threshold. You can get the angle between two vectors by the following:

 

With "<a,b>" being the dot product of the vectors a and b,

"c" being the angle between a and b,

|a| being the length of vector a, the following holds:

<a,b> = |a|*|b|*cos( c )

thus:

c = acos(<a,b>/|a|*|b|)

That's how you can get the angle between two vectors.

 

Now there are two things left:

- The vector from A to B is simply B.getPosition() - A.getPosition()

- The forward-vector of A. I have to admit, I am not really sure, how to get this one. I would assume, you can get it by transforming the vector (0,0,1) with the transformation matrix of A (i.e. multiplying them).

Link to comment
Share on other sites

Ma-Shell have you translated that to LE by chance? This is off the forward vector, like all examples I find online, but not sure in LE how to get the forward vector.

 

Some of these other examples are OK, but I'm just looking for a non picking method. My approach was to get entities in an AABB (this determines the length to look at) and then looking through those entities to see if they are in the cone.

Link to comment
Share on other sites

I have but I don't know dot products and vector math. I simply attached two hidden dummy entities to an enemy at outside triangle positions. Then I got their positions every frame. Then I just checked to see if hero's position is in the triangle formed by enemy's position and two dummy positions.

 

float sign(float p1x, float p1y, float p2x, float p2y, float p3x, float p3y)
{
  return (p1x - p3x) * (p2y - p3y) - (p2x - p3x) * (p1y - p3y);
}

bool PointInTriangle(float px, float py, float p1x, float p1y, float p2x, float p2y, float p3x, float p3y)
{
  bool b1, b2, b3;

  b1 = sign(px, py, p1x, p1y, p2x, p2y) < 0.0f;
  b2 = sign(px, py, p2x, p2y, p3x, p3y) < 0.0f;
  b3 = sign(px, py, p3x, p3y, p1x, p1y) < 0.0f;

  return ((b1 == b2) && (b2 == b3));
}

Link to comment
Share on other sites

It principally works. There is only one thing: I don't know how to iterate over all entities in LUA, so I only tested against one entity, which I assigned via the editor (self.ent).

Here is the code:

 

local forward_vec4 = Vec4(0,0,1,0)
local mat = self.entity:GetMatrix():Transpose()
--transform
ret = Vec4(0)
--System:Print(forward_vec[0] .. "," .. forward_vec[1] .. "," .. forward_vec[2] .. "," .. forward_vec[3])
for i = 0,3,1 do
 ret[i] = 0
 for j = 0,3,1 do
  ret[i] = ret[i] + mat[i][j] * forward_vec4[j]
 end
end
forward_vec4 = ret
--The following should actually be done for all entities, not just self.ent
local diff_vec = self.ent:GetPosition() - self.entity:GetPosition()
local forward_vec = forward_vec4:xyz()
--calculate angle
local dot = diff_vec:Dot(forward_vec)
local l1 = math.sqrt(diff_vec:Dot(diff_vec))
local l2 = math.sqrt(forward_vec:Dot(forward_vec))
local angle = Math:ACos(dot / (l1*l2))
if(angle < 35) then
 -- in cone
 self.ent:Show()
else
 -- not in cone
 self.ent:Hide()
end

 

I might eventually polish it some time and put it on the workshop, when I find out, how to iterate over all entities ;)

  • Upvote 1
Link to comment
Share on other sites

Not a problem as using 1 entity is all that's really needed in my mind. Looping over entities can be done in various different methods so that's not really the issue at hand and this can be applied to whatever looping method we pick. Thanks for this. Will check it out. That seems crazy that this is what it takes to get a forward vector.

 

I assume this is a universal angle (for width as well as height where 35 is the angle value?)

Link to comment
Share on other sites

That seems crazy that this is what it takes to get a forward vector.

Well, acutally the part that's responsible for getting the forward-vector is just a matrix multiplication with a vector. I was a bit surprised that LE didn't offer a way to do that but well... I can run through loops myself ;)

 

I assume this is a universal angle (for width as well as height where 35 is the angle value?)

You are right. This is a 35 degree universal angle

Link to comment
Share on other sites

So trying to refine this and take advantage of the existing GetEntityNeighbors.lua file. I must have screwed something up as the "Inside cone" isn't displaying. Still looking at it but thought I'd post it here for anyone else to take a look.

 

function GetForwardVector(entity)
local forward_vec4 = Vec4(0,0,1,0)
local mat = entity:GetMatrix():Transpose()

--transform
local ret = Vec4(0)

for i = 0,3,1 do
ret[i] = 0
for j = 0,3,1 do
ret[i] = ret[i] + mat[i][j] * forward_vec4[j]
end
end

forward_vec4 = ret

return forward_vec4
end

function GetEntityNeighborsViewCone(entity, raduis, scriptOnly, angle)
local entities = GetEntityNeighbors(entity, raduis, scriptOnly)
local e = {}
local k, v
local forward_vec4 = GetForwardVector(entity)

for k, v in pairs(entities) do
--The following should actually be done for all entities, not just self.ent
local diff_vec = v:GetPosition() - entity:GetPosition()
local forward_vec = forward_vec4:xyz()

--calculate angle
local dot = diff_vec:Dot(forward_vec)
local l1 = math.sqrt(diff_vec:Dot(diff_vec))
local l2 = math.sqrt(forward_vec:Dot(forward_vec))
local angle = Math:ACos(dot / (l1*l2))

local name = v:GetKeyValue("name")
System:Print("GetEntityNeighbors = "..name)

if(angle < angle) then
-- in cone
System:Print("Inside cone")
table.insert(e, v)
end
end

return e
end

 

The player is in the AABB and it's name is displayed so I know it's looping over it.

Link to comment
Share on other sites

You're welcome. Nice to know, I could help.

Just two minor things:

- At the end of GetForwardVector, you can just return ret without assigning it to forward_vec first (I did this originally because I first had it in a separate function but then I noticed, I wasn't really familiar with some LUA-specific function-things (like e.g. when the first parameter is interpreted as self etc.). So I just took the whole chunk and decided to not put it in a separate function.)

- The comment "--The following should actually be done for all entities, not just self.ent" doesn't hold any more.

Link to comment
Share on other sites

Nice function, a little critique

 

wrt the main function "GetEntityNeighborsViewCone(entity, raduis, scriptOnly, angle)"

 

assuming that "angle" is the apex angle ( it the angle of the pointy bit of the cone ) and that "raduis" is not the radius of the cone but rather the radius of the circle of interest (ie the height of the cone)

 

Might I suggest that it be changed to

 

"GetEntityNeighborsViewCone(entity, angle, height, scriptOnly)"

 

To keep the optional parameter at the end where it belongs and also keep the cone definition together.

 

 

For "WorldGetEntitiesInAABBDoCallback"

a cleaner solution would be to pass the global parameters as a table ( tables in lua are passed by reference always so changes to it will be reflected in the variable of the calling function ) using the "extra" field like so

 

local extraParameters={
 table={},
 entity=entity,
 scriptOnly=scriptOnly
}

 

It just removes an error source in case you start using it for both players and mobs ( concurrency, interrupts, etc )

System:

Linux Mint 17 ( = Ubuntu 14.04 with cinnamon desktop ) Ubuntu 14.04, AMD HD 6850, i5 2500k

Link to comment
Share on other sites

This function is a simple modification of the original Josh has already with the engine. The radius is actually the bounding box check done around the entity to get entities that lie within it to check and see if they are inside the vision cone. For this particular function you can think of it as the distance to check for the cone. I made the parameters to match the existing function and I just extended it by the 1 parameter which is why I put it at the end, and those 2 params aren't related so they don't need to stay together.

 

When you make the call to GetEntityNeighborsViewCone() everything is done right then and there. Using it for players or mobs won't make a difference as the function is ran in 1 cycle. If you wish to make a version that is does what it does over multiple cycles (threaded) then you are free to do so in the wiki. For me, this does what I need it to do and I'm not really building a library on the wiki so I'm not all that concerned with it atm. You should be able to call this on the player and any number of mobs and it should still work. Are you thinking the callback is done over multiple cycles? The callback is fired as many times as there are entities right when we call ForEachENtityInAABBDo(). That is ForEachEntityInAABBDo() won't come back until the callback has been fired for every entity in the bounding box.

Link to comment
Share on other sites

I realize that the radius is used for the bounding box, but given that it also limits the height/length of the cone. The function is named "GetEntityNeighborsViewCone" not "GetEntityNeighborsPieSlice" so I just figured giving it parameters describing the cone would make sence ;)

Optional parameters goes last as otherwise you cannot skip them ( tho maybe you can with lua )

 

My comment about concurrency does not imply having to rewrite it threadded, but rather than you can safe guard against changing circumstances such as for instance physics becoming multithreaded ( in that case if you checked the vision cone from a collision trigger the results would be unpredictable )

 

At any rate I did not mean to offend, you did how ever ask for optimizations - which I took to mean general feed back.

System:

Linux Mint 17 ( = Ubuntu 14.04 with cinnamon desktop ) Ubuntu 14.04, AMD HD 6850, i5 2500k

Link to comment
Share on other sites

At any rate I did not mean to offend

 

 

 

No offense was taken. I was simply showing you my laziness and content with how it already was wink.png But this is why I made the wiki. I am by no means the gatekeeper of the wiki and I encourage people to get in there and share some code. I welcome you to make a page and add a link to it in the page I made as an alternative approach.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...