blender/intern/cycles/render/light.cpp
Sergey Sharybin c502114ee1 Cycles: Solve issues with auto-disabled MIS
There were two issues:

1. Memory leak: std:;erase does not call delete on the
   pointer (which is actually a good idea),

2. After MIS was disabled in viewport render there was
   no way to bring MIS back.

Now instead of removing light from the scene data we
kind of tagging it for an ignore. Possible cleanup
would be to add Light::is_enabled and use that instead
of passing weird and wonderful function arguments.
2016-02-06 20:43:44 +01:00

824 lines
24 KiB
C++

/*
* Copyright 2011-2013 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "background.h"
#include "device.h"
#include "integrator.h"
#include "film.h"
#include "light.h"
#include "mesh.h"
#include "object.h"
#include "scene.h"
#include "shader.h"
#include "util_foreach.h"
#include "util_progress.h"
#include "util_logging.h"
CCL_NAMESPACE_BEGIN
static void shade_background_pixels(Device *device, DeviceScene *dscene, int res, vector<float3>& pixels, Progress& progress)
{
/* create input */
int width = res;
int height = res;
device_vector<uint4> d_input;
device_vector<float4> d_output;
uint4 *d_input_data = d_input.resize(width*height);
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
float u = x/(float)width;
float v = y/(float)height;
uint4 in = make_uint4(__float_as_int(u), __float_as_int(v), 0, 0);
d_input_data[x + y*width] = in;
}
}
/* compute on device */
d_output.resize(width*height);
memset((void*)d_output.data_pointer, 0, d_output.memory_size());
device->const_copy_to("__data", &dscene->data, sizeof(dscene->data));
device->mem_alloc(d_input, MEM_READ_ONLY);
device->mem_copy_to(d_input);
device->mem_alloc(d_output, MEM_WRITE_ONLY);
DeviceTask main_task(DeviceTask::SHADER);
main_task.shader_input = d_input.device_pointer;
main_task.shader_output = d_output.device_pointer;
main_task.shader_eval_type = SHADER_EVAL_BACKGROUND;
main_task.shader_x = 0;
main_task.shader_w = width*height;
main_task.num_samples = 1;
main_task.get_cancel = function_bind(&Progress::get_cancel, &progress);
/* disabled splitting for now, there's an issue with multi-GPU mem_copy_from */
list<DeviceTask> split_tasks;
main_task.split(split_tasks, 1, 128*128);
foreach(DeviceTask& task, split_tasks) {
device->task_add(task);
device->task_wait();
device->mem_copy_from(d_output, task.shader_x, 1, task.shader_w, sizeof(float4));
}
device->mem_free(d_input);
device->mem_free(d_output);
d_input.clear();
float4 *d_output_data = reinterpret_cast<float4*>(d_output.data_pointer);
pixels.resize(width*height);
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
pixels[y*width + x].x = d_output_data[y*width + x].x;
pixels[y*width + x].y = d_output_data[y*width + x].y;
pixels[y*width + x].z = d_output_data[y*width + x].z;
}
}
}
/* Light */
Light::Light()
{
type = LIGHT_POINT;
co = make_float3(0.0f, 0.0f, 0.0f);
dir = make_float3(0.0f, 0.0f, 0.0f);
size = 0.0f;
axisu = make_float3(0.0f, 0.0f, 0.0f);
sizeu = 1.0f;
axisv = make_float3(0.0f, 0.0f, 0.0f);
sizev = 1.0f;
map_resolution = 512;
spot_angle = M_PI_4_F;
spot_smooth = 0.0f;
cast_shadow = true;
use_mis = false;
use_diffuse = true;
use_glossy = true;
use_transmission = true;
use_scatter = true;
shader = 0;
samples = 1;
max_bounces = 1024;
is_portal = false;
}
void Light::tag_update(Scene *scene)
{
scene->light_manager->need_update = true;
}
bool Light::has_contribution(Scene *scene)
{
if(is_portal) {
return false;
}
if(type == LIGHT_BACKGROUND) {
return true;
}
return scene->shaders[shader]->has_surface_emission;
}
/* Light Manager */
LightManager::LightManager()
{
need_update = true;
use_light_visibility = false;
}
LightManager::~LightManager()
{
}
bool LightManager::skip_background_light(Device *device, Scene *scene)
{
/* Check whether we've got portals. */
bool has_portal = false;
foreach(Light *light, scene->lights) {
if(light->is_portal) {
has_portal = true;
break;
}
}
/* Ignore background light if:
* - If unsupported on a device
* - If we don't need it (no HDRs etc.)
*/
foreach(Light *light, scene->lights) {
if(light->type == LIGHT_BACKGROUND) {
Shader *shader = scene->shaders[scene->background->shader];
bool auto_disable_mis = (!has_portal && !shader->has_surface_spatial_varying);
if(!(device->info.advanced_shading) || auto_disable_mis) {
VLOG(1) << "Background MIS has been disabled.\n";
return true;
}
break;
}
}
return false;
}
void LightManager::device_update_distribution(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
{
progress.set_status("Updating Lights", "Computing distribution");
/* count */
size_t num_lights = 0;
size_t num_background_lights = 0;
size_t num_triangles = 0;
bool background_mis = false;
foreach(Light *light, scene->lights) {
if(light->has_contribution(scene))
num_lights++;
}
foreach(Object *object, scene->objects) {
Mesh *mesh = object->mesh;
bool have_emission = false;
/* skip if we are not visible for BSDFs */
if(!(object->visibility & (PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY|PATH_RAY_TRANSMIT)))
continue;
/* skip motion blurred deforming meshes, not supported yet */
if(mesh->has_motion_blur())
continue;
/* skip if we have no emission shaders */
foreach(uint sindex, mesh->used_shaders) {
Shader *shader = scene->shaders[sindex];
if(shader->use_mis && shader->has_surface_emission) {
have_emission = true;
break;
}
}
/* count triangles */
if(have_emission) {
for(size_t i = 0; i < mesh->triangles.size(); i++) {
Shader *shader = scene->shaders[mesh->shader[i]];
if(shader->use_mis && shader->has_surface_emission)
num_triangles++;
}
}
}
size_t num_distribution = num_triangles + num_lights;
/* emission area */
float4 *distribution = dscene->light_distribution.resize(num_distribution + 1);
float totarea = 0.0f;
/* triangles */
size_t offset = 0;
int j = 0;
foreach(Object *object, scene->objects) {
Mesh *mesh = object->mesh;
bool have_emission = false;
/* skip if we are not visible for BSDFs */
if(!(object->visibility & (PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY|PATH_RAY_TRANSMIT))) {
j++;
continue;
}
/* skip motion blurred deforming meshes, not supported yet */
if(mesh->has_motion_blur()) {
j++;
continue;
}
/* skip if we have no emission shaders */
foreach(uint sindex, mesh->used_shaders) {
Shader *shader = scene->shaders[sindex];
if(shader->use_mis && shader->has_surface_emission) {
have_emission = true;
break;
}
}
/* sum area */
if(have_emission) {
bool transform_applied = mesh->transform_applied;
Transform tfm = object->tfm;
int object_id = j;
int shader_flag = 0;
if(transform_applied)
object_id = ~object_id;
if(!(object->visibility & PATH_RAY_DIFFUSE)) {
shader_flag |= SHADER_EXCLUDE_DIFFUSE;
use_light_visibility = true;
}
if(!(object->visibility & PATH_RAY_GLOSSY)) {
shader_flag |= SHADER_EXCLUDE_GLOSSY;
use_light_visibility = true;
}
if(!(object->visibility & PATH_RAY_TRANSMIT)) {
shader_flag |= SHADER_EXCLUDE_TRANSMIT;
use_light_visibility = true;
}
if(!(object->visibility & PATH_RAY_VOLUME_SCATTER)) {
shader_flag |= SHADER_EXCLUDE_SCATTER;
use_light_visibility = true;
}
for(size_t i = 0; i < mesh->triangles.size(); i++) {
Shader *shader = scene->shaders[mesh->shader[i]];
if(shader->use_mis && shader->has_surface_emission) {
distribution[offset].x = totarea;
distribution[offset].y = __int_as_float(i + mesh->tri_offset);
distribution[offset].z = __int_as_float(shader_flag);
distribution[offset].w = __int_as_float(object_id);
offset++;
Mesh::Triangle t = mesh->triangles[i];
float3 p1 = mesh->verts[t.v[0]];
float3 p2 = mesh->verts[t.v[1]];
float3 p3 = mesh->verts[t.v[2]];
if(!transform_applied) {
p1 = transform_point(&tfm, p1);
p2 = transform_point(&tfm, p2);
p3 = transform_point(&tfm, p3);
}
totarea += triangle_area(p1, p2, p3);
}
}
}
if(progress.get_cancel()) return;
j++;
}
float trianglearea = totarea;
/* point lights */
float lightarea = (totarea > 0.0f) ? totarea / num_lights : 1.0f;
bool use_lamp_mis = false;
int light_index = 0;
foreach(Light *light, scene->lights) {
if(!light->has_contribution(scene))
continue;
distribution[offset].x = totarea;
distribution[offset].y = __int_as_float(~light_index);
distribution[offset].z = 1.0f;
distribution[offset].w = light->size;
totarea += lightarea;
if(light->size > 0.0f && light->use_mis)
use_lamp_mis = true;
if(light->type == LIGHT_BACKGROUND) {
num_background_lights++;
background_mis = light->use_mis;
}
light_index++;
offset++;
}
/* normalize cumulative distribution functions */
distribution[num_distribution].x = totarea;
distribution[num_distribution].y = 0.0f;
distribution[num_distribution].z = 0.0f;
distribution[num_distribution].w = 0.0f;
if(totarea > 0.0f) {
for(size_t i = 0; i < num_distribution; i++)
distribution[i].x /= totarea;
distribution[num_distribution].x = 1.0f;
}
if(progress.get_cancel()) return;
/* update device */
KernelIntegrator *kintegrator = &dscene->data.integrator;
KernelFilm *kfilm = &dscene->data.film;
kintegrator->use_direct_light = (totarea > 0.0f);
if(kintegrator->use_direct_light) {
/* number of emissives */
kintegrator->num_distribution = num_distribution;
/* precompute pdfs */
kintegrator->pdf_triangles = 0.0f;
kintegrator->pdf_lights = 0.0f;
kintegrator->inv_pdf_lights = 0.0f;
/* sample one, with 0.5 probability of light or triangle */
kintegrator->num_all_lights = num_lights;
if(trianglearea > 0.0f) {
kintegrator->pdf_triangles = 1.0f/trianglearea;
if(num_lights)
kintegrator->pdf_triangles *= 0.5f;
}
if(num_lights) {
kintegrator->pdf_lights = 1.0f/num_lights;
if(trianglearea > 0.0f)
kintegrator->pdf_lights *= 0.5f;
kintegrator->inv_pdf_lights = 1.0f/kintegrator->pdf_lights;
}
kintegrator->use_lamp_mis = use_lamp_mis;
/* bit of an ugly hack to compensate for emitting triangles influencing
* amount of samples we get for this pass */
kfilm->pass_shadow_scale = 1.0f;
if(kintegrator->pdf_triangles != 0.0f)
kfilm->pass_shadow_scale *= 0.5f;
if(num_background_lights < num_lights)
kfilm->pass_shadow_scale *= (float)(num_lights - num_background_lights)/(float)num_lights;
/* CDF */
device->tex_alloc("__light_distribution", dscene->light_distribution);
/* Portals */
if(num_background_lights > 0 && light_index != scene->lights.size()) {
kintegrator->portal_offset = light_index;
kintegrator->num_portals = scene->lights.size() - light_index;
kintegrator->portal_pdf = background_mis? 0.5f: 1.0f;
}
else {
kintegrator->num_portals = 0;
kintegrator->portal_offset = 0;
kintegrator->portal_pdf = 0.0f;
}
}
else {
dscene->light_distribution.clear();
kintegrator->num_distribution = 0;
kintegrator->num_all_lights = 0;
kintegrator->pdf_triangles = 0.0f;
kintegrator->pdf_lights = 0.0f;
kintegrator->inv_pdf_lights = 0.0f;
kintegrator->use_lamp_mis = false;
kintegrator->num_portals = 0;
kintegrator->portal_offset = 0;
kintegrator->portal_pdf = 0.0f;
kfilm->pass_shadow_scale = 1.0f;
}
}
static void background_cdf(int start,
int end,
int res,
int cdf_count,
const vector<float3> *pixels,
float2 *cond_cdf)
{
/* Conditional CDFs (rows, U direction). */
for(int i = start; i < end; i++) {
float sin_theta = sinf(M_PI_F * (i + 0.5f) / res);
float3 env_color = (*pixels)[i * res];
float ave_luminance = average(env_color);
cond_cdf[i * cdf_count].x = ave_luminance * sin_theta;
cond_cdf[i * cdf_count].y = 0.0f;
for(int j = 1; j < res; j++) {
env_color = (*pixels)[i * res + j];
ave_luminance = average(env_color);
cond_cdf[i * cdf_count + j].x = ave_luminance * sin_theta;
cond_cdf[i * cdf_count + j].y = cond_cdf[i * cdf_count + j - 1].y + cond_cdf[i * cdf_count + j - 1].x / res;
}
float cdf_total = cond_cdf[i * cdf_count + res - 1].y + cond_cdf[i * cdf_count + res - 1].x / res;
float cdf_total_inv = 1.0f / cdf_total;
/* stuff the total into the brightness value for the last entry, because
* we are going to normalize the CDFs to 0.0 to 1.0 afterwards */
cond_cdf[i * cdf_count + res].x = cdf_total;
if(cdf_total > 0.0f)
for(int j = 1; j < res; j++)
cond_cdf[i * cdf_count + j].y *= cdf_total_inv;
cond_cdf[i * cdf_count + res].y = 1.0f;
}
}
void LightManager::device_update_background(Device *device,
DeviceScene *dscene,
Scene *scene,
Progress& progress,
bool skip_background)
{
KernelIntegrator *kintegrator = &dscene->data.integrator;
Light *background_light = NULL;
/* find background light */
if(!skip_background) {
foreach(Light *light, scene->lights) {
if(light->type == LIGHT_BACKGROUND) {
background_light = light;
break;
}
}
}
/* no background light found, signal renderer to skip sampling */
if(!background_light) {
kintegrator->pdf_background_res = 0;
return;
}
progress.set_status("Updating Lights", "Importance map");
assert(kintegrator->use_direct_light);
/* get the resolution from the light's size (we stuff it in there) */
int res = background_light->map_resolution;
kintegrator->pdf_background_res = res;
assert(res > 0);
vector<float3> pixels;
shade_background_pixels(device, dscene, res, pixels, progress);
if(progress.get_cancel())
return;
/* build row distributions and column distribution for the infinite area environment light */
int cdf_count = res + 1;
float2 *marg_cdf = dscene->light_background_marginal_cdf.resize(cdf_count);
float2 *cond_cdf = dscene->light_background_conditional_cdf.resize(cdf_count * cdf_count);
double time_start = time_dt();
if(res < 512) {
/* Small enough resolution, faster to do single-threaded. */
background_cdf(0, res, res, cdf_count, &pixels, cond_cdf);
}
else {
/* Threaded evaluation for large resolution. */
const int num_blocks = TaskScheduler::num_threads();
const int chunk_size = res / num_blocks;
int start_row = 0;
TaskPool pool;
for(int i = 0; i < num_blocks; ++i) {
const int current_chunk_size =
(i != num_blocks - 1) ? chunk_size
: (res - i * chunk_size);
pool.push(function_bind(&background_cdf,
start_row, start_row + current_chunk_size,
res,
cdf_count,
&pixels,
cond_cdf));
start_row += current_chunk_size;
}
pool.wait_work();
}
/* marginal CDFs (column, V direction, sum of rows) */
marg_cdf[0].x = cond_cdf[res].x;
marg_cdf[0].y = 0.0f;
for(int i = 1; i < res; i++) {
marg_cdf[i].x = cond_cdf[i * cdf_count + res].x;
marg_cdf[i].y = marg_cdf[i - 1].y + marg_cdf[i - 1].x / res;
}
float cdf_total = marg_cdf[res - 1].y + marg_cdf[res - 1].x / res;
marg_cdf[res].x = cdf_total;
if(cdf_total > 0.0f)
for(int i = 1; i < res; i++)
marg_cdf[i].y /= cdf_total;
marg_cdf[res].y = 1.0f;
VLOG(2) << "Background MIS build time " << time_dt() - time_start << "\n";
/* update device */
device->tex_alloc("__light_background_marginal_cdf", dscene->light_background_marginal_cdf);
device->tex_alloc("__light_background_conditional_cdf", dscene->light_background_conditional_cdf);
}
void LightManager::device_update_points(Device *device,
DeviceScene *dscene,
Scene *scene,
bool skip_background)
{
int num_scene_lights = scene->lights.size();
if(num_scene_lights == 0)
return;
float4 *light_data = dscene->light_data.resize(num_scene_lights*LIGHT_SIZE);
int light_index = 0;
foreach(Light *light, scene->lights) {
if(!light->has_contribution(scene)) {
continue;
}
float3 co = light->co;
int shader_id = scene->shader_manager->get_shader_id(light->shader);
float samples = __int_as_float(light->samples);
float max_bounces = __int_as_float(light->max_bounces);
if(!light->cast_shadow)
shader_id &= ~SHADER_CAST_SHADOW;
if(!light->use_diffuse) {
shader_id |= SHADER_EXCLUDE_DIFFUSE;
use_light_visibility = true;
}
if(!light->use_glossy) {
shader_id |= SHADER_EXCLUDE_GLOSSY;
use_light_visibility = true;
}
if(!light->use_transmission) {
shader_id |= SHADER_EXCLUDE_TRANSMIT;
use_light_visibility = true;
}
if(!light->use_scatter) {
shader_id |= SHADER_EXCLUDE_SCATTER;
use_light_visibility = true;
}
if(light->type == LIGHT_POINT) {
shader_id &= ~SHADER_AREA_LIGHT;
float radius = light->size;
float invarea = (radius > 0.0f)? 1.0f/(M_PI_F*radius*radius): 1.0f;
if(light->use_mis && radius > 0.0f)
shader_id |= SHADER_USE_MIS;
light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, 0.0f);
light_data[light_index*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
light_data[light_index*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
}
else if(light->type == LIGHT_DISTANT) {
shader_id &= ~SHADER_AREA_LIGHT;
float radius = light->size;
float angle = atanf(radius);
float cosangle = cosf(angle);
float area = M_PI_F*radius*radius;
float invarea = (area > 0.0f)? 1.0f/area: 1.0f;
float3 dir = light->dir;
dir = safe_normalize(dir);
if(light->use_mis && area > 0.0f)
shader_id |= SHADER_USE_MIS;
light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), dir.x, dir.y, dir.z);
light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, cosangle, invarea);
light_data[light_index*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
light_data[light_index*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
}
else if(light->type == LIGHT_BACKGROUND) {
if(skip_background) {
continue;
}
uint visibility = scene->background->visibility;
shader_id &= ~SHADER_AREA_LIGHT;
shader_id |= SHADER_USE_MIS;
if(!(visibility & PATH_RAY_DIFFUSE)) {
shader_id |= SHADER_EXCLUDE_DIFFUSE;
use_light_visibility = true;
}
if(!(visibility & PATH_RAY_GLOSSY)) {
shader_id |= SHADER_EXCLUDE_GLOSSY;
use_light_visibility = true;
}
if(!(visibility & PATH_RAY_TRANSMIT)) {
shader_id |= SHADER_EXCLUDE_TRANSMIT;
use_light_visibility = true;
}
if(!(visibility & PATH_RAY_VOLUME_SCATTER)) {
shader_id |= SHADER_EXCLUDE_SCATTER;
use_light_visibility = true;
}
light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), 0.0f, 0.0f, 0.0f);
light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), 0.0f, 0.0f, 0.0f);
light_data[light_index*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
light_data[light_index*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
}
else if(light->type == LIGHT_AREA) {
float3 axisu = light->axisu*(light->sizeu*light->size);
float3 axisv = light->axisv*(light->sizev*light->size);
float area = len(axisu)*len(axisv);
float invarea = (area > 0.0f)? 1.0f/area: 1.0f;
float3 dir = light->dir;
dir = safe_normalize(dir);
if(light->use_mis && area > 0.0f)
shader_id |= SHADER_USE_MIS;
light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), axisu.x, axisu.y, axisu.z);
light_data[light_index*LIGHT_SIZE + 2] = make_float4(invarea, axisv.x, axisv.y, axisv.z);
light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, dir.x, dir.y, dir.z);
light_data[light_index*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
}
else if(light->type == LIGHT_SPOT) {
shader_id &= ~SHADER_AREA_LIGHT;
float radius = light->size;
float invarea = (radius > 0.0f)? 1.0f/(M_PI_F*radius*radius): 1.0f;
float spot_angle = cosf(light->spot_angle*0.5f);
float spot_smooth = (1.0f - spot_angle)*light->spot_smooth;
float3 dir = light->dir;
dir = safe_normalize(dir);
if(light->use_mis && radius > 0.0f)
shader_id |= SHADER_USE_MIS;
light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, spot_angle);
light_data[light_index*LIGHT_SIZE + 2] = make_float4(spot_smooth, dir.x, dir.y, dir.z);
light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
light_data[light_index*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
}
light_index++;
}
/* TODO(sergey): Consider moving portals update to their own function
* keeping this one more manageable.
*/
foreach(Light *light, scene->lights) {
if(!light->is_portal)
continue;
assert(light->type == LIGHT_AREA);
float3 co = light->co;
float3 axisu = light->axisu*(light->sizeu*light->size);
float3 axisv = light->axisv*(light->sizev*light->size);
float area = len(axisu)*len(axisv);
float invarea = (area > 0.0f) ? 1.0f / area : 1.0f;
float3 dir = light->dir;
dir = safe_normalize(dir);
light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
light_data[light_index*LIGHT_SIZE + 1] = make_float4(area, axisu.x, axisu.y, axisu.z);
light_data[light_index*LIGHT_SIZE + 2] = make_float4(invarea, axisv.x, axisv.y, axisv.z);
light_data[light_index*LIGHT_SIZE + 3] = make_float4(-1, dir.x, dir.y, dir.z);
light_data[light_index*LIGHT_SIZE + 4] = make_float4(-1, 0.0f, 0.0f, 0.0f);
light_index++;
}
VLOG(1) << "Number of lights sent to the device: " << light_index;
VLOG(1) << "Number of lights without contribution: "
<< num_scene_lights - light_index;
device->tex_alloc("__light_data", dscene->light_data);
}
void LightManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
{
VLOG(1) << "Total " << scene->lights.size() << " lights.";
if(!need_update)
return;
device_free(device, dscene);
use_light_visibility = false;
bool skip_background = skip_background_light(device, scene);
device_update_points(device, dscene, scene, skip_background);
if(progress.get_cancel()) return;
device_update_distribution(device, dscene, scene, progress);
if(progress.get_cancel()) return;
device_update_background(device, dscene, scene, progress, skip_background);
if(progress.get_cancel()) return;
if(use_light_visibility != scene->film->use_light_visibility) {
scene->film->use_light_visibility = use_light_visibility;
scene->film->tag_update(scene);
}
need_update = false;
}
void LightManager::device_free(Device *device, DeviceScene *dscene)
{
device->tex_free(dscene->light_distribution);
device->tex_free(dscene->light_data);
device->tex_free(dscene->light_background_marginal_cdf);
device->tex_free(dscene->light_background_conditional_cdf);
dscene->light_distribution.clear();
dscene->light_data.clear();
dscene->light_background_marginal_cdf.clear();
dscene->light_background_conditional_cdf.clear();
}
void LightManager::tag_update(Scene * /*scene*/)
{
need_update = true;
}
CCL_NAMESPACE_END