Jump to content

Terrain height at given point


Andy90
 Share

Go to solution Solved by Alienhead,

Recommended Posts

Hi, 

if you mean in UltraEngine, then this is what you're looking for: 

https://www.ultraengine.com/learn/Terrain_GetElevation?lang=cpp

https://www.ultraengine.com/learn/Terrain_GetHeight?lang=cpp

GetElevation get the global height of the terrain (including the scale), whereas Getheight get the raw height value (0.0 - 1.0) of the heightmap at the specific position.

For Leadwerks Engine the same commands exists.

 

  • Like 1
  • Intel® Core™ i7-8550U @ 1.80 Ghz 
  • 16GB RAM 
  • INTEL UHD Graphics 620
  • Windows 10 Pro 64-Bit-Version
Link to comment
Share on other sites

  • Solution

Make sure you have the correct pointer to the terrain object.

    -- Cycle loaded map
    for x=0,world:CountEntities()-1 do
        local entity = world:GetEntity(x)

        -- get terrain mesh
        if world:GetEntity(x):GetClass()==Object.TerrainClass then
            terrain=world:GetEntity(x)
            terrain=tolua.cast(terrain,"Terrain")
        end
 
   end

Your code should be more like this :

local y = terrain:GetElevation(xz)

 

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

No, at least not officially supported. In lua there is no way to achieve this. In the cpp version it is possible by using the not documented Vegetation methods of the terrain class, but as said, these are not supported to be used by the end user.

 

  • Intel® Core™ i7-8550U @ 1.80 Ghz 
  • 16GB RAM 
  • INTEL UHD Graphics 620
  • Windows 10 Pro 64-Bit-Version
Link to comment
Share on other sites

ah ok. Yeah i got the leadwerks professional version. So i could access it with c++? I would like that the player can harvest trees to gether ressources. The other way to do it would to create a prefab with the tree model and the script and place some tree manualy. What would you prefer in this case?

Link to comment
Share on other sites

A good starting point might be this topic: 

 

I haven't worked with LE since the UltraEngine Early Access, but the essential methods should all be located in Terrain.h and Vegetation.h .

If i remember correctly it is also possible to use camera picking to get the actual instance, but that is not for sure.

  • Intel® Core™ i7-8550U @ 1.80 Ghz 
  • 16GB RAM 
  • INTEL UHD Graphics 620
  • Windows 10 Pro 64-Bit-Version
Link to comment
Share on other sites

It's quite easy to mimic the vegetation system in LE. To be honest it proved to be faster creating a pivot system with attached trees to it manually. The only downside is you dont get to use the easy paint-on feature in the LE editor, but with some code you can mimic the paint on feature in your real map and save out the locations to an external file.  Doing so you'll have entity pointers to your trees to do as you please.

I did this in an experimental project I worked on last year and it year and it had very positive results, actually I'm using the same developed system for my current project.

 

  • Like 1
Link to comment
Share on other sites

53 minutes ago, klepto2 said:

A good starting point might be this topic: 

I haven't worked with LE since the UltraEngine Early Access, but the essential methods should all be located in Terrain.h and Vegetation.h .

If i remember correctly it is also possible to use camera picking to get the actual instance, but that is not for sure.

Is there allready an Early Access ?

Link to comment
Share on other sites

  • 2 weeks later...

In Leadwerks the terrain is just a static object in the map. Terrains are only editable in the editor, and there's no way to retrieve detailed information in-game.

In Ultra this is quite a lot more flexible.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

Ah, okay. Thanks anyway. I'll give it a shot with C++. If that doesn't work, I'll have to explore alternative methods to add wood to the player's inventory. Perhaps by incorporating additional prefab trees placed around a pivot, similar to the suggestion by @Alienhead.

----

1 hour ago, Josh said:

In Ultra this is quite a lot more flexible.

For example, will it be possible to access individual vegetation objects in the Ultra Engine?

 

 

Link to comment
Share on other sites

I have not started on any vegetation system in Ultra. The rendering is so fast that a special system for vegetation might not be needed at all, except in the case of very large environments. But in any case, the Lua and C++ APIs are much better synced together in Ultra than in Leadwerks.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

Ah okey this sounds very nice. I finished my script for a tree spawning based on a pivot
 

Script.terrain = nil
Script.player = nil --Entity "Player"
Script.playerDistance = 30 --Float "Player Distance"
Script.seed = 123456 --Float "Seed"
Script.treeCount = 25 --Int "Trees"
Script.minDist = 25 --Float "Min Distance"
Script.maxDist = 75 --Float "Max Distance"
Script.tree = "" --Path "Model"
Script.treeMinHeight = 0.5 --Float "Min height"
Script.treeMaxHeight = 1.0 --Float "Max height"
Script.debug = true --Bool "Debug Mode"

function Script:Start()
	--Find the terrain
	local world = World:GetCurrent()
	for i = 0, world:CountEntities() - 1 do
		local entity = world:GetEntity(i)
		if entity:GetClass() == Object.TerrainClass then
			self.terrain = tolua.cast(entity, "Terrain")
		end
	end

	--Sets a tree at the pivot location
	local x = self.entity:GetPosition(true).x
	local z = self.entity:GetPosition(true).z
	local y = self.terrain:GetElevation(x, z)
	local tree = Model:Load(self.tree)
	tree:SetPosition(x, y, z)
	tree:SetParent(self.entity)

	--Place a sphere at the pivot location
	if self.debug then
		local spehre = Model:Sphere()
		spehre:SetColor(1.0, 0.0, 0.0)
		spehre:SetScale(1.0)
		spehre:SetPosition(x, y, z)
	end

	math.randomseed(self.seed)
	for i = 0, self.treeCount do
		--Calculate the angle and the distance for the new tree
		local deg = 360 / self.treeCount * i
		local radians = math.rad(deg)
		local distance = math.random(self.minDist, self.maxDist)
		local sin = math.sin(radians)
		local cos = math.cos(radians)

		--Calculate the x,y,z cords for the tree
		local x = self.entity:GetPosition(true).x + distance * cos
		local z = self.entity:GetPosition(true).z + distance * sin
		local y = self.terrain:GetElevation(x, z)

		--Calculates the scale for the tree
		local scale = math.random(self.treeMinHeight * 100, self.treeMaxHeight * 100) / 100

		--Creates the tree within the scene
		local tree = Model:Load(self.tree)
		tree:SetPosition(x, y, z)
		tree:SetScale(scale)
		tree:SetParent(self.entity)

		--Creates a debug sphere at the tree location
		if self.debug then
			local spehre = Model:Sphere()
			spehre:SetColor(1.0, 1.0, 0.0)
			spehre:SetScale(1.0)
			spehre:SetPosition(x, y, z)
		end
	end
end

function Script:UpdateWorld()
	--Enables the trees when the player is nearby
	local distance = self.entity:GetDistance(self.player)
	if distance > self.playerDistance then
		self.entity:Hide()
	else
		self.entity:Show()
	end
end

 

  • Like 1
Link to comment
Share on other sites

I've developed a second iteration of the script, this time utilizing a prefab. This means there are now two scripts in play: the Spawn Manager and the tree itself. 


1. Spawn Manager

Script.terrain = nil
Script.player = nil --Entity "Player"
Script.playerDistance = 30 --Float "Player Distance"
Script.seed = 123456 --Float "Seed"
Script.treeCount = 25 --Int "Trees"
Script.minDist = 25 --Float "Min Distance"
Script.maxDist = 75 --Float "Max Distance"
Script.tree = "" --Path "Model"
Script.treeMinHeight = 0.5 --Float "Min height"
Script.treeMaxHeight = 1.0 --Float "Max height"
Script.aabbCheck = false --Bool "AABB Check"
Script.debug = true --Bool "Debug Mode"
Script.treeData = {}

function Script:Start()
	self.entity:Hide()
	--Find the terrain
	local world = World:GetCurrent()
	for i = 0, world:CountEntities() - 1 do
		local entity = world:GetEntity(i)
		if entity:GetClass() == Object.TerrainClass then
			self.terrain = tolua.cast(entity, "Terrain")
		end
	end

	local treeData = {}

	--Creates the tree data for the pivot tree
	local x = self.entity:GetPosition(true).x
	local z = self.entity:GetPosition(true).z
	local y = self.terrain:GetElevation(x, z)
	local treeInfo = {
		TreeName = self.entity:GetKeyValue("name") .. "_tree_center",
		TreeX = x,
		TreeY = y,
		TreeZ = z,
		TreeScale = 1.0,
		Visible = true,
		HideTime = 0
	}
	table.insert(treeData, treeInfo)

	--Place a sphere at the pivot location
	if self.debug then
		local spehre = Model:Sphere()
		spehre:SetColor(1.0, 0.0, 0.0)
		spehre:SetScale(1.0)
		spehre:SetPosition(x, y, z)
	end

	math.randomseed(self.seed)
	for i = 0, self.treeCount do
		--Calculate the angle and the distance for the new tree
		local deg = 360 / self.treeCount * i
		local radians = math.rad(deg)
		local distance = math.random(self.minDist, self.maxDist)
		local sin = math.sin(radians)
		local cos = math.cos(radians)

		--Calculate the x,y,z cords for the tree
		local x = self.entity:GetPosition(true).x + distance * cos
		local z = self.entity:GetPosition(true).z + distance * sin
		local y = self.terrain:GetElevation(x, z)

		--Calculates the scale for the tree
		local scale = math.random(self.treeMinHeight * 100, self.treeMaxHeight * 100) / 100

		--If AABB Check is enabled check for collision
		if self.aabbCheck then

			for _,item in pairs(self.treeData) do
				if Vec3(item.TreeX, item.TreeY, item.TreeZ):DistanceToPoint(Vec3(x,y,z)) < 0.5 then
					System:Print("Double Point")
					goto continue
				end
			end

			for i = 0, world:CountEntities() - 1 do
				local entity = world:GetEntity(i)
				if entity:GetClass() == Object.ModelClass and entity:GetParent() == nil then
					if entity:GetAABB():IntersectsPoint(Vec3(x,y,z), 1) then
						System:Print("intersect with entity " .. entity:GetKeyValue("name"))
						goto continue
					end
				end
			end
		end

		--Adds the tree info into the table
		local treeInfo = {
			TreeName = self.entity:GetKeyValue("name") .. "_tree_" .. i,
			TreeX = x,
			TreeY = y,
			TreeZ = z,
			TreeScale = scale,
			Visible = true,
			HideTime = 0
		}
		table.insert(treeData, treeInfo)
		::continue::
	end
	self.treeData = treeData;
end

function Script:UpdateWorld()
	--Enables the trees when the player is nearby
	local distance = self.entity:GetDistance(self.player)
	if distance > self.playerDistance + self.maxDist and not self.entity:Hidden() then
		self.entity:Hide()
		self:HideTrees()
	elseif distance < self.playerDistance + self.maxDist and self.entity:Hidden() then
		self.entity:Show()
		self:ShowTrees()
	end
	-- System:Print(self.entity:GetKeyValue("name") .. " Children " .. self.entity:CountChildren() .. " / " .. #self.treeData)
end

function Script:ShowTrees()
	System:Print("Show Trees!")
	for _, item in pairs(self.treeData) do
		local tree = Prefab:Load(self.tree)
		tree.script.treeData = item
		tree:SetPosition(item.TreeX, item.TreeY, item.TreeZ)
		tree:SetScale(item.TreeScale)
		tree:SetKeyValue("name", item.TreeName)
		tree:SetParent(self.entity)
		if not item.Visible then
			tree:Hide()
		end
	end
end

function Script:HideTrees() 
	local t = self.entity:CountChildren()
	for i = 0, self.entity:CountChildren() -1 do
		local child = self.entity:GetChild(i)
		child:Release()
	end
end

2. Tree Script

Script.treeData = nil
Script.respawn = 10 * 60000

function Script:UpdateWorld()
	if self.entity:Hidden() then
		local now = Time:GetCurrent()
		if now > self.treeData.HideTime + self.respawn then
			self.treeData.Visible = true
			self.entity:Show()
		end
	end
end

function Script:Collision(entity, position, normal, speed)
	if entity:GetKeyValue("name") == "player" then
		if Window:GetCurrent():KeyDown(Key.E) then
			self.entity:Hide()
			self.treeData.Visible = false
			self.treeData.HideTime = Time:GetCurrent()
		end
	end
end

As you can see, the trees are no longer created within the Start function. They are dynamically generated when the player is nearby and released when the player moves away. This enhancement greatly improves performance. For example, if you have 10 spawners each with 50 trees, the old script would add 500 entities to the scene. With the new script, you only add the 10 pivot points, and create the entities for the trees only when the player is nearby.

I hope this will help anyone within the future :) 

  • Upvote 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...