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

its not

each wheel has a bunch of vectors each with a purpose
image

forward, friction and right are nothing to do with gravity
up vector is the suspension force
grav vector is the gravity vector

causing this
image

Alright. From the video it looks like the car’s suspension is simply being clamped down to a positive value and not a negative value.

I don’t suppose this is the case, but you should check for it, because the constraints in the video disappear when this happens (meaning it is disabled).

the vector forces will only become 0 if no ground by the raycast is met
so i do this so it stops pushing on the vehicle because it aint touching the ground

the gravity force is always applied no matter what
i set the gravity back to 196.2 because i want the player and the vehicle to be the same

the workspace.Gravity is still 0
here a video of what is currently going on

update: scrap everything i said
just realized i dont need a gravity force at each wheel, plus the calculation of the force requires on where the force to be applied at the center of mass

so i did that, there is now only one gravity force in the center of mass of the entire model
now its just bouncing

  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.