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

Unity点云可视化C#性能优化:避免重复绘制同色点,增大粒子尺寸

Efficiently Avoid Duplicate Particles in Unity Point Cloud Visualization

Hey there! Let's tackle that slow duplicate particle issue you're facing. Your original approach with Array.IndexOf() is slow because it does a linear search every time—no wonder a 50x50 grid takes over a minute. Let's look at two way better options that'll keep your processing time close to the 1-2 seconds you're used to.

Option 1: Use a Dictionary for O(1) Lookups

This is the most memory-efficient solution, especially when your image has lots of repeated colors. We'll map each unique RGB color to its occurrence count using a Dictionary—lookups here are near-instant (O(1) time complexity), so even large images won't bog down.

First, define a simple struct to hold our count (or you could just use an int directly, but a struct keeps it clean):

struct ParticleOccurrence
{
    public int Count;
}

Then process your pixels and build the map:

// Assume you've already loaded your texture and grabbed its pixels
Texture2D texture = LoadYourTextureHere();
Color32[] pixels = texture.GetPixels32();

// Initialize our dictionary to track color counts
Dictionary<Color32, ParticleOccurrence> colorCountMap = new Dictionary<Color32, ParticleOccurrence>();

foreach (Color32 pixel in pixels)
{
    // Skip transparent pixels if you don't want them in your point cloud
    if (pixel.a == 0) continue;

    if (colorCountMap.TryGetValue(pixel, out ParticleOccurrence occurrence))
    {
        // Color exists—increase its count
        occurrence.Count++;
        colorCountMap[pixel] = occurrence;
    }
    else
    {
        // New color—add it to the map with a count of 1
        colorCountMap.Add(pixel, new ParticleOccurrence { Count = 1 });
    }
}

// Now create particles only for unique colors, scaling size by count
foreach (var entry in colorCountMap)
{
    Color32 color = entry.Key;
    int count = entry.Value.Count;

    // Convert RGB values to world position (adjust scaling as needed)
    Vector3 position = new Vector3(color.r / 255f, color.g / 255f, color.b / 255f);

    // Spawn your particle prefab
    GameObject particle = Instantiate(yourParticlePrefab, position, Quaternion.identity);
    
    // Adjust particle size—use Mathf.Sqrt(count) to avoid massive sizes for super frequent colors
    ParticleSystem particleSystem = particle.GetComponent<ParticleSystem>();
    var mainSettings = particleSystem.main;
    mainSettings.startSize = 0.1f * Mathf.Sqrt(count);
}

Why this works:

  • Speed: Dictionary lookups are way faster than linear searches. Processing a 50x50 grid will take milliseconds, not minutes.
  • Memory: We only store entries for colors that actually exist in your image, not all 16 million possible RGB combinations.

If you want a tiny extra speed boost, you can convert the RGB values into a single integer key instead of using Color32:

// Convert RGB to a unique integer key
int colorKey = (pixel.r << 16) | (pixel.g << 8) | pixel.b;

Then use Dictionary<int, ParticleOccurrence> instead—this avoids any overhead from hashing the Color32 struct, though the difference is minimal for most cases.

Option 2: 3D Integer Array for Direct Indexing

If your image has a wide spread of colors (close to the full 16 million possible RGB values), a 3D array might be faster than a dictionary—no hash calculations needed, just direct index access. And don't worry about the "huge overhead" you thought: a int[256,256,256] uses only ~64MB of memory (256256256 = 16,777,216 integers, each 4 bytes), which is trivial for modern systems.

Here's how to implement it:

Texture2D texture = LoadYourTextureHere();
Color32[] pixels = texture.GetPixels32();

// Initialize the 3D array to track counts (starts at 0 for all entries)
int[,,] colorCounts = new int[256, 256, 256];

foreach (Color32 pixel in pixels)
{
    if (pixel.a == 0) continue;
    // Directly increment the count for this RGB combination
    colorCounts[pixel.r, pixel.g, pixel.b]++;
}

// Iterate through the array to create particles
for (int r = 0; r < 256; r++)
{
    for (int g = 0; g < 256; g++)
    {
        for (int b = 0; b < 256; b++)
        {
            int count = colorCounts[r, g, b];
            // Skip colors that don't appear in the image
            if (count == 0) continue;

            Vector3 position = new Vector3(r / 255f, g / 255f, b / 255f);
            GameObject particle = Instantiate(yourParticlePrefab, position, Quaternion.identity);
            
            ParticleSystem particleSystem = particle.GetComponent<ParticleSystem>();
            var mainSettings = particleSystem.main;
            mainSettings.startSize = 0.1f * Mathf.Sqrt(count);
        }
    }
}

Why this works:

  • Raw Speed: Direct array access is faster than dictionary lookups for high-color-variety images.
  • Simplicity: No need to deal with dictionary logic—just increment and iterate.

Why Your Original List/Array Approach Was Slow

Using List.Contains() or Array.IndexOf() means checking every existing particle every time you process a new pixel. For a 50x50 grid, that's 2500 pixels, each potentially checking up to 2500 existing particles—total of 6 million operations. The dictionary or 3D array cuts that down to 2500 near-instant checks instead.

Both of these options will keep your processing time well within your 10x overhead limit—you might even see faster overall performance because you're spawning way fewer particles (instantiating GameObjects is one of the more costly operations in Unity!).

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:18:46