Cycles render engine, initial commit. This is the engine itself, blender modifications and build instructions will follow later.
Cycles uses code from some great open source projects, many thanks them: * BVH building and traversal code from NVidia's "Understanding the Efficiency of Ray Traversal on GPUs": http://code.google.com/p/understanding-the-efficiency-of-ray-traversal-on-gpus/ * Open Shading Language for a large part of the shading system: http://code.google.com/p/openshadinglanguage/ * Blender for procedural textures and a few other nodes. * Approximate Catmull Clark subdivision from NVidia Mesh tools: http://code.google.com/p/nvidia-mesh-tools/ * Sobol direction vectors from: http://web.maths.unsw.edu.au/~fkuo/sobol/ * Film response functions from: http://www.cs.columbia.edu/CAVE/software/softlib/dorf.php
This commit is contained in:
220
intern/cycles/render/light.cpp
Normal file
220
intern/cycles/render/light.cpp
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "device.h"
|
||||
#include "light.h"
|
||||
#include "mesh.h"
|
||||
#include "object.h"
|
||||
#include "scene.h"
|
||||
#include "shader.h"
|
||||
|
||||
#include "util_foreach.h"
|
||||
#include "util_progress.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Light */
|
||||
|
||||
Light::Light()
|
||||
{
|
||||
co = make_float3(0.0f, 0.0f, 0.0f);
|
||||
radius = 0.0f;
|
||||
shader = 0;
|
||||
}
|
||||
|
||||
void Light::tag_update(Scene *scene)
|
||||
{
|
||||
scene->light_manager->need_update = true;
|
||||
}
|
||||
|
||||
/* Light Manager */
|
||||
|
||||
LightManager::LightManager()
|
||||
{
|
||||
need_update = true;
|
||||
}
|
||||
|
||||
LightManager::~LightManager()
|
||||
{
|
||||
}
|
||||
|
||||
void LightManager::device_update_distribution(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
|
||||
{
|
||||
/* count */
|
||||
size_t num_lights = scene->lights.size();
|
||||
size_t num_triangles = 0;
|
||||
|
||||
foreach(Object *object, scene->objects) {
|
||||
Mesh *mesh = object->mesh;
|
||||
|
||||
for(size_t i = 0; i < mesh->triangles.size(); i++) {
|
||||
Shader *shader = scene->shaders[mesh->shader[i]];
|
||||
|
||||
if(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;
|
||||
size_t j = 0;
|
||||
|
||||
foreach(Object *object, scene->objects) {
|
||||
Mesh *mesh = object->mesh;
|
||||
Transform tfm = object->tfm;
|
||||
int object_id = (mesh->transform_applied)? -j-1: j;
|
||||
|
||||
for(size_t i = 0; i < mesh->triangles.size(); i++) {
|
||||
Shader *shader = scene->shaders[mesh->shader[i]];
|
||||
|
||||
if(shader->has_surface_emission) {
|
||||
distribution[offset].x = totarea;
|
||||
distribution[offset].y = __int_as_float(i + mesh->tri_offset);
|
||||
distribution[offset].z = 1.0f;
|
||||
distribution[offset].w = __int_as_float(object_id);
|
||||
offset++;
|
||||
|
||||
Mesh::Triangle t = mesh->triangles[i];
|
||||
float3 p1 = transform(&tfm, mesh->verts[t.v[0]]);
|
||||
float3 p2 = transform(&tfm, mesh->verts[t.v[1]]);
|
||||
float3 p3 = transform(&tfm, mesh->verts[t.v[2]]);
|
||||
|
||||
totarea += triangle_area(p1, p2, p3);
|
||||
}
|
||||
}
|
||||
|
||||
if(progress.get_cancel()) return;
|
||||
|
||||
j++;
|
||||
}
|
||||
|
||||
float trianglearea = totarea;
|
||||
|
||||
/* point lights */
|
||||
float lightarea = (totarea > 0.0f)? totarea/scene->lights.size(): 1.0f;
|
||||
|
||||
for(size_t i = 0; i < scene->lights.size(); i++, offset++) {
|
||||
distribution[offset].x = totarea;
|
||||
distribution[offset].y = __int_as_float(-i-1);
|
||||
distribution[offset].z = 1.0f;
|
||||
distribution[offset].w = scene->lights[i]->radius;
|
||||
totarea += lightarea;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
kintegrator->use_emission = (totarea > 0.0f);
|
||||
|
||||
if(kintegrator->use_emission) {
|
||||
/* number of emissives */
|
||||
kintegrator->num_triangles = num_triangles;
|
||||
kintegrator->num_lights = num_lights;
|
||||
kintegrator->num_distribution = num_distribution;
|
||||
|
||||
/* precompute pdfs */
|
||||
kintegrator->pdf_triangles = 0.0f;
|
||||
kintegrator->pdf_lights = 0.0f;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* CDF */
|
||||
device->tex_alloc("__light_distribution", dscene->light_distribution);
|
||||
}
|
||||
else
|
||||
dscene->light_distribution.clear();
|
||||
}
|
||||
|
||||
void LightManager::device_update_points(Device *device, DeviceScene *dscene, Scene *scene)
|
||||
{
|
||||
if(scene->lights.size() == 0)
|
||||
return;
|
||||
|
||||
float4 *light_point = dscene->light_point.resize(scene->lights.size());
|
||||
|
||||
for(size_t i = 0; i < scene->lights.size(); i++) {
|
||||
float3 co = scene->lights[i]->co;
|
||||
int shader_id = scene->shader_manager->get_shader_id(scene->lights[i]->shader);
|
||||
|
||||
light_point[i] = make_float4(co.x, co.y, co.z, __int_as_float(shader_id));
|
||||
}
|
||||
|
||||
device->tex_alloc("__light_point", dscene->light_point);
|
||||
}
|
||||
|
||||
void LightManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
|
||||
{
|
||||
if(!need_update)
|
||||
return;
|
||||
|
||||
device_free(device, dscene);
|
||||
|
||||
device_update_points(device, dscene, scene);
|
||||
if(progress.get_cancel()) return;
|
||||
|
||||
device_update_distribution(device, dscene, scene, progress);
|
||||
if(progress.get_cancel()) return;
|
||||
|
||||
need_update = false;
|
||||
}
|
||||
|
||||
void LightManager::device_free(Device *device, DeviceScene *dscene)
|
||||
{
|
||||
device->tex_free(dscene->light_distribution);
|
||||
device->tex_free(dscene->light_point);
|
||||
|
||||
dscene->light_distribution.clear();
|
||||
dscene->light_point.clear();
|
||||
}
|
||||
|
||||
void LightManager::tag_update(Scene *scene)
|
||||
{
|
||||
need_update = true;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
Reference in New Issue
Block a user