Hey there! So, im at the forum again because i have been trying to debug this little thing and nothing works. So, i want the trees to go perfectly on top of terrain, so i raycast it since its the only way i found on google.
(I added 30 cuz i thought it might work with it but it doesn’t work with and without the +30)
local origin = Vector3.new(pos.X, pos.Y+30, pos.Z)
local direction = Vector3.new(0, -100000, 0)
local ray = Ray.new(origin, direction)
-- search for the collision point with the terrain
local whitelist = { game.Workspace.Terrain }
local ignoreWater = true
local _, intersection, surfaceNormal, surfaceMaterial = game.Workspace:FindPartOnRayWithWhitelist(ray, whitelist, ignoreWater)
local cframe = CFrame.new(intersection)
* CFrame.new(
math.random() * math.random(-10, 10),
0,
math.random() * math.random(-10, 10)
)
* CFrame.Angles(0, 2 * math.pi * math.random(), 0)
tree:SetPrimaryPartCFrame(cframe)
and ofcourse, it doesn’t work. doing CFrame.new(intersection) does not work but doing CFrame.new(pos) does)??
(doing pos makes it so its not on the surface and some trees are buried underground)
I print CFrame.new(pos) and CFrame.new(intersection) and this is the output
I don’t see a difference except the Y axis because Pos is based on the chunk position and Intersection is based on the Terrain position so its higher so the tree can be placed normally and not sink underground.
Make sure that your raycast is actually hitting the ground, I am saying this because you are getting -99984 for Y-axis which is a number close to the maximum raycast length that you defined in the direction Vector3 that has Y-axis of -100000. If the raycast isn’t hitting anything, it will go until it reaches said limit, therefore, you can make an assumption that the ray didn’t hit the terrain.
I just noticed, you are using :FindPartOnRayWithWhitelist, notice the keyword “Part”?
The raycast system is ignoring the terrain as it’s looking specifically for a part. Use the new raycast API.
Here is a sample to give you an idea on how to use it:
local raycast_config = RaycastParams.new()
raycast_config.BruteForceAllSlow = false
raycast_config.IgnoreWater = true
local raycast_result = workspace:Raycast(part.Position, Vector3.yAxis * -1000, raycast_config)
if raycast_result then
tree:PivotTo(CFrame.new(raycast_result.Position))
end
You are attempting to put Ray object into parameter that accepts Vector3 value.
local raycastConfig = RaycastParams.new()
raycastConfig.BruteForceAllSlow = false
raycastConfig.IgnoreWater = true
local raycastResult = workspace:Raycast(Vector3.new(pos.X, pos.Y + 30, pos.Z), Vector3.yAxis * -100000, raycastConfig)
if raycastResult then
local cframe = CFrame.new(raycastResult.Position) * CFrame.Angles(0, 2 * math.pi * math.random(), 0)
tree:PivotTo(cframe)
end
Also, you should not modify the position that your model will be set to after raycasting as it might get pushed somewhere into the terrain, randomize your raycast origin position instead.
Try lowering the pivot even more by disabling pivot snapping and adjust it until your trees are placed as desired. Just be aware that SetPrimaryPartCFrame is deprecated and pivots should be used instead (like the PivotTo method), you also get more control over the origin.