Files
test2/intern/cycles/scene/light_tree_debug.cpp

328 lines
10 KiB
C++

/* SPDX-FileCopyrightText: 2011-2025 Blender Foundation
*
* SPDX-License-Identifier: Apache-2.0 */
#include "scene/light_tree_debug.h"
#include "scene/light.h"
#include "scene/light_tree.h"
#include "scene/object.h"
#include "scene/scene.h"
#include "util/path.h"
#include "util/string.h"
CCL_NAMESPACE_BEGIN
static string get_node_id(const LightTreeNode &node)
{
return string_printf("node@%p", &node);
}
static string get_emitter_id(const LightTreeEmitter &emitter)
{
return string_printf("emitter@%p", &emitter);
}
static string set_membership_str(const uint64_t set_membership)
{
if (set_membership == ~uint64_t(0)) {
return "ALL";
}
return std::to_string(set_membership);
}
static void recursive_print_node(FILE *file, const LightTreeNode &node)
{
int field = 0;
string label = string_printf("<f%d> node @%p", field++, &node);
if (node.is_instance()) {
label += string_printf("| <f%d> instance", field++);
}
if (node.is_leaf()) {
label += string_printf("| <f%d> leaf", field++);
}
if (node.is_inner()) {
label += string_printf("| <f%d> inner", field++);
}
if (node.is_distant()) {
label += string_printf("| <f%d> distant", field++);
}
if (node.light_link.set_membership == ~uint64_t(0)) {
label += string_printf("| <f%d> set membership:ALL", field++);
}
else {
label += string_printf("| <f%d> set membership:%s",
field++,
set_membership_str(node.light_link.set_membership).c_str());
}
label += string_printf(
"| <f%d> shareable:%s", field++, node.light_link.shareable ? "True" : "False");
if (node.is_inner()) {
label += string_printf("| <left> left");
label += string_printf("| <right> right");
}
else if (node.is_leaf()) {
label += string_printf("| <emitters> emitters");
}
fprintf(file, "\"%s\" [\n", get_node_id(node).c_str());
fprintf(file, " label = \"%s\"\n", label.c_str());
fprintf(file, " shape = \"record\"\n");
fprintf(file, "];\n");
if (node.is_inner()) {
const LightTreeNode &left_node = *node.get_inner().children[LightTree::left];
const LightTreeNode &right_node = *node.get_inner().children[LightTree::right];
recursive_print_node(file, left_node);
recursive_print_node(file, right_node);
}
}
static void print_emitters(FILE *file, const Scene &scene, const LightTree &tree)
{
const size_t num_emitters = tree.num_emitters();
const LightTreeEmitter *emitters = tree.get_emitters();
for (size_t i = 0; i < num_emitters; ++i) {
const LightTreeEmitter &emitter = emitters[i];
int field = 0;
string label = string_printf("<f%d> emitter %s", field++, std::to_string(i).c_str());
/* Emitter details (type, object or light name). */
const Object &object = *scene.objects[emitter.object_id];
if (emitter.is_light()) {
label += string_printf("|<f%d> light", field++);
}
else if (emitter.is_triangle()) {
label += string_printf("|<f%d> triangle", field++);
}
else if (emitter.is_mesh()) {
label += string_printf("|<f%d> mesh", field++);
}
label += string_printf("|<f%d> %s", field++, object.name.c_str());
/* Light linking. */
if (emitter.light_set_membership == ~uint64_t(0)) {
label += string_printf("|<f%d> set membership:ALL", field++);
}
else {
label += string_printf("|<f%d> set membership:%s",
field++,
set_membership_str(emitter.light_set_membership).c_str());
}
/* Bounding box. */
label += string_printf("|<f%d> bbox.min (%f %f %f)",
field++,
double(emitter.measure.bbox.min.x),
double(emitter.measure.bbox.min.y),
double(emitter.measure.bbox.min.z));
label += string_printf("|<f%d> bbox.max (%f %f %f)",
field++,
double(emitter.measure.bbox.max.x),
double(emitter.measure.bbox.max.y),
double(emitter.measure.bbox.max.z));
/* Orientation bounds. */
label += string_printf("|<f%d> bcone.axis (%f %f %f)",
field++,
double(emitter.measure.bcone.axis.x),
double(emitter.measure.bcone.axis.y),
double(emitter.measure.bcone.axis.z));
label += string_printf("|<f%d> theta_o %f, theta_e %f",
field++,
double(emitter.measure.bcone.theta_o),
double(emitter.measure.bcone.theta_e));
/* Print node to the file. */
fprintf(file, "\"%s\" [\n", get_emitter_id(emitter).c_str());
fprintf(file, " label = \"%s\"\n", label.c_str());
fprintf(file, " shape = \"record\"\n");
fprintf(file, "];\n");
}
}
static void recursive_print_node_relations(FILE *file,
const LightTree &tree,
const LightTreeNode &node,
int &relation_id)
{
const string from_node_id = get_node_id(node);
if (node.is_leaf() || node.is_distant()) {
const LightTreeEmitter *emitters = tree.get_emitters();
for (int i = 0; i < node.get_leaf().num_emitters; i++) {
const LightTreeEmitter &emitter = emitters[node.get_leaf().first_emitter_index + i];
fprintf(file,
"\"%s\":<emitters> -> \"%s\":f0 [ id = %d ];\n",
from_node_id.c_str(),
get_emitter_id(emitter).c_str(),
relation_id++);
}
return;
}
if (!node.is_inner()) {
return;
}
const LightTreeNode &left_node = *node.get_inner().children[LightTree::left];
const LightTreeNode &right_node = *node.get_inner().children[LightTree::right];
const string left_node_id = get_node_id(left_node);
const string right_node_id = get_node_id(right_node);
fprintf(file,
"\"%s\":left -> \"%s\":f0 [ id = %d ];\n",
from_node_id.c_str(),
left_node_id.c_str(),
relation_id++);
fprintf(file,
"\"%s\":right -> \"%s\":f0 [ id = %d ];\n",
from_node_id.c_str(),
right_node_id.c_str(),
relation_id++);
recursive_print_node_relations(file, tree, left_node, relation_id);
recursive_print_node_relations(file, tree, right_node, relation_id);
}
void light_tree_plot_to_file(const Scene &scene,
const LightTree &tree,
const LightTreeNode &root_node,
const string &filename)
{
FILE *file = path_fopen(filename, "w");
if (!file) {
return;
}
int relation_id = 0;
fprintf(file, "digraph g {\n");
fprintf(file, "graph [\n");
fprintf(file, " rankdir = \"LR\"\n");
fprintf(file, "];\n");
recursive_print_node(file, root_node);
print_emitters(file, scene, tree);
recursive_print_node_relations(file, tree, root_node, relation_id);
fprintf(file, "}\n");
fclose(file);
}
static string get_knode_id(const KernelLightTreeNode &knode)
{
return string_printf("knode@%p", &knode);
}
static void recursive_print_knode(FILE *file,
const uint knode_index,
const KernelLightTreeNode *knodes,
int &relation_id)
{
const KernelLightTreeNode &knode = knodes[knode_index];
/* The distant node is also considered o leaf node. */
const bool is_leaf = knode.type >= LIGHT_TREE_LEAF;
const bool is_inner = !is_leaf;
assert(!is_inner || knode.type != LIGHT_TREE_INSTANCE);
int field = 0;
string label = string_printf("<f%d> knode %u", field++, knode_index);
/* Bounding box. */
label += string_printf("|<f%d> min (%f %f %f)",
field++,
double(knode.bbox.min.x),
double(knode.bbox.min.y),
double(knode.bbox.min.z));
label += string_printf("|<f%d> max (%f %f %f)",
field++,
double(knode.bbox.max.x),
double(knode.bbox.max.y),
double(knode.bbox.max.z));
/* Orientation bounds. */
label += string_printf("|<f%d> bcone.axis (%f %f %f)",
field++,
double(knode.bcone.axis.x),
double(knode.bcone.axis.y),
double(knode.bcone.axis.z));
label += string_printf("|<f%d> theta_o %f, theta_e %f",
field++,
double(knode.bcone.theta_o),
double(knode.bcone.theta_e));
label += string_printf("|<f%d> energy %f", field++, knode.energy);
if (is_leaf) {
label += string_printf("|<f%d> first emitter %d", field++, knode.leaf.first_emitter);
label += string_printf("|<f%d> num emitters %d", field++, knode.num_emitters);
}
label += string_printf("|<f%d> bit trail %u", field++, knode.bit_trail);
label += string_printf("|<f%d> bit skip %d", field++, int(knode.bit_skip));
if (is_inner) {
label += string_printf("| <left> left");
label += string_printf("| <right> right");
}
const string knode_id = get_knode_id(knode);
/* Print node to the file. */
fprintf(file, "\"%s\" [\n", knode_id.c_str());
fprintf(file, " label = \"%s\"\n", label.c_str());
fprintf(file, " shape = \"record\"\n");
fprintf(file, "];\n");
/* Print relations. */
if (is_inner) {
recursive_print_knode(file, knode.inner.left_child, knodes, relation_id);
recursive_print_knode(file, knode.inner.right_child, knodes, relation_id);
fprintf(file,
"\"%s\":left -> \"%s\":f0 [ id = %d ];\n",
knode_id.c_str(),
get_knode_id(knodes[knode.inner.left_child]).c_str(),
relation_id++);
fprintf(file,
"\"%s\":right -> \"%s\":f0 [ id = %d ];\n",
knode_id.c_str(),
get_knode_id(knodes[knode.inner.right_child]).c_str(),
relation_id++);
}
}
void klight_tree_plot_to_file(uint root, const KernelLightTreeNode *knodes, const string &filename)
{
FILE *file = path_fopen(filename, "w");
if (!file) {
return;
}
int relation_id = 0;
fprintf(file, "digraph g {\n");
fprintf(file, "graph [\n");
fprintf(file, " rankdir = \"LR\"\n");
fprintf(file, "];\n");
recursive_print_knode(file, root, knodes, relation_id);
fprintf(file, "}\n");
fclose(file);
}
CCL_NAMESPACE_END