Currently the developers are putting their own money into JC2-MP to keep the servers online.

Please take a few seconds of your time and disable your AdBlock plugin for our website.

Ad revenue is not going to developers, it is used purely for covering our hosting costs.

 

You are also free to donate, which removes all ads from our website!

Patch 0.3 was just released! Full changelog here: https://t.co/4A50m6IKen

3 years ago

Advertisement
October 29, 2020, 08:48:07 pm

Author Topic: getting a server side staticbject's actual size  (Read 2073 times)

Darwood37

  • Donator
  • Hero Member
  • *****
  • Posts: 690
    • View Profile
getting a server side staticbject's actual size
« on: September 01, 2015, 09:34:27 pm »
Is there a way I can obtain the actual size of a server side created staticobject, i guess like using GetBoundingBox() client side, so that i can see if one position is within that staticobject's position. I have some rather large staticobjects (subs)  that I need to calculate if a missile or bomb has hit and just using Vector3.Distance to find if the one position(missile or bomb) is within the staticobject's position is a little inaccurate because of the shape of the staticobject. Thank you.

SinisterRectus

  • JC2-MP Betatester
  • Sr. Member
  • *****
  • Posts: 452
    • View Profile
Re: getting a server side staticbject's actual size
« Reply #1 on: September 01, 2015, 11:29:43 pm »
Nope. You need to gather the bounding box data on a client and save it to a file (or network it in real time). I briefly described how I did it for vehicles here. If you want more detail, I can walk you through the process. It would be the same for StaticObjects, but obviously more involved because of how many there are.

Darwood37

  • Donator
  • Hero Member
  • *****
  • Posts: 690
    • View Profile
Re: getting a server side staticbject's actual size
« Reply #2 on: September 02, 2015, 11:22:30 pm »
Thanks. I just need it for one type of static object right now, the sub. after i get that info i need to find out how to check to see if a vector3 position, which will be the final position of the bomb or missile is within the "bounding box" data of the moving sub staticobject. As of now i am clueless on how to do any of this. Cheers.

SinisterRectus

  • JC2-MP Betatester
  • Sr. Member
  • *****
  • Posts: 452
    • View Profile
Re: getting a server side staticbject's actual size
« Reply #3 on: September 03, 2015, 06:16:16 am »
Tomorrow, I'll explain what I did, but I just want to ask first: Are these bombs/missiles created/controlled by a player, or are they controlled only by the server?
« Last Edit: September 03, 2015, 06:17:47 am by SinisterRectus »

Darwood37

  • Donator
  • Hero Member
  • *****
  • Posts: 690
    • View Profile
Re: getting a server side staticbject's actual size
« Reply #4 on: September 05, 2015, 03:56:25 am »
Thanks. They are created by the client/player. I only really need it for the bombs as the missiles use a raycast.

SinisterRectus

  • JC2-MP Betatester
  • Sr. Member
  • *****
  • Posts: 452
    • View Profile
Re: getting a server side staticbject's actual size
« Reply #5 on: September 05, 2015, 01:57:09 pm »
So why are you doing the check on the server, and why can't you use a raycast for the bombs?

Darwood37

  • Donator
  • Hero Member
  • *****
  • Posts: 690
    • View Profile
Re: getting a server side staticbject's actual size
« Reply #6 on: September 05, 2015, 04:00:27 pm »
I moved all the damage control to the server. once the bomb reaches its destination it Network:Sends the final position and amount of damage. When i tried to calculate the positions on the client i ended up getting position (NaN) errors which i thought was due to the plane going out of streaming distance to the final destination, seeing as they fly so fast. I could do a raycast from the final position, down, and all around i guess and  if the entity matches the model for the sub staticobject then do damage as required, but this i am sure i will run in to similar NaN problems. Also i am not real sure how to fire a raycast properly from the final position and check to see if that is near the staticobject. appreciate the help.

SinisterRectus

  • JC2-MP Betatester
  • Sr. Member
  • *****
  • Posts: 452
    • View Profile
Re: getting a server side staticbject's actual size
« Reply #7 on: September 05, 2015, 06:40:52 pm »
You have to simulate the projectile motion of the bomb (which I assume you're already doing?), and raycast ahead in the direction that it is moving, but I can see how the stream distance can be a problem. If you've moved the logic to the server, then this is a way to check whether you are inside of the submarine. Sorry for the long-winded explanation, but you did say you are clueless :P So, here you go!

----

The first thing you want to do is make sure your submarine is spawned with a zero angle. Any position is fine, and either a ClientStaticObject or StaticObject can be used. I used a StaticObject in this example.

The function StaticObject:GetBoundingBox() returns two opposite corners of an axis-aligned bounding box (AABB) for that object.

You can see them marked here with yellow circles:

Code: [Select]
function DrawBoundingCorners(obj, color)

local u, v = obj:GetBoundingBox()
Render:DrawCircle(Render:WorldToScreen(u), 10, color)
Render:DrawCircle(Render:WorldToScreen(v), 10, color)

end



If you take those two corners, and permutate their x, y, and z values, you will get the remaining six corners of a BB. By drawing lines between the eight corners, you can visualize the whole BB:
Code: [Select]
function DrawBoundingBox(obj, color)

local u, v = obj:GetBoundingBox()

local corners = {
Vector3(u.x, u.y, u.z),
Vector3(u.x, u.y, v.z),
Vector3(v.x, u.y, v.z),
Vector3(v.x, u.y, u.z),
Vector3(u.x, v.y, u.z),
Vector3(u.x, v.y, v.z),
Vector3(v.x, v.y, v.z),
Vector3(v.x, v.y, u.z),
}

Render:DrawLine(corners[1], corners[2], color)
Render:DrawLine(corners[2], corners[3], color)
Render:DrawLine(corners[3], corners[4], color)
Render:DrawLine(corners[4], corners[1], color)

Render:DrawLine(corners[1], corners[5], color)
Render:DrawLine(corners[2], corners[6], color)
Render:DrawLine(corners[3], corners[7], color)
Render:DrawLine(corners[4], corners[8], color)

Render:DrawLine(corners[5], corners[6], color)
Render:DrawLine(corners[6], corners[7], color)
Render:DrawLine(corners[7], corners[8], color)
Render:DrawLine(corners[8], corners[5], color)

end



The 'axis-aligned' part means that the edges of the BB will always be parallel to the axes of the game world, regardless of the orientation of the object.



If you rotate the submarine, you can see how the BB expands to fit the object, but its orientation does not change. Only when the object is axis-aligned (like when set with a zero angle) is the BB also object-aligned, which more accurately represents the shape of the object.



How can you make sure that the BB is always object-aligned? One way to do this is by recording the BB data while the object is axis-aligned. You can then "playback" the data at any other angle.

Notice that the BB corners, like all positions, are relative to the game world. You want them to be relative to the object. To convert them, subtract the object's position from the BB corners:

Code: [Select]
function GetBoundingBoxRelative(obj)

local position = obj:GetPosition()
local u,v = obj:GetBoundingBox()

return u - position, v - position

end

With the submarine, you get the following points. These tell you how far the corners are from the object's base position:

Code: [Select]
Vector3(-66.159668, -41.867691, -265.626831)
Vector3( 66.140381,  69.942322,  255.328735)

You can save these values to a table:

Code: [Select]
boxes = {
['km07.submarine.eez/key014_02-a.lod'] = {Vector3(-66.16, -41.87, -265.63), Vector3(66.14, 69.94, 255.33)}
}

and use them to draw a BB relative to the object:

Code: [Select]
function DrawBoundingBoxRelative(obj, color)

local model = obj:GetModel()
local position = obj:GetPosition()
local angle = obj:GetAngle()

local u = boxes[model][1]
local v = boxes[model][2]

local corners = {
position + angle * Vector3(u.x, u.y, u.z),
position + angle * Vector3(u.x, u.y, v.z),
position + angle * Vector3(v.x, u.y, v.z),
position + angle * Vector3(v.x, u.y, u.z),
position + angle * Vector3(u.x, v.y, u.z),
position + angle * Vector3(u.x, v.y, v.z),
position + angle * Vector3(v.x, v.y, v.z),
position + angle * Vector3(v.x, v.y, u.z),
}

Render:DrawLine(corners[1], corners[2], color)
Render:DrawLine(corners[2], corners[3], color)
Render:DrawLine(corners[3], corners[4], color)
Render:DrawLine(corners[4], corners[1], color)

Render:DrawLine(corners[1], corners[5], color)
Render:DrawLine(corners[2], corners[6], color)
Render:DrawLine(corners[3], corners[7], color)
Render:DrawLine(corners[4], corners[8], color)

Render:DrawLine(corners[5], corners[6], color)
Render:DrawLine(corners[6], corners[7], color)
Render:DrawLine(corners[7], corners[8], color)
Render:DrawLine(corners[8], corners[5], color)

end

If you look at the BB at this point, you're probably saying that it's not even close to submarine sized or shaped. That's because the BB expands to fit every irregular part of the submarine. That's not really helpful. This is where I recommend that you use convert your bounding box into an bounding ellipsoid. I find that it is easier to check whether a point lies inside of an ellipsoid than in a box. Submarines are also conveniently ellipsoid-shaped. If you didn't already know, an ellipsoid is a 3D ellipse; a squashed sphere. The concept here is similar to that of a Vector3.Distance check, except instead of being confined to one radius, you can have a radius that continuously changes depending upon the length, width, and height of the object.

What the following does is determine the parameters for an ellipsoid based on the BB:

If you want a circumscribed ellipsoid, divide the edge lengths by sqrt(2):

Code: [Select]
ellipsoids = {}

for model,box in pairs(boxes) do

local a = (box[2].x - box[1].x) / math.sqrt(2)
local b = (box[2].y - box[1].y) / math.sqrt(2)
local c = (box[2].z - box[1].z) / math.sqrt(2)

ellipsoids[model] = {a, b, c}

end



If you want an inscribed ellipsoid, divide the edge lengths by 2:

Code: [Select]
ellipsoids = {}

for model,box in pairs(boxes) do

local a = (box[2].x - box[1].x) / 2
local b = (box[2].y - box[1].y) / 2
local c = (box[2].z - box[1].z) / 2

ellipsoids[model] = {a, b, c}

end

I used an inscribed ellipsoid.



You could use these values to draw a 3D model of an ellipsoid, but it's a easier to draw and visualize with a 2D ellipse on each plane:

Code: [Select]
function DrawBoundingEllipsoidRelative(obj, resolution, color)

local model = obj:GetModel()
local position = obj:GetPosition()
local angle = obj:GetAngle()

local u = position + angle * boxes[model][1]
local v = position + angle * boxes[model][2]
local origin = math.lerp(u, v, 0.5)

local a = ellipsoids[model][1]
local b = ellipsoids[model][2]
local c = ellipsoids[model][3]

local ellipses = {{}, {}, {}}

for theta = 0, (2 * math.pi), (2 * math.pi) / resolution do

table.insert(ellipses[1], origin + angle * Vector3(a * math.cos(theta), b * math.sin(theta), 0))
table.insert(ellipses[2], origin + angle * Vector3(a * math.cos(theta), 0, c * math.sin(theta)))
table.insert(ellipses[3], origin + angle * Vector3(0, b * math.sin(theta), c * math.cos(theta)))

end

for i,u in ipairs(ellipses) do
for j,v in ipairs(u) do
if u[j+1] then Render:DrawLine(v, u[j+1], color) end
end
end

end



This is starting to look more submarine like, except that it isn't quite centered and it's obviously too big. To fix this, you can adjust the box data until the ellipsoid better matches the size and shape of the submarine. I came up with the following numbers:

Code: [Select]
boxes = {
['km07.submarine.eez/key014_02-a.lod'] = {Vector3(-45, -42, -280), Vector3(45, 5, 260)}
}



It's not perfect, and you're never going to get a perfect fit unless you use multiple boxes. If that's something you want to do, let me know, but I think this should be good enough.





If you wanted to get crazy, you could look at a 'superellipsoid', which would allow you to use more irregular shapes:



But an ellipsoid should be good enough.

Visualizing the data is great, but since the whole point of this is to figure out if a position is inside of the submarine, you can do that by evaluating the standard function for an ellipsoid:



Code: [Select]
function PositionIsInsideStaticObject(position, obj)

local model = obj:GetModel()
local pos = obj:GetPosition()
local angle = obj:GetAngle()

local u = pos + angle * boxes[model][1]
local v = pos + angle * boxes[model][2]
local origin = math.lerp(u, v, 0.5)

local coord = -angle * (position - origin)

local x_term = (coord.x / ellipsoids[model][1])^2
local y_term = (coord.y / ellipsoids[model][2])^2
local z_term = (coord.z / ellipsoids[model][3])^2

if x_term + y_term + z_term > 1 then
return false
else
return true
end

end

----

I hope this helps and isn't too confusing. Please let me know if you have questions, or if something doesn't work as advertised.

Here is the whole script that I used: http://pastebin.com/qvpw85qG
« Last Edit: December 05, 2015, 09:11:18 pm by SinisterRectus »

Darwood37

  • Donator
  • Hero Member
  • *****
  • Posts: 690
    • View Profile
Re: getting a server side staticbject's actual size
« Reply #8 on: September 07, 2015, 11:08:06 am »
I cannot thank you enough for taking the time to explain this in such great depth and detail.

Just a quick question. When i iterate through all the staticobjects to check if it is the model i want when i pass the position and obj to the PositionIsInsideStaticObject function it returns true for all of the static objects that use that model. I have 4 subs, it should only return true for the obj i am passing that is closet to the pos(bomb or missile).

Code: [Select]
for object in Server:GetStaticObjects() do
if object:GetModel() == "km04.submarine.eez/key004_02-a.lod" then
Proximity = PositionIsInsideStaticObject(pos, object)
if Proximity then
« Last Edit: September 07, 2015, 03:44:26 pm by Darwood37 »

SinisterRectus

  • JC2-MP Betatester
  • Sr. Member
  • *****
  • Posts: 452
    • View Profile
Re: getting a server side staticbject's actual size
« Reply #9 on: September 08, 2015, 02:15:30 am »
There was a mistake in the my post. Try it now with the edited function, where I don't overwrite the position.
« Last Edit: September 08, 2015, 02:43:01 am by SinisterRectus »

Darwood37

  • Donator
  • Hero Member
  • *****
  • Posts: 690
    • View Profile
Re: getting a server side staticbject's actual size
« Reply #10 on: September 09, 2015, 04:13:03 am »
Ahh, thanks muchly.

I see it now pos and poistion.
« Last Edit: September 09, 2015, 04:31:53 am by Darwood37 »