How can I get the material from a color?

So if I have a color, how can I get the closest material to that color? I want this for terrain, and I think I can use GetMaterialColor to do this but I’m not sure.

Elaborate? there is no way to change a material to a color or a color to a material.

Unless you directly matchthese “material colors”
Screenshot

To get the closest you would have to use something like the levenshtein distance. It is, complicated but might work for your situation.

Still Dont Understand?

We’ll use this function to see the levenshtein distance. These scripts were made from ChatGPT…

function Levenshtein(str1, strArray)
    local distances = {}
    
    -- Iterate over the array of strings
    for index, str2 in ipairs(strArray) do
        local len1 = #str1
        local len2 = #str2
        
        -- Create a table to hold the distances
        local distance = {}
        
        -- Initialize the first row and column of the distance table
        for i = 0, len1 do
            distance[i] = {}
            distance[i][0] = i
        end
        
        for j = 0, len2 do
            distance[0][j] = j
        end
        
        -- Compute the distances
        for i = 1, len1 do
            for j = 1, len2 do
                local cost = (str1:sub(i, i) == str2:sub(j, j)) and 0 or 1
                distance[i][j] = math.min(
                    distance[i-1][j] + 1,      -- Deletion
                    distance[i][j-1] + 1,      -- Insertion
                    distance[i-1][j-1] + cost  -- Substitution
                )
            end
        end
        
        -- Store the final distance for this string in the array
        distances[index] = distance[len1][len2]
    end
    
    return distances
end

Testing it out.

local baseString = "kitten"
local comparisonStrings = {"sitting", "bitten", "kitchen"}

local distances = Levenshtein(baseString, comparisonStrings)

for i, dist in ipairs(distances) do
    print("Levenshtein Distance to", comparisonStrings[i], ":", dist)
end

-- Output:
-- Levenshtein Distance to sitting : 3
-- Levenshtein Distance to bitten : 1
-- Levenshtein Distance to kitchen : 3

As we can see, bitten is close to kitten, so we will say its similar. using this same function we can make this;

New Function

function LevenshteinClosestMatch(str1, strArray)
    local closestMatch = nil
    local minDistance = math.huge  -- Initialize with a very large number
    local distances = {}
    
    -- Iterate over the array of strings
    for index, str2 in ipairs(strArray) do
        local len1 = #str1
        local len2 = #str2
        
        -- Create a table to hold the distances
        local distance = {}
        
        -- Initialize the first row and column of the distance table
        for i = 0, len1 do
            distance[i] = {}
            distance[i][0] = i
        end
        
        for j = 0, len2 do
            distance[0][j] = j
        end
        
        -- Compute the distances
        for i = 1, len1 do
            for j = 1, len2 do
                local cost = (str1:sub(i, i) == str2:sub(j, j)) and 0 or 1
                distance[i][j] = math.min(
                    distance[i-1][j] + 1,      -- Deletion
                    distance[i][j-1] + 1,      -- Insertion
                    distance[i-1][j-1] + cost  -- Substitution
                )
            end
        end
        
        -- Store the final distance for this string
        local currentDistance = distance[len1][len2]
        distances[index] = currentDistance
        
        -- Check if this is the smallest distance found so far
        if currentDistance < minDistance then
            minDistance = currentDistance
            closestMatch = str2
        end
    end
    
    return closestMatch, minDistance, distances
end

New Iteration

local baseString = "kitten"
local comparisonStrings = {"sitting", "bitten", "kitchen", "mitten"}

local closestMatch, minDistance, distances = LevenshteinClosestMatch(baseString, comparisonStrings)

print("Closest Match:", closestMatch)
print("Levenshtein Distance:", minDistance)

-- Output:
-- Closest Match: bitten
-- Levenshtein Distance: 1

1 Like

For the levenshtein, DiffLib (Python Library) also uses this for its “get_close_matches”

1 Like
--modify this as you like
--this uses Euclidean distance instead of levenshtein
local function getColorDistance(c1: Color3, c2: Color3): number 
	local v1 = Vector3.new(c1.R, c1.G, c1.B)
	local v2 = Vector3.new(c2.R, c2.G, c2.B)
	return (v2-v1).Magnitude 
end

--gets all materials that wont error the GetMaterialColor function
local function getTerrainMaterials(): {[Enum.Material]: Color3}
	local materials = {}
	for _, material in pairs(Enum.Material:GetEnumItems()) do
		pcall(function()
			materials[material] = workspace.Terrain:GetMaterialColor(material)
		end)
	end
	return materials 
end

local function getClosestMaterial(color: Color3): Enum.Material
	local current, distance = nil, nil
	for material, c in pairs(getTerrainMaterials()) do
		local d = getColorDistance(color, c) 
		if not current or d < distance then
			current, distance = material, d 
		end
	end
	return current 
end

--Green/Lime -> Enum.Material.LeafyGrass
print(getClosestMaterial(Color3.new(0, 1, 0)))
1 Like

Can you make this work with water? Also can you explain the syntax here? I barely understand it lol.

To make it work with water:

--gets all materials that wont error the GetMaterialColor function
local function getTerrainMaterials(): {[Enum.Material]: Color3}
	local materials = {}
	for _, material in pairs(Enum.Material:GetEnumItems()) do
		pcall(function()
			materials[material] = workspace.Terrain:GetMaterialColor(material)
		end)
	end
	materials[Enum.Material.Water] = workspace.Terrain.WaterColor
	return materials 
end

The syntax means that the function returns a dictionary/mapping with materials as keys and colors as values.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.