You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Godot 4.3中如何确保PNG图片保持原始颜色不被修改?

Godot 4.3中加载PNG时颜色失真,如何保证颜色完全一致?

问题背景

我制作了一张地图PNG,每个国家区域使用唯一的纯色(比如France = #00bbd4Italy = #ff3131),通过Sprite2D的Texture属性加载后,原本单一颜色的区域出现了约30种相似色,导致我基于颜色匹配的地图逻辑完全失效。

我用regions.txt维护颜色与国家的对应关系:

{
  "#00bbd4" : "France",
  "#ff3131" : "Italy",
  "#f1c30f" : "Spain",
  "#00cc00" : "Berber"
}

处理图片的main.gd代码如下:

extends Node2D

@onready var mapImage = $Sprite2D
func _ready():
    load_regions()

func _process(delta):
    pass

func load_regions():
    var image = mapImage.get_texture().get_image()
    var pixel_color_dict = get_pixel_color_dict(image)
    var regions_dict = import_file("res://Map_data/regions.txt")
    
    for region_color in regions_dict:
        var region = load("res://Scenes/Region_Area.tscn").instantiate()
        region.region_name = regions_dict[region_color]
        region.set_name(region_color)
        get_node("Regions").add_child(region)
        
        var polygons = get_polygons(image, region_color, pixel_color_dict)
    
        for polygon in polygons:
            var region_collision = CollisionPolygon2D.new()
            var region_polygon = Polygon2D.new()
            
            region_collision.polygon = polygon
            region_polygon.polygon = polygon
            
            region.add_child(region_collision)
            region.add_child(region_polygon)
    mapImage.queue_free()

func get_pixel_color_dict(image):
    var pixel_color_dict = {}
    for y in range(image.get_height()):
        for x in range(image.get_width()):
            var pixel_color = "#" + str(image.get_pixel(int(x), int(y)).to_html(false))
            if pixel_color not in pixel_color_dict:
                pixel_color_dict[pixel_color] = []
            pixel_color_dict[pixel_color].append(Vector2(x,y))
    return pixel_color_dict

func get_polygons(image, region_color, pixel_color_dict):
    var targetImage = Image.create(image.get_size().x,image.get_size().y, false, Image.FORMAT_RGBA8)
    for value in pixel_color_dict[region_color]:
        targetImage.set_pixel(value.x,value.y, "#ffffff")
        
    var bitmap = BitMap.new()
    bitmap.create_from_image_alpha(targetImage)
    var polygons = bitmap.opaque_to_polygons(Rect2(Vector2(0,0), bitmap.get_size()), 0.1)
    return polygons

#Import JSON files and converts to lists or dictionary
func import_file(filepath):
    var file = FileAccess.open(filepath, FileAccess.READ)
    if file != null:
        return JSON.parse_string(file.get_as_text().replace("_", " "))
    else:
        print("Failed to open file:", filepath)
        return null

解决方案

1. 修改PNG的导入设置

Godot默认的纹理压缩、颜色优化是导致颜色失真的核心原因。选中你的PNG文件,在导入面板中调整以下参数:

  • 压缩模式:设置为Uncompressed(完全不压缩)
  • 格式:选择RGBA8(与代码中使用的格式一致,保证每个颜色通道8位精度)
  • 启用mipmaps:取消勾选(mipmap生成会引入颜色模糊)
  • 颜色空间:根据原始图片格式选择sRGBLinear,避免自动颜色空间转换
  • 过滤:设置为Nearest(禁用纹理插值采样,保证像素颜色完全一致)

设置完成后点击重新导入,让Godot应用新参数。

2. 直接加载原始图片文件(绕过纹理导入)

如果导入设置调整后仍有问题,可以直接读取原始PNG文件,完全跳过Godot的纹理优化流程:

# 替换原代码中从Sprite2D获取image的逻辑
var image = Image.load_from_file("res://path/to/your/map.png")
# 确保格式统一为RGBA8
if image.get_format() != Image.FORMAT_RGBA8:
    image.convert(Image.FORMAT_RGBA8)

3. 颜色匹配容错处理(备选方案)

如果无法完全消除颜色偏差,可以在颜色匹配时加入容差判断,允许RGB通道小范围差值:

# 替换原get_pixel_color_dict函数,加入容差逻辑
func get_pixel_color_dict(image, tolerance: int = 1):
    var pixel_color_dict = {}
    for y in range(image.get_height()):
        for x in range(image.get_width()):
            var pixel = image.get_pixel(x, y)
            var rgb = [int(pixel.r * 255), int(pixel.g * 255), int(pixel.b * 255)]
            var matched_key = null
            
            # 遍历已有颜色,寻找容差范围内的匹配
            for key in pixel_color_dict:
                var target_rgb = [
                    int(key[1:3], 16),
                    int(key[3:5], 16),
                    int(key[5:7], 16)
                ]
                var diff = abs(rgb[0]-target_rgb[0]) + abs(rgb[1]-target_rgb[1]) + abs(rgb[2]-target_rgb[2])
                if diff <= tolerance * 3:
                    matched_key = key
                    break
            
            if matched_key:
                pixel_color_dict[matched_key].append(Vector2(x,y))
            else:
                var pixel_color = "#" + str(pixel.to_html(false))
                pixel_color_dict[pixel_color] = [Vector2(x,y)]
    return pixel_color_dict

内容的提问来源于stack exchange,提问作者Mike Twain

火山引擎 最新活动