You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何按特定顺序基于黑白图在3D场景中生成物体

实现特定顺序遍历像素生成物体的方案

核心思路

要按特定顺序生成物体,本质是修改像素遍历的循环逻辑——不再用固定的x从左到右、y从下到上的嵌套循环,而是先按目标顺序生成所有像素坐标的序列,再依次遍历这个序列判断是否生成物体。


常见特定顺序的实现方法

1. 蛇形遍历(左右交替逐行)

如果目标是逐行扫描,奇数行从左到右、偶数行从右到左(类似蛇形路径),可以直接修改循环方向:

using Dreamteck.Splines;
using System.Collections.Generic;
using UnityEngine;

[ExecuteInEditMode]
public class ReadImage : MonoBehaviour
{
    public Texture2D spawnMap;
    public float spawnSpacing = 1.0f;
    public Vector2 startPosition = Vector2.zero;
    public bool canSpawn;

    [SerializeField] GameObject cubePrefab;

    private void OnEnable()
    {
        if (canSpawn)
        {
            SpawnObjects();
        }
    }

    void SpawnObjects()
    {
        // 先清除已有生成物体,避免重复
        foreach (Transform child in transform) DestroyImmediate(child);
        
        int index = 0;
        for (int y = 0; y < spawnMap.height; y++)
        {
            // 偶数行从左到右,奇数行从右到左
            if (y % 2 == 0)
            {
                for (int x = 0; x < spawnMap.width; x++)
                {
                    SpawnIfWhite(x, y, ref index);
                }
            }
            else
            {
                for (int x = spawnMap.width - 1; x >= 0; x--)
                {
                    SpawnIfWhite(x, y, ref index);
                }
            }
        }
    }

    // 提取重复逻辑,简化代码
    void SpawnIfWhite(int x, int y, ref int index)
    {
        Color pixelColor = spawnMap.GetPixel(x, y);
        if (pixelColor == Color.white)
        {
            Vector3 worldPos = new Vector3(x * spawnSpacing, 0, y * spawnSpacing);
            index++;
            Instantiate(cubePrefab, worldPos, Quaternion.identity, transform);
        }
    }
}

2. 螺旋形遍历

如果目标是从角落或中心向外螺旋扫描,需要先生成螺旋路径的坐标列表,再遍历生成:

// 仅修改SpawnObjects和新增GenerateSpiralCoords方法,其余代码同上
void SpawnObjects()
{
    foreach (Transform child in transform) DestroyImmediate(child);
    
    int index = 0;
    List<Vector2Int> spiralCoords = GenerateSpiralCoords(spawnMap.width, spawnMap.height);
    
    foreach (var coord in spiralCoords)
    {
        SpawnIfWhite(coord.x, coord.y, ref index);
    }
}

List<Vector2Int> GenerateSpiralCoords(int width, int height)
{
    List<Vector2Int> coords = new List<Vector2Int>();
    int left = 0, right = width - 1;
    int top = height - 1, bottom = 0;

    while (left <= right && bottom <= top)
    {
        // 从左到右遍历顶部行
        for (int x = left; x <= right; x++) coords.Add(new Vector2Int(x, top));
        top--;
        // 从上到下遍历右侧列
        for (int y = top; y >= bottom; y--) coords.Add(new Vector2Int(right, y));
        right--;
        // 从右到左遍历底部行(剩余行有效时)
        if (bottom <= top)
        {
            for (int x = right; x >= left; x--) coords.Add(new Vector2Int(x, bottom));
            bottom++;
        }
        // 从下到上遍历左侧列(剩余列有效时)
        if (left <= right)
        {
            for (int y = bottom; y <= top; y++) coords.Add(new Vector2Int(left, y));
            left++;
        }
    }
    return coords;
}

3. 自定义路径(匹配参考图的特定顺序)

如果参考图的顺序是完全自定义的(比如特定折线、区域优先),可以用灰度图标记顺序:

  1. 把参考图改成灰度图:路径上的像素灰度从0(最先)到255(最后)渐变
  2. 按灰度值排序像素坐标,再遍历生成:
// 仅修改SpawnObjects方法,其余代码同上
void SpawnObjects()
{
    foreach (Transform child in transform) DestroyImmediate(child);
    
    int index = 0;
    List<(Vector2Int coord, float orderValue)> pixelOrder = new List<(Vector2Int, float)>();

    // 遍历所有像素,记录坐标和对应的灰度值(灰度越小越先)
    for (int x = 0; x < spawnMap.width; x++)
    {
        for (int y = 0; y < spawnMap.height; y++)
        {
            Color pixelColor = spawnMap.GetPixel(x, y);
            float grayValue = (pixelColor.r + pixelColor.g + pixelColor.b) / 3f;
            pixelOrder.Add((new Vector2Int(x, y), grayValue));
        }
    }

    // 按灰度值从小到大排序,匹配参考图顺序
    pixelOrder.Sort((a, b) => a.orderValue.CompareTo(b.orderValue));

    // 遍历排序后的列表生成物体
    foreach (var item in pixelOrder)
    {
        Color pixelColor = spawnMap.GetPixel(item.coord.x, item.coord.y);
        if (pixelColor == Color.white)
        {
            Vector3 worldPos = new Vector3(item.coord.x * spawnSpacing, 0, item.coord.y * spawnSpacing);
            index++;
            Instantiate(cubePrefab, worldPos, Quaternion.identity, transform);
        }
    }
}

注意事项

  • 若需要完全匹配参考图的自定义路径,优先用第三种灰度图标记的方法,精度最高;
  • EditMode下运行时,务必先清除已有生成物体,避免重复实例化;
  • 判断白色像素时可以加容差(比如pixelColor.grayscale > 0.9f),避免因图像压缩导致的纯白判断失效。

内容的提问来源于stack exchange,提问作者Sachin Kankane

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 11:44:53