I have been trying for some time to implement an octree system in a class project aimed at 3D image rendering optimization. But I always block in the implementation of this one, indeed I have a basic class center that I must adapt to an octree system and I have an Octree and OctreeNOde class which implements the octree system and the creation of child nodes. But I still get code errors.
The goal is to divide the texture into octree to optimize rendering. But I get errors on methods traverse:
CalculateAverageColor of type Method 'CalculateAverageColor' has 2 parameter(s) but is invoked with 1 argument(s),Method 'Traverse' has 2 parameter(s) but is invoked with 1 argument (s).
I am showing my 3 classes here:
using ...
public class Center : MonoBehaviour
{
private float _divisionResolution;
public int Channel { get; set; } = 0;
public int nbChannel;
public int[] listChannel = {1};
private int _nbChannelGlobal = 1;
public int sizeChannel;
public IDictionary<int, byte[]> lut = new Dictionary<int, byte[]>();
internal Data _data;
private int _nbOfSliceUsed;
private bool _textureCreated = false;
public bool lutChange = true;
public int[] Size { get; set; }
public Texture3D Texture { get; set; }
private Octree _colorOctree;
public OctreeNode octree;
public void SetData(Data data, float divisionResolution=1, int nbChannelsGlobal=1)
{
nbChannel = data._matriceImages[0].channels();
sizeChannel = data._matriceImages[0].depth();
// Extraction des données.
_data = data;
_nbChannelGlobal = nbChannelsGlobal;
// Initialisation de la taille de la matrice de référence pour choisir les plan de coupe.
transform.localScale = new Vector3((float)_data.Size["width"]/_data.Size.Values.Max(), (float)_data.Size["height"]/_data.Size.Values.Max(),
(float)_data.Size["depth"]/_data.Size.Values.Max());
// Créer l'octree
Vector3Int dimensions = new Vector3Int(_data.Size["width"], _data.Size["height"], _data.Size["depth"]);
Vector3Int position = Vector3Int.zero;
_colorOctree = new Octree(position, dimensions);
// Calculer la couleur moyenne pour chaque noeud de l'octree
_colorOctree.CalculateAverageColor((node, color) =>
{
_data.SetPixelTexture(Texture, nbChannel, _nbChannelGlobal, listChannel, lut);
Texture.Apply(false, true);
color.r = 0f;
color.g = 0f;
color.b = 0f;
int count = 0;
for (int z = node.Position.z; z < node.Position.z + node.Dimensions.z; z++)
{
for (int y = node.Position.y; y < node.Position.y + node.Dimensions.y; y++)
{
for (int x = node.Position.x; x < node.Position.x + node.Dimensions.x; x++)
{
count++;
color.r += Texture.GetPixel(x, y, z).r;
color.g += Texture.GetPixel(x, y, z).g;
color.b += Texture.GetPixel(x, y, z).b;
}
}
}
color /= count;
});
}
private void Update()
{
if ((_data != null && !_textureCreated) && Keyboard.current.kKey.isPressed || (lutChange && _data != null))
{
CreateTexture();
_textureCreated = true;
lutChange = false;
}
}
private void CreateTexture()
{
const TextureFormat format = TextureFormat.RGB24;
// Création de la texture.
Texture = new Texture3D(_data.Size["width"], _data.Size["height"], _data.Size["depth"], format, false);
// Update de l'octree avec la nouvelle texture
_colorOctree.Update(new Vector3Int(0, 0, 0),
new Vector3Int(_data.Size["width"], _data.Size["height"], _data.Size["depth"]),
(node, color) =>
{
color.r = 0f;
color.g = 0f;
color.b = 0f;
int count = 0;
for (int z = node.position.z; z < node.position.z + node.dimensions.z; z++)
{
for (int y = node.position.y; y < node.position.y + node.dimensions.y; y++)
{
for (int x = node.position.x; x < node.position.x + node.dimensions.x; x++)
{
count++;
color.r += Texture.GetPixel(x, y, z).r;
color.g += Texture.GetPixel(x, y, z).g;
color.b += Texture.GetPixel(x, y, z).b;
}
}
}
color /= count;
});
// Définir les données de la texture
_colorOctree.Traverse((node, color) =>
{
int startIndex = ((node.position.z * Texture.width + node.Position.y) * Texture.width + node.Position.x) * 3;
int count = 0;
for (int z = node.Position.z; z < node.Position.z + node.Dimensions.z; z++)
{
for (int y = node.Position.y; y < node.Position.y + node.Dimensions.y; y++)
{
for (int x = node.Position.x; x < node.Position.x + node.Dimensions.x; x++)
{
int index = ((z * Texture.width + y) * Texture.width + x) * 3;
Texture.SetPixel(x, y, z, color);
count++;
}
}
}
Texture.Apply(false, true);
});
// Aplliquer la texture au matériel
GetComponent<Renderer>().material.SetTexture("_Volume", Texture);
}
}
using ...
public class Octree
{
private OctreeNode rootNode;
public Octree(Texture3D texture)
{
// Déterminer les dimensions du nœud racine
Vector3Int dimensions = new Vector3Int(texture.width, texture.height, texture.depth);
rootNode = new OctreeNode(Vector3Int.zero, dimensions);
// Calculer la couleur moyenne pour chaque nœud
CalculateAverageColors(rootNode, texture);
}
public Octree(Vector3Int position, Vector3Int dimensions)
{
throw new System.NotImplementedException();
}
private void CalculateAverageColors(OctreeNode node, Texture3D texture)
{
// S'il s'agit d'un nœud feuille, calculez sa couleur moyenne et retournez la
if (node.IsLeaf())
{
node.AverageColor = CalculateAverageColor(node.Bounds, texture);
return;
}
// Sinon, calculez la couleur moyenne pour chaque nœud enfant
foreach (OctreeNode childNode in node.Children)
{
CalculateAverageColors(childNode, texture);
}
// Calculer la couleur moyenne de ce nœud comme la moyenne des couleurs de ses enfants
node.AverageColor = new Color();
foreach (OctreeNode childNode in node.Children)
{
node.AverageColor += childNode.AverageColor;
}
node.AverageColor /= node.Children.Count();
}
public Color CalculateAverageColor(Bounds bounds, Texture3D texture)
{
// Calculer la couleur moyenne de la texture
Color averageColor = new Color();
int count = 0;
for (int x = (int)bounds.min.x; x < bounds.max.x; x++)
{
for (int y = (int)bounds.min.y; y < bounds.max.y; y++)
{
for (int z = (int)bounds.min.z; z < bounds.max.z; z++)
{
averageColor += texture.GetPixel(x, y, z);
count++;
}
}
}
averageColor /= count;
return averageColor;
}
public List<OctreeNode> GetNodesIntersectingBounds(Bounds bounds)
{
// Create a list of all nodes in the tree that intersect the given bounds
List<OctreeNode> nodes = new List<OctreeNode>();
Traverse(rootNode, node =>
{
if (node.Bounds.Intersects(bounds))
{
nodes.Add(node);
}
});
return nodes;
}
public void Traverse(OctreeNode node, System.Action<OctreeNode> action)
{
// Effectuez l'action donnée sur ce nœud, puis effectuez-la de manière récursive sur ses enfants
action(node);
foreach (OctreeNode childNode in node.Children)
{
Traverse(childNode, action);
}
}
public void Update(Vector3Int min, Vector3Int max, System.Action<OctreeNode, Color> action)
{
// Mettre à jour les couleurs moyennes de tous les nœuds
Traverse(rootNode, node =>
{
if (node.Bounds.Intersects(new Bounds(min, max)))
{
action(node, CalculateAverageColor(node.Bounds, node.Texture));
}
});
}
}
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class OctreeNode
{
public Vector3Int position;
public Vector3Int dimensions;
private List<OctreeNode> children;
private Color averageColor;
private readonly List<OctreeNode> _children = null;
public OctreeNode(Vector3Int position, Vector3Int dimensions)
{
this.position = position;
this.dimensions = dimensions;
this.children = new List<OctreeNode>();
_children = Enumerable.Repeat<OctreeNode>(null, 8).ToList();
// Créer 8 enfants
if (!IsLeaf())
{
Subdivide();
}
}
public Color AverageColor { get; set; }
public Bounds Bounds { get; set; }
public IEnumerable<OctreeNode> Children { get { return children; } }
public Texture3D Texture { get; set; }
private void Subdivide()
{
int childSize = dimensions.x / 2;
for (int x = 0; x <= 1; x++)
{
for (int y = 0; y <= 1; y++)
{
for (int z = 0; z <= 1; z++)
{
Vector3Int childPosition = position + new Vector3Int(x * childSize, y * childSize, z * childSize);
OctreeNode childNode = new OctreeNode(childPosition, new Vector3Int(childSize, childSize, childSize));
children.Add(childNode);
}
}
}
}
public void CalculateAverageColor(Texture3D texture)
{
if (IsLeaf())
{
// Calcul de la couleur moyenne
Color sum = Color.black;
int count = 0;
for (int x = position.x; x < position.x + dimensions.x; x++)
{
for (int y = position.y; y < position.y + dimensions.y; y++)
{
for (int z = position.z; z < position.z + dimensions.z; z++)
{
sum += texture.GetPixel(x, y, z);
count++;
}
}
}
averageColor = sum / count;
}
else
{
// calcul de la couleur moyenne des enfants
Color sum = Color.black;
int count = 0;
foreach (OctreeNode child in children)
{
child.CalculateAverageColor(texture);
sum += child.averageColor;
count++;
}
averageColor = sum / count;
}
}
public bool IsLeaf()
{
return dimensions.x == 1;
}
public Vector3Int GetPosition()
{
return position;
}
public Vector3Int GetDimensions()
{
return dimensions;
}
public List<OctreeNode> GetChildren()
{
return children;
}
public Color GetAverageColor()
{
return averageColor;
}
}