Commit: b323b40af648c2a46bf1193c16ecc35916f26dba Author: Jeffrey Liu Date: Tue Jun 21 00:05:55 2022 -0400 Branches: soc-2022-many-lights-sampling https://developer.blender.org/rBb323b40af648c2a46bf1193c16ecc35916f26dba
Cycles: support emissive triangles in light tree =================================================================== M intern/cycles/kernel/light/light_tree.h M intern/cycles/kernel/textures.h M intern/cycles/kernel/types.h M intern/cycles/scene/light.cpp M intern/cycles/scene/light_tree.cpp M intern/cycles/scene/scene.cpp M intern/cycles/scene/scene.h =================================================================== diff --git a/intern/cycles/kernel/light/light_tree.h b/intern/cycles/kernel/light/light_tree.h index 1c9684e006c..ebc6d8280a2 100644 --- a/intern/cycles/kernel/light/light_tree.h +++ b/intern/cycles/kernel/light/light_tree.h @@ -77,29 +77,22 @@ ccl_device float light_tree_emitter_importance(KernelGlobals kg, const float3 N, int emitter_index) { - ccl_global const KernelLightDistribution *kdistribution = &kernel_tex_fetch(__light_distribution, - emitter_index); - const int prim = kdistribution->prim; + ccl_global const KernelLightTreeEmitter *kemitter = &kernel_tex_fetch(__light_tree_emitters, + emitter_index); - if (prim >= 0) { - /* to-do: handle case for mesh lights. */ - } - - /* If we're not at a mesh light, then we should be at a point, spot, or area light. */ - const int lamp = -prim - 1; - const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp); - const float radius = klight->spot.radius; - const float3 bbox_min = make_float3( - klight->co[0] - radius, klight->co[1] - radius, klight->co[2] - radius); - const float3 bbox_max = make_float3( - klight->co[0] + radius, klight->co[1] + radius, klight->co[2] + radius); - const float3 bcone_axis = make_float3( - klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]); - const float3 rgb_strength = make_float3( - klight->strength[0], klight->strength[1], klight->strength[2]); + /* Convert the data from the struct into float3 for calculations. */ + const float3 bbox_min = make_float3(kemitter->bounding_box_min[0], + kemitter->bounding_box_min[1], + kemitter->bounding_box_min[2]); + const float3 bbox_max = make_float3(kemitter->bounding_box_max[0], + kemitter->bounding_box_max[1], + kemitter->bounding_box_max[2]); + const float3 bcone_axis = make_float3(kemitter->bounding_cone_axis[0], + kemitter->bounding_cone_axis[1], + kemitter->bounding_cone_axis[2]); return light_tree_node_importance( - P, N, bbox_min, bbox_max, bcone_axis, M_PI_F, M_PI_2_F, linear_rgb_to_gray(kg, rgb_strength)); + P, N, bbox_min, bbox_max, bcone_axis, kemitter->theta_o, kemitter->theta_e, kemitter->energy); } ccl_device float light_tree_cluster_importance(KernelGlobals kg, @@ -193,10 +186,36 @@ ccl_device bool light_tree_sample(KernelGlobals kg, emitter_cdf += emitter_pdf; if (tree_u < emitter_cdf) { *pdf_factor *= emitter_pdf; - if (UNLIKELY(light_select_reached_max_bounces(kg, prim_index, bounce))) { + ccl_global const KernelLightDistribution *kdistribution = &kernel_tex_fetch(__light_distribution, + prim_index); + + /* to-do: this is the same code as light_distribution_sample, except the index is determined differently. + * Would it be better to refactor this into a separate function? */ + const int prim = kdistribution->prim; + + if (prim >= 0) { + /* Mesh light. */ + const int object = kdistribution->mesh_light.object_id; + + /* Exclude synthetic meshes from shadow catcher pass. */ + if ((path_flag & PATH_RAY_SHADOW_CATCHER_PASS) && + !(kernel_tex_fetch(__object_flag, object) & SD_OBJECT_SHADOW_CATCHER)) { + return false; + } + + const int shader_flag = kdistribution->mesh_light.shader_flag; + triangle_light_sample<in_volume_segment>(kg, prim, object, randu, randv, time, ls, P); + ls->shader |= shader_flag; + return (ls->pdf > 0.0f); + } + + const int lamp = -prim - 1; + + if (UNLIKELY(light_select_reached_max_bounces(kg, lamp, bounce))) { return false; } - return light_sample<in_volume_segment>(kg, prim_index, randu, randv, P, path_flag, ls); + + return light_sample<in_volume_segment>(kg, lamp, randu, randv, P, path_flag, ls); } } diff --git a/intern/cycles/kernel/textures.h b/intern/cycles/kernel/textures.h index 58f0a312d9a..b08409be7c7 100644 --- a/intern/cycles/kernel/textures.h +++ b/intern/cycles/kernel/textures.h @@ -62,6 +62,7 @@ KERNEL_TEX(float2, __light_background_conditional_cdf) /* light tree */ KERNEL_TEX(KernelLightTreeNode, __light_tree_nodes) +KERNEL_TEX(KernelLightTreeEmitter, __light_tree_emitters) /* particles */ KERNEL_TEX(KernelParticle, __particles) diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h index 069c179fc73..5a5e1bcc220 100644 --- a/intern/cycles/kernel/types.h +++ b/intern/cycles/kernel/types.h @@ -1526,6 +1526,27 @@ typedef struct KernelLightTreeNode { } KernelLightTreeNode; static_assert_align(KernelLightTreeNode, 16); +typedef struct KernelLightTreeEmitter { + /* Bounding box. */ + float bounding_box_min[3]; + float bounding_box_max[3]; + + /* Bounding cone. */ + float bounding_cone_axis[3]; + float theta_o; + float theta_e; + + /* Energy. */ + float energy; + + /* If this is positive, this is a triangle. Otherwise, it's a light source. */ + int prim_id; + + /* Padding. */ + int pad1, pad2, pad3; +} KernelLightTreeEmitter; +static_assert_align(KernelLightTreeEmitter, 16); + typedef struct KernelParticle { int index; float age; diff --git a/intern/cycles/scene/light.cpp b/intern/cycles/scene/light.cpp index e9407554cbe..7d07b3797ab 100644 --- a/intern/cycles/scene/light.cpp +++ b/intern/cycles/scene/light.cpp @@ -350,6 +350,7 @@ void LightManager::device_update_distribution(Device *, LightTree light_tree(light_prims, scene, 8); light_prims = light_tree.get_prims(); + /* First initialize the light tree's nodes. */ const vector<PackedLightTreeNode> &linearized_bvh = light_tree.get_nodes(); KernelLightTreeNode *light_tree_nodes = dscene->light_tree_nodes.alloc(linearized_bvh.size()); for (int index = 0; index < linearized_bvh.size(); index++) { @@ -374,8 +375,28 @@ void LightManager::device_update_distribution(Device *, light_tree_nodes[index].child_index = node.second_child_index; } } - dscene->light_tree_nodes.copy_to_device(); + + /* The light tree emitters store extra information about their bounds. */ + KernelLightTreeEmitter *light_tree_emitters = dscene->light_tree_emitters.alloc(num_distribution); + for (int index = 0; index < num_distribution; index++) { + LightTreePrimitive &prim = light_prims[index]; + BoundBox bbox = prim.calculate_bbox(scene); + OrientationBounds bcone = prim.calculate_bcone(scene); + float energy = prim.calculate_energy(scene); + + light_tree_emitters[index].energy = energy; + for (int i = 0; i < 3; i++) { + light_tree_emitters[index].bounding_box_min[i] = bbox.min[i]; + light_tree_emitters[index].bounding_box_max[i] = bbox.max[i]; + light_tree_emitters[index].bounding_cone_axis[i] = bcone.axis[i]; + } + light_tree_emitters[index].theta_o = bcone.theta_o; + light_tree_emitters[index].theta_e = bcone.theta_e; + + light_tree_emitters[index].prim_id = prim.prim_id; + } + dscene->light_tree_emitters.copy_to_device(); } /* triangles */ @@ -1099,6 +1120,7 @@ void LightManager::device_free(Device *, DeviceScene *dscene, const bool free_ba { /* to-do: check if the light tree member variables need to be wrapped in a conditional too*/ dscene->light_tree_nodes.free(); + dscene->light_tree_emitters.free(); dscene->light_distribution.free(); dscene->lights.free(); if (free_background) { diff --git a/intern/cycles/scene/light_tree.cpp b/intern/cycles/scene/light_tree.cpp index 22930586d43..252f15ab997 100644 --- a/intern/cycles/scene/light_tree.cpp +++ b/intern/cycles/scene/light_tree.cpp @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ +#include "scene/mesh.h" +#include "scene/object.h" #include "scene/light_tree.h" CCL_NAMESPACE_BEGIN @@ -62,7 +64,27 @@ BoundBox LightTreePrimitive::calculate_bbox(Scene *scene) const BoundBox bbox = BoundBox::empty; if (prim_id >= 0) { - /* to-do: handle mesh lights in the future. */ + Object *object = scene->objects[object_id]; + Mesh *mesh = static_cast<Mesh*>(object->get_geometry()); + Mesh::Triangle triangle = mesh->get_triangle(prim_id - mesh->prim_offset); + + float3 p[3] = {mesh->get_verts()[triangle.v[0]], + mesh->get_verts()[triangle.v[1]], + mesh->get_verts()[triangle.v[2]]}; + + /* instanced mesh lights have not applied their transform at this point. + * in this case, these points have to be transformed to get the proper + * spatial bound. */ + if (!mesh->transform_applied) { + const Transform &tfm = object->get_tfm(); + for (int i = 0; i < 3; i++) { + p[i] = transform_point(&tfm, p[i]); + } + } + + for (int i = 0; i < 3; i++) { + bbox.grow(p[i]); + } } else { Light *lamp = scene->lights[lamp_id]; @@ -102,7 +124,29 @@ OrientationBounds LightTreePrimitive::calculate_bcone(Scene *scene) const OrientationBounds bcone = OrientationBounds::empty; if (prim_id >= 0) { - /* to-do: handle mesh lights in the future. */ + Object *object = scene->objects[object_id]; + Mesh *mesh = static_cast<Mesh *>(object->get_geometry()); + Mesh::Triangle triangle = mesh->get_triangle(prim_id - mesh->prim_offset); + + float3 p[3] = {mesh->get_verts()[triangle.v[0]], + mesh->get_verts()[triangle.v[1]], + mesh->get_verts()[triangle.v[2]]}; + + /* instanced mesh lights have not applied their transform at this point. + * in this case, these points have to be transformed to get the proper + * spatial bound. */ + if (!mesh->transform_applied) { + const Transform &tfm = object->get_tfm( @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs