Rick Posted January 19, 2015 Share Posted January 19, 2015 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 1 Quote Link to comment Share on other sites More sharing options...
MarkusR Posted January 19, 2015 Share Posted January 19, 2015 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. Quote 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 More sharing options...
YouGroove Posted January 19, 2015 Share Posted January 19, 2015 Why not some raycast, if the ray collides with an other entity , just check the angle to see if it's inside the cone angle ? It's something i will do for some simple stupid robots AI. Quote Stop toying and make games Link to comment Share on other sites More sharing options...
AggrorJorn Posted January 19, 2015 Share Posted January 19, 2015 This is roughly what I do: Quote Link to comment Share on other sites More sharing options...
Ma-Shell Posted January 19, 2015 Share Posted January 19, 2015 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). Quote Link to comment Share on other sites More sharing options...
Rick Posted January 19, 2015 Author Share Posted January 19, 2015 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. Quote Link to comment Share on other sites More sharing options...
Ma-Shell Posted January 19, 2015 Share Posted January 19, 2015 I'm currently trying Posting results, if I get some... 1 Quote Link to comment Share on other sites More sharing options...
gamecreator Posted January 19, 2015 Share Posted January 19, 2015 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)); } Quote Link to comment Share on other sites More sharing options...
Ma-Shell Posted January 19, 2015 Share Posted January 19, 2015 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 1 Quote Link to comment Share on other sites More sharing options...
Rick Posted January 19, 2015 Author Share Posted January 19, 2015 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?) Quote Link to comment Share on other sites More sharing options...
Ma-Shell Posted January 19, 2015 Share Posted January 19, 2015 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 Quote Link to comment Share on other sites More sharing options...
Rick Posted January 19, 2015 Author Share Posted January 19, 2015 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. Quote Link to comment Share on other sites More sharing options...
Ma-Shell Posted January 19, 2015 Share Posted January 19, 2015 Well... "if(angle < angle)" Quote Link to comment Share on other sites More sharing options...
Rick Posted January 19, 2015 Author Share Posted January 19, 2015 lol the joys of refactoring. That did it! I'll add it to the wiki. Of course the model I'm using was exported 180 on the y axis so visually this model has to look like it's facing me, but that's an export issue. Will make an entry in the wiki. Quote Link to comment Share on other sites More sharing options...
Rick Posted January 19, 2015 Author Share Posted January 19, 2015 Added http://leadwerks.wikidot.com/wiki:vision-cone Thank you so very much Ma. If you have any sort of optimizations that you add you can change on the wiki or let me know here. 1 1 Quote Link to comment Share on other sites More sharing options...
Ma-Shell Posted January 19, 2015 Share Posted January 19, 2015 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. Quote Link to comment Share on other sites More sharing options...
Rick Posted January 19, 2015 Author Share Posted January 19, 2015 wiki has been edited for the changes you noted above. thanks Quote Link to comment Share on other sites More sharing options...
Guppy Posted January 20, 2015 Share Posted January 20, 2015 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 ) Quote 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 More sharing options...
Rick Posted January 20, 2015 Author Share Posted January 20, 2015 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. Quote Link to comment Share on other sites More sharing options...
Guppy Posted January 20, 2015 Share Posted January 20, 2015 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. Quote 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 More sharing options...
Rick Posted January 20, 2015 Author Share Posted January 20, 2015 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 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. Quote Link to comment Share on other sites More sharing options...
shadmar Posted January 20, 2015 Share Posted January 20, 2015 If you need the forward vector of the camera you can simply calculate it like this since it's stored in the rotmatrix. self.cameravector = Vec3(camera.mat.k.x,camera.mat.k.y,camera.mat.k.z):Normalize() Quote HP Omen - 16GB - i7 - Nvidia GTX 1060 6GB Link to comment Share on other sites More sharing options...
Rick Posted January 20, 2015 Author Share Posted January 20, 2015 So this works for ALL entities because this isn't for the camera but just any entity. Quote Link to comment Share on other sites More sharing options...
shadmar Posted January 20, 2015 Share Posted January 20, 2015 Yes. Quote HP Omen - 16GB - i7 - Nvidia GTX 1060 6GB Link to comment Share on other sites More sharing options...
Ma-Shell Posted January 20, 2015 Share Posted January 20, 2015 You are right. A matrix-multiplication with the vector (0,0,1,0)^T is just the third column. Doing it your way, we can get rid of the for-loops and the matrix-transposition. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.