Creating smooth terrain and part terrain planet gravity. edit: for a physics based car now

  1. Use EgoMoose’s gravity controller:
  1. Store a list of positions for the center of the planets.
  2. Each physics update:
    • Get the nearest planet position
    • Set the direction of gravity to be in that direction (planet position - player position) in the gravity controller
  3. Done!

i already made the controller for the player
im now trying to get this working for my physics based car

i should edit the title…

edit:
force for the gravity on the Y is -294k (ish)
force for the suspension on the Y is somewhere above that (it changes a lot)

edit 2:
stiffness = 60000
damping = 5000
too much makes it bounce

stiffness = 40000
damping = 2500
too little

1 Like

Ah okay. To do that:

  • Either set Workspace.Gravity to 0 or add a vector force to each assembly (with force: mass * workspace gravity) in the upwards direction to cancel the existing gravity
  • Add a vector force to each assembly for the artificial gravity
  • Every physics update:
    • Get the closest planet
    • Get the unit direction of the planet from the assembly’s center of mass
    • Set the force to be unit direction * mass * desired gravity

I think you do need gravity for each wheel, because I’m pretty sure they’re separate assemblies

I also wouldn’t use raycasting because then the car wouldn’t do anything on hills and even walls (like slow down or stop). Instead I would pick a way to calculate the gravity at a point (like picking the closest planet from a list of planet positions).

You can calculate the artificial gravity forces to be assembly mass * workspace.gravity to get the fake gravity to be consistent with the regular gravity.

  1. already done
  2. already done
  3. already done

and no i dont need one for each wheel for now. im just trying to get this working with a perfect sphere. it will be easier to convert a perfect sphere to work with hills and mountains

raycast is a very important part of the vehicle without it i would have no idea where the ground is. this vehicle is all done through math there is no spring constraints or friction going. nothing is touching the ground (that can collide)

as seen in this video (second one): Creating smooth terrain and part terrain planet gravity. edit: for a physics based car now - #23 by bIorbee
the car bounces up and down. i tried fine tuning the suspension and damping but nothing will keep it stable

also at some point the car just decides to fall over

1 Like

That looks way more than 196.2 gravity. Are you sure you are calculating gravity correctly? Can’t you adjust the suspension’s stiffness and damping?

the reason is was way more is because there was 4 wheels applying it

the updated one looks more like the second video from this message: Creating smooth terrain and part terrain planet gravity. edit: for a physics based car now - #23 by bIorbee

yes i already tried changing the stiffness and damping, nothing i set it to worked; either it was too weak or too strong

You can try BasePart.AssemblyMass to get the mass then divide it by wheels.

thats already done. the gravoty is calculated the same way as before but this time just on gector force at the center of mass

-- base gravity (right now 196.2), workspace.Gravity is 0
local g = workspace.PlanetCenter.Gravity.Value
-- mass of the base. base is the only thing that has mass everything else is massless
local mass = base.AssemblyMass

-- upVector is a Unit vector
local gForce = g * mass * self.upVector
return gForce

@SubtotalAnt8185 @BendsSpace update

so heres the real issue and also im sending this up to clear up any confusion

the vehicle with the fake gravity works fine when the up vector is (0, 1, 0)
the current gravity is 196.2 and nothing is changed in this video except now the gravity points towards the center of the planet

i also turned off everything but the gravity and suspension force.

i had this bouncing glitch before and i fixed it by getting a better speed calculator. but now i tried to do that and it aint working.

what i currently have to calculate the vertical speed is this

-- self.attach is the attachment the vector force is attached to
-- self.upVector is the calculated up vector based on the planet
-- baseCF is the cframe of the base
-- base is an invisible part where all the forces are applied, also the only part with mass

function getVelocityAtPoint(part, worldPoint)
	return part.Velocity + part.RotVelocity:Cross(worldPoint - part.Position)
end

-- without :Cross(self.upVector) it was much more bouncy than with
local velocity = getVelocityAtPoint(self.attach.Parent, self.attach.WorldPosition):Cross(self.upVector)
local verticalSpeed = baseCF:vectorToWorldSpace(self.upVector):Dot(velocity)

this method seems to be more stable but still very bouncy

local velocity = baseCF:vectorToObjectSpace(getVelocityAtPoint(self.attach.Parent, self.attach.WorldPosition):Cross(self.upVector))
local verticalSpeed = baseCF:vectorToWorldSpace(self.upVector):Dot(velocity)

this is very stable but flings the cart some times

local verticalSpeed = base:GetVelocityAtPosition(self.attach.Position).Y

video of the method above:

this is then multiplied by the damping (just the dampened spring formula)
this works fine when the up vector is (0, 1, 0) but doesnt seem to work when it moves around.
i also tried making it (0, -1, 0) thinking that it doesnt work when X or Z isnt 0 but that didnt work either

so im lost at this point. i dont know what to do make it work with the correct up vector

1 Like

You need to have a multiplier for it and decrease it.

What do you mean by this? Do you mean that it prevents the vehicle from moving?

no its to the dampended spring formula modified for games

and no there is no multiplier to the velocity it doesnt exist

@BendsSpace @SubtotalAnt8185 im mentioning you two because you two are helping me out a lot with this

update #2 i fixed the issue within the last update but now a bunch more are now here

1st is the big and main one
the suspension force isnt applied directly up causing it to move around since the force is slightly pushing that way. (the video will make this make more sense)

this is a problem for two reason. 1 when going around the planet you speed up a ton and cant stop ever. 2 i dont want the car to slide around when stopped. when stopped the car should stay around the same place

video:

this is what i do to make it point directly up based on the gravity’s up vector
data.upVector.Force = suspensionForce * Vector3.new(0, -upVector.y, 0)
upVector is relative to its attachment

but since each wheel isnt at the same elevation this causing a slight change in the direction of all four of the vectors causing it to push back then the others push in the opposite direction and this just repeats with a never ending cycle

2nd issue
when getting into the vehicle (as seen in the video) the car just snaps down for no reason.
the gravity force does not change. i made sure the character is massless. i know for sure when handing over gravity control to the client, the client has the same values, and no variables were changed between the transfer

just for some reason when you get in it the offset (which is the distance between the vector force’s attachment’s position and the ground) decreases from 2.7 to 2.0. this causing the suspension force to be much larger (while not really impacting a lot) but this also is a stable 2.0 and never goes back to 2.7 where it should be. it just sits there causing the vehicle to be very low to the ground

i know everything works fine because i reuse the same module for the client and server. so i dont get whats wrong with that

i think i know how to fix this but it could be unoptimized since the idea is just doing gravity calculation and force appliance on the server and leaving the client to do the rest. this may help it but the problem is i give network ownership to the client.

gravity force calculation. every heartbeat this is added

-- if you really want to see this function
-- i dont understand it i just know how to use it
function getRotationBetween(u, v, axis)
	local dot, uxv = u:Dot(v), u:Cross(v)
	if (dot < -0.99999) then return CFrame.fromAxisAngle(axis, math.pi) end
	return CFrame.new(0, 0, 0, uxv.x, uxv.y, uxv.z, 1 + dot)
end

function calculateGrav(base, upVector)
	local g = workspace.PlanetCenter.Gravity.Value
	local mass = base.AssemblyMass

	local gForce = upVector.Unit * mass * g
	return gForce
end

local upVector
local gravityDir = (planetCenter.Position - self.base.Position)
local rotateToFloorCFrame = getRotationBetween(self.base.CFrame.UpVector, -gravityDir, Vector3.new(1, 0, 0))

if gravityDir.Magnitude <= planetCenter.GravityDistance.Value then
	upVector = -gravityDir.Unit
else
	upVector = Vector3.new(0, 1, 0)
end
self.upVector = upVector

local gravForce = calculateGrav(self.base, self.upVector)
self.gravVector.Force = -gravForce

thats the two main issues i have right now. i need some help solving them

1 Like

You need to subtract velocity from it to achieve damping.

I’ve made a chassis that uses the normal vector for this too. I just damped the dot product of velocity going perpendicular to the wheel, and this somewhat worked in my case.

However, what you could possibly do is take the average up vector of all of the wheels and apply it to all of them to smooth it out.

Probably because of network ownership. SetNetworkOwner should be used.

Though, you imply that you use this for the client and server, so I’m not sure.

this has nothing to do with the cycle
i said this. its getting pushed back and forth not up and down
i know how to make the suspension force i have done it many times before

this is how i get the velocity

local base: BasePart = self.attach.Parent
local baseCF = base.CFrame

local velocity = getVelocityAtPoint(self.attach.Parent, self.attach.WorldPosition)
local verticalSpeed = baseCF:vectorToWorldSpace(Vector3.new(0, 1, 0)):Dot(velocity)

and gets applied like so

suspensionForce * Vector3.new(0, -upVector.y, 0)

and its relative to its attachment. so its local up vector is directly perpendicular to the base
i dont think you understand whats wrong here. i will draw a picture

the circle is the planet, the red brick is the car, the black dots on the car are the vector forces, and the green arrows are their velocity

so when like this the higher up wheel is pushing UP AND TO THE LEFT this causing the car to drift in that direction.
but the lower wheel after getting pushed down will push back causing it going back to the right.

since the wheels are never aligned perfectly this causes the car to drift.

now this is easily fixed in cars that drive on flat ground and their up vector is always (0, 1, 0)
because their vector forces will always be relative to the world so they will always point straight up

but due to the up vector of the car never being consistent, and when upside down pushing up relative to the world will causing it to push in the direction of the planet instead of away from it

the player owns network of the car when getting in. i already said this

I did not say it needed to. Damping can be in any direction.

I don’t think it’s the wheels, but rather the terrain. Terrain is not perfectly smooth. Maybe you could have a sphere inside the terrain that you use to raycast to and then you blacklist terrain from it.

you still arent understanding the issue

the issue is the car while on a slope will fall backwrads down it (or forwards)
this is due to the suspension force which is aligned with the car and not the global up vector
image

the spring force can be deconstructed into two vectors, shown in yellow (yellow forces are not rotated correctly to make it easier to see)
image

first is the up force. this pushes up to keep it from just laying on the ground.
next due to the up vector of the car, there is a new backwards force that is happening
this pushes the vehicle backwards which basically makes it roll down the slope

there is also a friction force applied for rolling friction. this isnt enough to keep it from rolling down the slope

so the solution is to figure out how to scale the rolling friction force enough so it makes it not roll down the slope.
i seen this done before in math through free body diagrams but i cant figure out how to code one in roblox

here is an example of a free body diagram
image

this picture was rotated so the camera is now rotated based on the rotation of the car
the car is still on the slope (as seen with the gravity not pointing donw)
there is also the theta symbol (Θ)

this is what im trying to calculate and i think i know how to calculate it by
taking the raycast hit normal inverted
then calculating the angle between the gravity unit vector and the normal

this gives around 17 degrees which makes sense since they are pretty close together

now the problem is how do i scale the rolling force so now when on a slope the car wont fall down
how would i counter the yellow force in this picture?

so thats what i been trying to do for the past 12 hours

no i cannot just extract the yellow force, since the suspension force actually has no force there. its just the rotation of the car that causes that. since the suspension force is always pointing up relative to the car, when the car is rotated this causes the spring force to “rotate” with it even though no force is being applied in that direction

this has nothing to do with damping or the suspension force, or even the gravity
all of it is to do with the rolling force not applying enough force for it to stay on the slope

now you may say “why not make the spring force global to the world” well that would fix the issue but brings in another.
image

when upside down the suspension force is now pointing in the wrong direction.
now you may say “thats an easy fix just point that force to the up vector of the car” and no that wouldnt work since now we are back to where we started with the vector force being relative to attachment0 but with more steps

Exactly.

I actually have no idea how this is calculated internally. Additionally, we do not know exactly how much force is being applied. However, what I did in a similar situation (more of a hacky workaround) is to allow the suspension force to be negative to some extent (although this may be problematic). You can also get a rough calculation using AssemblyAngularVelocity if that works better for you.

hey man! Awesom job with this! I have been trying to figure this out for the past few days, and I just can’t manage it! Would you mind showing me your code? Thanks!

Great what about the player has a ship or tool that flys and goes away the planet gravity will pull still or not?

its been a year and ive gotten much better at physics based math. i know the way to solve this so for anyone who is looking for a solution, i will post it now
i wont be posting any code, just the math you will need to solve it

the ultimate problem is that the car is not staying where it should on the planet
when on flat gound every force is normal, as you can see in this picture
image

you can see that the gravity force and normal force are straight up and down, so the car wont be push to the side

now lets see the forces when on a sphere

we now have a force pushing to the left Fgx and up Fgy, or in this case up the arc of the circle
the gravity force always points directly to the center of the circle, since thats where gravity is coming from, and the normal force is always perpendicular to the surface

how would we solve this? lets look at a close up

so in this case, the gravity force is pushing down the slope. you can get the x and y components of the gravity force (relative to the slope) by using Fg * sinθ and Fg * cosθ, sin is the x component and cos is the y component. for those who don’t know trig, θ is an angle, usually in radians, which is what the math.cos and math.sin equations take so make sure your angle is in radians before putting it in by using math.rad (if you call this on an angle already that’s in radians it will mess it up too)

so we have the vertical already delt with, this is our normal force. the minimal amount of force required to keep the car from pushing into the ground, it will still touch the ground but our spring force will be the one pushing it off the ground. our normal force would just be the y component of the gravity force, Fg * cosθ since its whats pushing into the ground so we need to counter that

but now we got a big issue, we have the gravity force pushing us down the slope Fg * sinθ we can introduce a new force to push in the opposite way to counter that, we will call this the friction force (f)

lets look at our new forces

to keep something from moving we need the net force (add up all the forces and see what you get) to be 0, so lets look at the vertical with respect to the slope

we have Fn pushing up, which this is equal to Fg * cosθ going down so the vertical does cancel out, Fnety = 0 how about the horizontal? we have f pushing up the slope and this is equal to Fg * sinθ pushing down the slope. they cancel out so Fnetx = 0

if Fnetx = 0 and Fnety = 0 we can say that Fnet = 0 if the net force is 0 then we won’t be moving. we have solved it!

this entire problem was the physics problem of an object on a slope


but have we? what is θ? we don’t know what this is, how do we calculate it?
we can do some vector math to solve for it. so θ is the angle respect to the vertical (the dotted line to the right of the angle). the vertical in this case is the opposite of where the normal force is going, and remember normal force is always perpendicular to the surface

if we knew the angle of the slope, then this would be easy but we are on a sphere where that angle is not easy to get, so we need another method

usually our normal force will match the up vector of the car, so we can just use that and invert it. now we now know our gravity force and the direction straight down relative to the surface, we can use a very useful vector equation called the dot product, you can see more examples of how useful the dot and cross product of vectors are here The Ultimate Guide to Vector3:Cross() and Vector3:Dot()

in our case we are going to use it to get an angle between the gravity force, and the y direction of the gravity force
image

this is Vector3:Dot(Vector3) this gives the angle in radians, if you want to make sure the angle makes sense you can convert it to degrees by using math.deg and printing it, but remember math.cos and math.sin require the angle to be in radians to process it correctly

your gravity force and inverted surface direction should be aligned on the same plane most of the time, so weird aligning wont give you an issue with the angle


now we have truly solved the problem. if anybody still reading this needs help ask me, i tried to explain it the best i could

1 Like