function test:dotproduct(v1, v2)
if v1 and v2 then
return ((v1.x * v2.x) + (v1.y * v2.y) + (v1.z + v2.z))
else return nil
end
end
local vNormalizedVel = vector.normalize(self.object:getvelocity())
local pEntityPos = self.object:getpos()
local distance = 3
local minp = {x = self.vAgentPos.x - distance, y = self.vAgentPos.y - 3.5, z = self.vAgentPos.z - distance}
local maxp = {x = self.vAgentPos.x + distance, y = self.vAgentPos.y + 1.5, z = self.vAgentPos.z + distance}
local nodes = minetest.find_nodes_in_area(minp, maxp, {"group:water"})
if #nodes > 0 then
for _,node in ipairs(nodes) do
local pTargetPos = node:getpos()
local vTargetPos = vector.normalize(vector.subtract(pTargetPos,pEntityPos))
local iProjection = test:dotproduct(vTargetPos,vNormalizedVel)
if iProjection > 0 then
print("node = "..minetest.pos_to_string(node))
end
end
end
local function yaw2vec(yaw)
return { x = math.cos(yaw), z = math.sin(yaw), y = 0 }
end
local function dotproduct(v1, v2)
if v1 and v2 then
return ((v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z))
else
return nil
end
end
local function angle(v1, v2)
if v1 and v2 then
return math.acos(dotproduct(v1, v2) / (vector.length(v1) * vector.length(v2)))
end
end
TeTpaAka wrote:You need to convert the yaw to a vector and determine the vector between the two positions. If you got that, you need to measure the angle between the two vectors:
- Code: Select all
local function yaw2vec(yaw)
return { x = math.cos(yaw), z = math.sin(yaw), y = 0 }
end
TeTpaAka wrote:
- Code: Select all
return math.acos(dotproduct(v1, v2) / (vector.length(v1) * vector.length(v2)))
lag01 wrote:TeTpaAka wrote:You need to convert the yaw to a vector and determine the vector between the two positions. If you got that, you need to measure the angle between the two vectors:
- Code: Select all
local function yaw2vec(yaw)
return { x = math.cos(yaw), z = math.sin(yaw), y = 0 }
end
Oh, it was that easy? Thanks!
lag01 wrote:TeTpaAka wrote:
- Code: Select all
return math.acos(dotproduct(v1, v2) / (vector.length(v1) * vector.length(v2)))
Please make sure to not divide by zero here, or it will produce random game hangs.
local function yaw2vec(yaw, pitch)
pitch = pitch or 0
return { x = math.cos(yaw) * math.cos(pitch), z = math.sin(yaw) * math.cos(pitch), y = math.sin(pitch) }
end
BrandonReese wrote:I did FOV in my version of simple mobs for Adventuretest.
https://github.com/Bremaweb/adventurete ... i.lua#L148
This is where I found the formulas, very helpful reference.
http://blog.wolfire.com/2009/07/linear- ... rs-part-2/
local function in_fov (pos1, pos2, yaw, pitch, fov)
local function yaw2vec (yaw, pitch)
return {x = math.cos(yaw) * math.cos(pitch), y = math.sin(pitch), z = math.sin(yaw) * math.cos(pitch)}
end
local function dotproduct (v1, v2)
return ((v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z))
end
local function angle (v1, v2)
return math.acos(dotproduct(v1, v2) / (vector.length(v1) * vector.length(v2))) * 180 / math.pi
end
print(angle(pos1, pos2).."\n"..dump(yaw2vec(yaw, pitch)))
end
-- somewhere in the mob's on_step function
if player:get_player_name() == "singleplayer" then
in_fov(self.object:getpos(), player:getpos(), self.object:getyaw(), 0, 90)
end
0.50313994472358
{
y = 0,
x = -0.082862613092331,
z = -0.99656098024733
}
local an = ( d.x * p.x ) + ( d.z * p.z )
local a = math.deg( math.acos( an ) )
local function in_fov (pos1, pos2, yaw, pitch, fov)
local function yaw2vec (yaw, pitch)
return {x = -math.sin(yaw) * math.cos(pitch), y = math.sin(pitch), z = math.cos(yaw) * math.cos(pitch)}
end
local function dotproduct (v1, v2)
return ((v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z))
end
local function angle (v1, v2)
return math.deg(math.acos(dotproduct(v1, v2) / (vector.length(v1) * vector.length(v2))))
end
print(90 - angle(yaw2vec(yaw, pitch), vector.subtract(pos1, pos2)))
end
BrandonReese wrote:If I remember correctly this bit of code was key to actually get a number I could use:
BrandonReese wrote:Since mobs don't have pitch I think you have to treat it like a 2D world and exclude pitch and the Y coordinate from your formulas.
vector.subtract(pos2, pos1)
TeTpaAka wrote:My code is correct. But you have to invert the order in vector.subtract. To get the direction from one point to the other, you need to subtract the origin from the target, so
- Code: Select all
vector.subtract(pos2, pos1)
should return the right vector.
The 90- has to be removed and the formula in yaw2vec reverted to my function.
The problem is, that minetest uses a left-handed coordinate system while in school, you always use right-handed ones, so the formula has to be inverted, also. (Which mine is)
EDIT:
http://irc.minetest.ru/minetest/2015-06-24#i_4297415
This produces 90 because you print 90-0.
local function in_fov (pos1, pos2, yaw, pitch, fov)
local function yaw2vec (yaw, pitch)
return {x = math.cos(yaw) * math.cos(pitch), y = math.sin(pitch), z = math.sin(yaw) * math.cos(pitch)}
end
local function dotproduct (v1, v2)
return ((v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z))
end
local function angle (v1, v2)
return math.deg(math.acos(dotproduct(v1, v2) / (vector.length(v1) * vector.length(v2))))
end
print(angle(yaw2vec(yaw, pitch), vector.subtract(pos2, pos1)))
end
90
180 ------- 0
90
0
90 ------- 90
180
TeTpaAka wrote:For player:get_look_yaw, it works with my formula. Could it be, that for entities, the yaw has another reference point?
Anyway, could you try flipping x and z (again, sorry).
It seems to be :
- Code: Select all
90
180 ------- 0
90
When it should be:
- Code: Select all
0
90 ------- 90
180
in_fov = function(self,pos)
-- checks if POS is in self's FOV
local yaw = self.object:getyaw() + self.rotate
local vx = math.sin(yaw)
local vz = math.cos(yaw)
local ds = math.sqrt(vx^2 + vz^2)
local ps = math.sqrt(pos.x^2 + pos.z^2)
local d = { x = vx / ds, z = vz / ds }
local p = { x = pos.x / ps, z = pos.z / ps }
local an = ( d.x * p.x ) + ( d.z * p.z )
a = math.deg( math.acos( an ) )
if a > ( self.fov / 2 ) then
return false
else
return true
end
end,
local function in_fov (pos1, pos2, yaw, pitch, fov)
local function yaw2vec (yaw, pitch)
-- we must invert the yaw for x to keep the result from inverting when facing opposite directions (0* becoming 180*)
return {x = math.sin(-yaw) * math.cos(pitch), y = math.sin(pitch), z = math.cos(yaw) * math.cos(pitch)}
end
local function dotproduct (v1, v2)
return ((v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z))
end
local function angle (v1, v2)
return math.deg(math.acos(dotproduct(v1, v2) / (vector.length(v1) * vector.length(v2))))
end
local v = vector.subtract(pos2, pos1)
print(angle(yaw2vec(yaw, pitch), v))
end
-- returns the angle difference between pos1 and pos2, as seen from pos1 at the specified yaw and pitch
function pos_to_angle (pos1, pos2, yaw, pitch)
-- note: we must invert the yaw for x in yaw_vec, to keep the result from inverting when facing opposite directions (0* becoming 180*)
local yaw_vec = {x = -math.sin(yaw) * math.cos(pitch), y = math.sin(pitch), z = math.cos(yaw) * math.cos(pitch)}
local pos_subtract = vector.subtract(pos2, pos1)
local pos_dotproduct = (yaw_vec.x * pos_subtract.x) + (yaw_vec.y * pos_subtract.y) + (yaw_vec.z * pos_subtract.z)
local angle = math.deg(math.acos(pos_dotproduct / (vector.length(yaw_vec) * vector.length(pos_subtract))))
return angle
end
Users browsing this forum: Oil_boi and 2 guests