MeshVox V1.1 - A powerful 3D mesh-terrain converter

I’m currently doing wave function collapse for large scale chunk operations a simple solution was using the zone entry points to generate the next region so that they encompass the currently explored region and execute with a ordered delay. I’ve watched a few videos about it on youtube. Currently I’m using a seed based on the position of the chunk and reloading the closest chunk and the position where the player left off. Compressing objects not in view to a reference to their source object in the games library.
image

But I was looking at this code and was wondering if you could help with getting and output of RGB values for the triangle using the surface appearance. I have some low poly assets that are one piece with a texture and I could not use it because the current implementation lacks support.

	if meshPart then
				local surfaceAppearance = meshPart:FindFirstChildWhichIsA("SurfaceAppearance",true)
				local textureID = meshPart.TextureID 
				if textureID == "" then
					textureID = nil
				end
				if textureID then
					if not textureID:match("%d") then
						textureID = nil
					end
				end
				if surfaceAppearance then
					if not textureID then
						textureID = surfaceAppearance.ColorMap
						if textureID == "" then
							textureID = nil
						end
					end
				end

				if textureID then
					CanLoadTexture:set(false)
					LoadingImage:set(true)
					local promise = RobloxImage.fromAsset(textureID)
					promise:andThen(function(fileType,width,height,imgData)
						local idNum = textureID:match("%d+")
						LoadedImageName:set(string.format("%s.%s",idNum,fileType))
						LoadedImage:set{
							width = width,
							height = height,
							imgData = imgData
						}
						LoadedImageID:set(textureID)
					end):catch(function()
						print("Failed to load image")
					end)
					promise:finally(function()
						CanLoadTexture:set(true)
						LoadingImage:set()
					end)
					return
				end
			end
			LoadingImage:set(true)
			local file = StudioService:PromptImportFile({"jpg","png","bmp"})
			if file then
				LoadingImage:set(true)
				local promise = RobloxImage.fromBin(file:GetBinaryContents())
				promise:andThen(function(fileType,width,height,imgData)
					if fileType then
						LoadedImageID:set(file:GetTemporaryId())
						LoadingImage:set()
						LoadedImageName:set(file.Name)
						LoadedImage:set{
							width = width,
							height = height,
							imgData = imgData
						}
					end
				end):catch(function()
					print("Failed to load image")
				end)
				promise:finally(function()
					CanLoadTexture:set(true)
					LoadingImage:set()
				end)
			else
				CanLoadTexture:set(true)
				LoadingImage:set()
			end
		end,

image

--[[ Generation function, takes in a table of MeshParts, not asynchronous ]]
local function Generate(meshParts,fmaterial,surfacem,jobsover)
	if fmaterial==nil then fmaterial=fillMaterial end
	if surfacem==nil then surfacem=surfaceMaterial end
	local objDatas = {}
	local numMeshes = #meshParts
	local promises = {}
	--Decode a cached job
	
	--if jobsover~=nil then
	--	print("using module")
	--	for _,job in jobsover do 
	--		for i,v in job[2] do 
	--			for t,o in job[2][i] do 
	--				if t~=4 then
	--				--if string.upper(job[2][i][t])==job[2][i][t] then -- check if is a word
	--				job[2][i][t]=Vector3.new(job[2][i][t])
	--				end	
	--			end	
				
	--	end
	--		TerrainGen:DoJobs({{unpack(job)}})
	--	end	
	--	return true
	--end
	local fail
	for i,meshPart in meshParts do
		local promise = RobloxMesh.fromAsset(meshPart.MeshId)
		table.insert(promises,promise)
		promise:andThen(function(meshData)
			local objData = {Verts = meshData.Verts,Tris = meshData.LODs[1]}
			table.insert(objDatas,{meshPart=meshPart,objData=objData})
		end)
		promise:catch(function()
			fail = true
		end)
	end
	task.spawn(function()
	
	repeat task.wait() until #objDatas == numMeshes or fail
	
		if fail then
			print("Generating from multiple failed")
			for _,promise in promises do 
				promise:cancel()
			end
		else
			local jobs = {}
			--[[ Generating ]]
			for i,data in objDatas do 
				local meshPart = data.meshPart
				local objData = data.objData
				local tris = objData.Tris
				local meshCFrame,meshSize = CalculateMeshBounds(objData,tris)

				local stampSize,meshSize,stampCF,scale = GetGenerationData(meshPart,objData,meshSize)


				stampCF *= CFrame.new(generationOffset)

				scale *= generationScale


				local triangles = {}
				local matTarget = surfacem
			

				for _,tri in tris do
					local v1 = objData.Verts[tri[1]]
					local v2 = objData.Verts[tri[2]]
					local v3 = objData.Verts[tri[3]]

					local a = stampCF * (meshCFrame:PointToObjectSpace(v1.Position) * scale)
					local b = stampCF * (meshCFrame:PointToObjectSpace(v2.Position) * scale)
					local c = stampCF * (meshCFrame:PointToObjectSpace(v3.Position) * scale)

					local triangleMaterial = matTarget
					table.insert(triangles,{a,b,c,triangleMaterial})
				end

				table.insert(jobs,{replaceVoxels,triangles,fmaterial,generationFloorStuds,generationSurfaceThickness})
			end
			for _,job in jobs do 
				TerrainGen:DoJobs({{unpack(job)}})
			end				
		--return jobs
		end
	end)
	
end

Also included a commented section which demonstrates simple encoding and decoding of a cached job to reduce API usage but is restricted to a static position. It would be good to implement if I have any issues with performance when implementing the library. I would have to just bake the model at position 0,0,0 and adjust them based on their new CFrame.

Also, I’ve gotten pretty good performance benchmarks and almost double the speed using the baked mesh into a module method I explained above. Beyond that I didn’t edit anything beyond mainly using optimized low poly assets.


This was my much anticipated project with this module so thanks for your help! I’ve gotten a lot done with this am done for now. :saluting_face:

2 Likes

Once editablemeshes are live it should be fairly trivial to replace the mesh data fetching stuff with that

1 Like

Yeah those are going to be very cool! This is a very awesome tool you have created and hope to see more updates! Basic functionality for any new features of this branch of your MeshVox is greatly appreciated, such as a means get RGB output of a texture on the mesh surface like in your plugin.


Procedurally generated rooms/towers/castle/caves/pyramids

lots of fun stuff. :slight_smile:

including AI
PS: I integrated the new library into the procedural world generator and got these benchmarks testing on a online server.
image

2 Likes

Love the plugin, saved me quite a bit of time with trying to make a heightmap that would require way too much editing but I have to ask, would it be too much to ask for normal part conversion as well?

1 Like

Hello,
I’m really enjoying this plugins ability to generate large maps with ease. It seems that the heightmap won’t large height differences though. I only get 1 stud variations instead of my entered amount.

Where is there a height map option or how are u teying to use a height map ?

I’m not sure what you’re talking about honestly , there isn’t a height map option . This plugin is meant to replace height map generation

I don’t know what I was saying either honestly.
I got it working, really awesome plugin! Love the fact that it allows you to generate massive terrains from .obj files

let’ try to figure out what you are saying before you hit the reply… we were all very concerned about your usage of this powerful converter! I just spent over 3 hours trying to find a height map options, which honestly makes no sense…

k, I gotta make a sandwich now.

Just wanna thank you for this plugin. I’ve struggled with approaching large scale terrains in Roblox for a while. The default tools were just not cutting it. This plugin paired with your terrain painter one is an insane combo.

1 Like

Just want to say this looks incredibly powerful and I really appreciate people like you on the devforum.
Quick question involving this though, I don’t seem to have any load mesh button? Just “Clear Terrain” and able to choose materials?

I might not be seeing something I’m supposed to, but any help would be great.

Update: Figured out that I could get it to work by importing it from OBJ, but it seems that selection doesn’t work.

Are you selecting a meshpart? Load mesh button only shows up if you have a meshpart selected

2 Likes

I am yes, I’ve selected everything from unions to meshparts to parts with a special mesh in it, the load button didn’t appear for any of them until I import an OBJ then went back to the meshpart tab.

Is HTTPService enabled in studio and plugin has permissions?

1 Like

HTTPService was in fact enabled and the plugin had permissions when I was trying it out.
Keep in mind only after I imported an OBJ it allowed me to convert meshes to terrain as advertised, but from meshpart selection only it was not working and didn’t show anything.

Sorry for the late responses.

Does not work, it is stuck on “Loading” for the generate selected meshparts. Permissions are given, everything is set up correctly

Would you consider making a 3D mesh to parts converter? this would be significantly useful in creating unions.