Cycles Bake

Expand Cycles to use the new baking API in Blender.

It works on the selected object, and the panel can be accessed in the Render panel (similar to where it is for the Blender Internal).

It bakes for the active texture of each material of the object. The active texture is currently defined as the active Image Texture node present in the material nodetree. If you don't want the baking to override an existent material, make sure the active Image Texture node is not connected to the nodetree. The active texture is also the texture shown in the viewport in the rendered mode.

Remember to save your images after the baking is complete.

Note: Bake currently only works in the CPU
Note: This is not supported by Cycles standalone because a lot of the work is done in Blender as part of the operator only, not the engine (Cycles).

Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Bake

Supported Passes:
-----------------
Data Passes
 * Normal
 * UV
 * Diffuse/Glossy/Transmission/Subsurface/Emit Color

Light Passes
 * AO
 * Combined
 * Shadow
 * Diffuse/Glossy/Transmission/Subsurface/Emit Direct/Indirect
 * Environment

Review: D421
Reviewed by: Campbell Barton, Brecht van Lommel, Sergey Sharybin, Thomas Dinge

Original design by Brecht van Lommel.

The entire commit history can be found on the branch: bake-cycles
This commit is contained in:
Dalai Felinto 2014-01-02 19:05:07 -02:00
parent 97641a0ec9
commit eec3eaba08
22 changed files with 937 additions and 55 deletions

View File

@ -67,6 +67,9 @@ class CyclesRender(bpy.types.RenderEngine):
def render(self, scene):
engine.render(self)
def bake(self, scene, obj, pass_type, pixel_array, num_pixels, depth, result):
engine.bake(self, obj, pass_type, pixel_array, num_pixels, depth, result)
# viewport render
def view_update(self, context):
if not self.session:

View File

@ -59,6 +59,12 @@ def render(engine):
_cycles.render(engine.session)
def bake(engine, obj, pass_type, pixel_array, num_pixels, depth, result):
import _cycles
session = getattr(engine, "session", None)
if session is not None:
_cycles.bake(engine.session, obj.as_pointer(), pass_type, pixel_array.as_pointer(), num_pixels, depth, result.as_pointer())
def reset(engine, data, scene):
import _cycles
data = data.as_pointer()

View File

@ -471,6 +471,33 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
default=False,
)
cls.bake_type = EnumProperty(
name="Bake Type",
default='COMBINED',
description="Type of pass to bake",
items = (
('COMBINED', "Combined", ""),
('AO', "Ambient Occlusion", ""),
('SHADOW', "Shadow", ""),
('NORMAL', "Normal", ""),
('UV', "UV", ""),
('EMIT', "Emit", ""),
('ENVIRONMENT', "Environment", ""),
('DIFFUSE_DIRECT', "Diffuse Direct", ""),
('DIFFUSE_INDIRECT', "Diffuse Indirect", ""),
('DIFFUSE_COLOR', "Diffuse Color", ""),
('GLOSSY_DIRECT', "Glossy Direct", ""),
('GLOSSY_INDIRECT', "Glossy Indirect", ""),
('GLOSSY_COLOR', "Glossy Color", ""),
('TRANSMISSION_DIRECT', "Transmission Direct", ""),
('TRANSMISSION_INDIRECT', "Transmission Indirect", ""),
('TRANSMISSION_COLOR', "Transmission Color", ""),
('SUBSURFACE_DIRECT', "Subsurface Direct", ""),
('SUBSURFACE_INDIRECT', "Subsurface Indirect", ""),
('SUBSURFACE_COLOR', "Subsurface Color", ""),
),
)
@classmethod
def unregister(cls):
del bpy.types.Scene.cycles

View File

@ -1227,6 +1227,54 @@ class CyclesRender_PT_CurveRendering(CyclesButtonsPanel, Panel):
row.prop(ccscene, "maximum_width", text="Max Ext.")
class CyclesRender_PT_bake(CyclesButtonsPanel, Panel):
bl_label = "Bake"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'CYCLES'}
def draw(self, context):
layout = self.layout
scene = context.scene
cscene = scene.cycles
cbk = scene.render.bake
layout.operator("object.bake", icon='RENDER_STILL').type = \
cscene.bake_type
col = layout.column()
col.prop(cscene, "bake_type")
col.separator()
split = layout.split()
sub = split.column()
sub.prop(cbk, "use_clear")
sub.prop(cbk, "margin")
sub = split.column()
sub.prop(cbk, "use_selected_to_active")
sub = sub.column()
sub.active = cbk.use_selected_to_active
sub.prop(cbk, "cage_extrusion", text="Distance")
sub.prop_search(cbk, "cage", scene, "objects")
if cscene.bake_type == 'NORMAL':
col.separator()
box = col.box()
box.label(text="Normal Settings:")
box.prop(cbk, "normal_space", text="Space")
row = box.row(align=True)
row.label(text = "Swizzle:")
row.prop(cbk, "normal_r", text="")
row.prop(cbk, "normal_g", text="")
row.prop(cbk, "normal_b", text="")
class CyclesParticle_PT_CurveSettings(CyclesButtonsPanel, Panel):
bl_label = "Cycles Hair Settings"
bl_context = "particle"

View File

@ -147,6 +147,38 @@ static PyObject *render_func(PyObject *self, PyObject *value)
Py_RETURN_NONE;
}
/* pixel_array and result passed as pointers */
static PyObject *bake_func(PyObject *self, PyObject *args)
{
PyObject *pysession, *pyobject;
PyObject *pypixel_array, *pyresult;
const char *pass_type;
int num_pixels, depth;
if(!PyArg_ParseTuple(args, "OOsOiiO", &pysession, &pyobject, &pass_type, &pypixel_array, &num_pixels, &depth, &pyresult))
return NULL;
Py_BEGIN_ALLOW_THREADS
BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
PointerRNA objectptr;
RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyobject), &objectptr);
BL::Object b_object(objectptr);
void *b_result = PyLong_AsVoidPtr(pyresult);
PointerRNA bakepixelptr;
RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pypixel_array), &bakepixelptr);
BL::BakePixel b_bake_pixel(bakepixelptr);
session->bake(b_object, pass_type, b_bake_pixel, num_pixels, depth, (float *)b_result);
Py_END_ALLOW_THREADS
Py_RETURN_NONE;
}
static PyObject *draw_func(PyObject *self, PyObject *args)
{
PyObject *pysession, *pyv3d, *pyrv3d;
@ -418,6 +450,7 @@ static PyMethodDef methods[] = {
{"create", create_func, METH_VARARGS, ""},
{"free", free_func, METH_O, ""},
{"render", render_func, METH_O, ""},
{"bake", bake_func, METH_VARARGS, ""},
{"draw", draw_func, METH_VARARGS, ""},
{"sync", sync_func, METH_O, ""},
{"reset", reset_func, METH_VARARGS, ""},

View File

@ -14,6 +14,8 @@
* limitations under the License
*/
#include <stdlib.h>
#include "background.h"
#include "buffers.h"
#include "camera.h"
@ -21,6 +23,8 @@
#include "integrator.h"
#include "film.h"
#include "light.h"
#include "mesh.h"
#include "object.h"
#include "scene.h"
#include "session.h"
#include "shader.h"
@ -259,6 +263,58 @@ static PassType get_pass_type(BL::RenderPass b_pass)
return PASS_NONE;
}
static ShaderEvalType get_shader_type(const string& pass_type)
{
const char *shader_type = pass_type.c_str();
/* data passes */
if(strcmp(shader_type, "NORMAL")==0)
return SHADER_EVAL_NORMAL;
else if(strcmp(shader_type, "UV")==0)
return SHADER_EVAL_UV;
else if(strcmp(shader_type, "DIFFUSE_COLOR")==0)
return SHADER_EVAL_DIFFUSE_COLOR;
else if(strcmp(shader_type, "GLOSSY_COLOR")==0)
return SHADER_EVAL_GLOSSY_COLOR;
else if(strcmp(shader_type, "TRANSMISSION_COLOR")==0)
return SHADER_EVAL_TRANSMISSION_COLOR;
else if(strcmp(shader_type, "SUBSURFACE_COLOR")==0)
return SHADER_EVAL_SUBSURFACE_COLOR;
else if(strcmp(shader_type, "EMIT")==0)
return SHADER_EVAL_EMISSION;
/* light passes */
else if(strcmp(shader_type, "AO")==0)
return SHADER_EVAL_AO;
else if(strcmp(shader_type, "COMBINED")==0)
return SHADER_EVAL_COMBINED;
else if(strcmp(shader_type, "SHADOW")==0)
return SHADER_EVAL_SHADOW;
else if(strcmp(shader_type, "DIFFUSE_DIRECT")==0)
return SHADER_EVAL_DIFFUSE_DIRECT;
else if(strcmp(shader_type, "GLOSSY_DIRECT")==0)
return SHADER_EVAL_GLOSSY_DIRECT;
else if(strcmp(shader_type, "TRANSMISSION_DIRECT")==0)
return SHADER_EVAL_TRANSMISSION_DIRECT;
else if(strcmp(shader_type, "SUBSURFACE_DIRECT")==0)
return SHADER_EVAL_SUBSURFACE_DIRECT;
else if(strcmp(shader_type, "DIFFUSE_INDIRECT")==0)
return SHADER_EVAL_DIFFUSE_INDIRECT;
else if(strcmp(shader_type, "GLOSSY_INDIRECT")==0)
return SHADER_EVAL_GLOSSY_INDIRECT;
else if(strcmp(shader_type, "TRANSMISSION_INDIRECT")==0)
return SHADER_EVAL_TRANSMISSION_INDIRECT;
else if(strcmp(shader_type, "SUBSURFACE_INDIRECT")==0)
return SHADER_EVAL_SUBSURFACE_INDIRECT;
/* extra */
else if(strcmp(shader_type, "ENVIRONMENT")==0)
return SHADER_EVAL_ENVIRONMENT;
else
return SHADER_EVAL_BAKE;
}
static BL::RenderResult begin_render_result(BL::RenderEngine b_engine, int x, int y, int w, int h, const char *layername)
{
return b_engine.begin_result(x, y, w, h, layername);
@ -425,6 +481,105 @@ void BlenderSession::render()
sync = NULL;
}
static void populate_bake_data(BakeData *data, BL::BakePixel pixel_array, const int num_pixels)
{
BL::BakePixel bp = pixel_array;
int i;
for(i=0; i < num_pixels; i++) {
data->set(i, bp.primitive_id(), bp.uv());
bp = bp.next();
}
}
static bool is_light_pass(ShaderEvalType type)
{
switch (type) {
case SHADER_EVAL_AO:
case SHADER_EVAL_COMBINED:
case SHADER_EVAL_SHADOW:
case SHADER_EVAL_DIFFUSE_DIRECT:
case SHADER_EVAL_GLOSSY_DIRECT:
case SHADER_EVAL_TRANSMISSION_DIRECT:
case SHADER_EVAL_SUBSURFACE_DIRECT:
case SHADER_EVAL_DIFFUSE_INDIRECT:
case SHADER_EVAL_GLOSSY_INDIRECT:
case SHADER_EVAL_TRANSMISSION_INDIRECT:
case SHADER_EVAL_SUBSURFACE_INDIRECT:
return true;
default:
return false;
}
}
void BlenderSession::bake(BL::Object b_object, const string& pass_type, BL::BakePixel pixel_array, int num_pixels, int depth, float result[])
{
ShaderEvalType shader_type = get_shader_type(pass_type);
size_t object_index = OBJECT_NONE;
int tri_offset = 0;
if(shader_type == SHADER_EVAL_UV) {
/* force UV to be available */
Pass::add(PASS_UV, scene->film->passes);
}
if(is_light_pass(shader_type)) {
/* force use_light_pass to be true */
Pass::add(PASS_LIGHT, scene->film->passes);
}
/* create device and update scene */
scene->film->tag_update(scene);
scene->integrator->tag_update(scene);
/* update scene */
sync->sync_camera(b_render, b_engine.camera_override(), width, height);
sync->sync_data(b_v3d, b_engine.camera_override(), &python_thread_state);
/* get buffer parameters */
SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_scene, b_v3d, b_rv3d, scene->camera, width, height);
scene->bake_manager->set_baking(true);
/* set number of samples */
session->tile_manager.set_samples(session_params.samples);
session->reset(buffer_params, session_params.samples);
session->update_scene();
/* find object index. todo: is arbitrary - copied from mesh_displace.cpp */
for(size_t i = 0; i < scene->objects.size(); i++) {
if(strcmp(scene->objects[i]->name.c_str(), b_object.name().c_str()) == 0) {
object_index = i;
tri_offset = scene->objects[i]->mesh->tri_offset;
break;
}
}
/* when used, non-instanced convention: object = ~object */
int object = ~object_index;
BakeData *bake_data = scene->bake_manager->init(object, tri_offset, num_pixels);
populate_bake_data(bake_data, pixel_array, num_pixels);
/* set number of samples */
session->tile_manager.set_samples(session_params.samples);
session->reset(buffer_params, session_params.samples);
session->update_scene();
scene->bake_manager->bake(scene->device, &scene->dscene, scene, session->progress, shader_type, bake_data, result);
/* free all memory used (host and device), so we wouldn't leave render
* engine with extra memory allocated
*/
session->device_free();
delete sync;
sync = NULL;
}
void BlenderSession::do_write_update_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile, bool do_update_only)
{
RenderBuffers *buffers = rtile.buffers;

View File

@ -20,6 +20,7 @@
#include "device.h"
#include "scene.h"
#include "session.h"
#include "bake.h"
#include "util_vector.h"
@ -51,6 +52,8 @@ public:
/* offline render */
void render();
void bake(BL::Object b_object, const string& pass_type, BL::BakePixel pixel_array, int num_pixels, int depth, float pixels[]);
void write_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile);
void write_render_tile(RenderTile& rtile);

View File

@ -395,7 +395,7 @@ public:
for(int x = task.shader_x; x < task.shader_x + task.shader_w; x++) {
kernel_cpu_avx_shader(&kg, (uint4*)task.shader_input, (float4*)task.shader_output, task.shader_eval_type, x);
if(task_pool.canceled())
if(task.get_cancel() || task_pool.canceled())
break;
}
}
@ -406,7 +406,7 @@ public:
for(int x = task.shader_x; x < task.shader_x + task.shader_w; x++) {
kernel_cpu_sse41_shader(&kg, (uint4*)task.shader_input, (float4*)task.shader_output, task.shader_eval_type, x);
if(task_pool.canceled())
if(task.get_cancel() || task_pool.canceled())
break;
}
}
@ -417,7 +417,7 @@ public:
for(int x = task.shader_x; x < task.shader_x + task.shader_w; x++) {
kernel_cpu_sse3_shader(&kg, (uint4*)task.shader_input, (float4*)task.shader_output, task.shader_eval_type, x);
if(task_pool.canceled())
if(task.get_cancel() || task_pool.canceled())
break;
}
}
@ -428,7 +428,7 @@ public:
for(int x = task.shader_x; x < task.shader_x + task.shader_w; x++) {
kernel_cpu_sse2_shader(&kg, (uint4*)task.shader_input, (float4*)task.shader_output, task.shader_eval_type, x);
if(task_pool.canceled())
if(task.get_cancel() || task_pool.canceled())
break;
}
}
@ -438,7 +438,7 @@ public:
for(int x = task.shader_x; x < task.shader_x + task.shader_w; x++) {
kernel_cpu_shader(&kg, (uint4*)task.shader_input, (float4*)task.shader_output, task.shader_eval_type, x);
if(task_pool.canceled())
if(task.get_cancel() || task_pool.canceled())
break;
}
}

View File

@ -407,5 +407,26 @@ ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadi
return L_sum;
}
ccl_device_inline void path_radiance_accum_sample(PathRadiance *L, PathRadiance *L_sample, int num_samples)
{
float fac = 1.0f/num_samples;
L->direct_diffuse += L_sample->direct_diffuse*fac;
L->direct_glossy += L_sample->direct_glossy*fac;
L->direct_transmission += L_sample->direct_transmission*fac;
L->direct_subsurface += L_sample->direct_subsurface*fac;
L->indirect_diffuse += L_sample->indirect_diffuse*fac;
L->indirect_glossy += L_sample->indirect_glossy*fac;
L->indirect_transmission += L_sample->indirect_transmission*fac;
L->indirect_subsurface += L_sample->indirect_subsurface*fac;
L->emission += L_sample->emission*fac;
L->background += L_sample->background*fac;
L->ao += L_sample->ao*fac;
L->shadow += L_sample->shadow*fac;
L->mist += L_sample->mist*fac;
}
CCL_NAMESPACE_END

View File

@ -16,8 +16,275 @@
CCL_NAMESPACE_BEGIN
ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadiance *L, RNG rng, bool is_ao)
{
int samples = kernel_data.integrator.aa_samples;
/* initialize master radiance accumulator */
kernel_assert(kernel_data.film.use_light_pass);
path_radiance_init(L, kernel_data.film.use_light_pass);
/* take multiple samples */
for(int sample = 0; sample < samples; sample++) {
PathRadiance L_sample;
PathState state;
Ray ray;
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
/* init radiance */
path_radiance_init(&L_sample, kernel_data.film.use_light_pass);
/* init path state */
path_state_init(kg, &state, &rng, sample);
state.num_samples = samples;
/* evaluate surface shader */
float rbsdf = path_state_rng_1D(kg, &rng, &state, PRNG_BSDF);
shader_eval_surface(kg, sd, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
/* sample ambient occlusion */
if(is_ao) {
kernel_path_ao(kg, sd, &L_sample, &state, &rng, throughput);
}
/* sample light and BSDF */
else if(kernel_path_integrate_lighting(kg, &rng, sd, &throughput, &state, &L_sample, &ray)) {
#ifdef __LAMP_MIS__
state.ray_t = 0.0f;
#endif
/* compute indirect light */
kernel_path_indirect(kg, &rng, ray, throughput, state.num_samples, state, &L_sample);
/* sum and reset indirect light pass variables for the next samples */
path_radiance_sum_indirect(&L_sample);
path_radiance_reset_indirect(&L_sample);
}
/* accumulate into master L */
path_radiance_accum_sample(L, &L_sample, samples);
}
}
ccl_device bool is_light_pass(ShaderEvalType type)
{
switch (type) {
case SHADER_EVAL_AO:
case SHADER_EVAL_COMBINED:
case SHADER_EVAL_SHADOW:
case SHADER_EVAL_DIFFUSE_DIRECT:
case SHADER_EVAL_GLOSSY_DIRECT:
case SHADER_EVAL_TRANSMISSION_DIRECT:
case SHADER_EVAL_SUBSURFACE_DIRECT:
case SHADER_EVAL_DIFFUSE_INDIRECT:
case SHADER_EVAL_GLOSSY_INDIRECT:
case SHADER_EVAL_TRANSMISSION_INDIRECT:
case SHADER_EVAL_SUBSURFACE_INDIRECT:
return true;
default:
return false;
}
}
ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, ccl_global float4 *output, ShaderEvalType type, int i)
{
ShaderData sd;
uint4 in = input[i];
float3 out;
int object = in.x;
int prim = in.y;
if(prim == -1)
return;
float u = __uint_as_float(in.z);
float v = __uint_as_float(in.w);
int shader;
float3 P, Ng;
triangle_point_normal(kg, prim, u, v, &P, &Ng, &shader);
/* dummy initilizations copied from SHADER_EVAL_DISPLACE */
float3 I = Ng;
float t = 0.0f;
float time = TIME_INVALID;
int bounce = 0;
int transparent_bounce = 0;
/* light passes */
PathRadiance L;
/* TODO, disable the closures we won't need */
shader_setup_from_sample(kg, &sd, P, Ng, I, shader, object, prim, u, v, t, time, bounce, transparent_bounce);
if(is_light_pass(type)){
RNG rng = cmj_hash(i, 0);
compute_light_pass(kg, &sd, &L, rng, (type == SHADER_EVAL_AO));
}
switch (type) {
/* data passes */
case SHADER_EVAL_NORMAL:
{
/* compression: normal = (2 * color) - 1 */
out = sd.N * 0.5f + make_float3(0.5f, 0.5f, 0.5f);
break;
}
case SHADER_EVAL_UV:
{
out = primitive_uv(kg, &sd);
break;
}
case SHADER_EVAL_DIFFUSE_COLOR:
{
shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
out = shader_bsdf_diffuse(kg, &sd);
break;
}
case SHADER_EVAL_GLOSSY_COLOR:
{
shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
out = shader_bsdf_glossy(kg, &sd);
break;
}
case SHADER_EVAL_TRANSMISSION_COLOR:
{
shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
out = shader_bsdf_transmission(kg, &sd);
break;
}
case SHADER_EVAL_SUBSURFACE_COLOR:
{
#ifdef __SUBSURFACE__
shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
out = shader_bsdf_subsurface(kg, &sd);
#endif
break;
}
case SHADER_EVAL_EMISSION:
{
shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_EMISSION);
out = shader_emissive_eval(kg, &sd);
break;
}
/* light passes */
case SHADER_EVAL_AO:
{
out = L.ao;
break;
}
case SHADER_EVAL_COMBINED:
{
out = path_radiance_clamp_and_sum(kg, &L);
break;
}
case SHADER_EVAL_SHADOW:
{
out = make_float3(L.shadow.x, L.shadow.y, L.shadow.z);
break;
}
case SHADER_EVAL_DIFFUSE_DIRECT:
{
shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
out = safe_divide_color(L.direct_diffuse, shader_bsdf_diffuse(kg, &sd));
break;
}
case SHADER_EVAL_GLOSSY_DIRECT:
{
shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
out = safe_divide_color(L.direct_glossy, shader_bsdf_glossy(kg, &sd));
break;
}
case SHADER_EVAL_TRANSMISSION_DIRECT:
{
shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
out = safe_divide_color(L.direct_transmission, shader_bsdf_transmission(kg, &sd));
break;
}
case SHADER_EVAL_SUBSURFACE_DIRECT:
{
#ifdef __SUBSURFACE__
shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
out = safe_divide_color(L.direct_subsurface, shader_bsdf_subsurface(kg, &sd));
#endif
break;
}
case SHADER_EVAL_DIFFUSE_INDIRECT:
{
shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
out = safe_divide_color(L.indirect_diffuse, shader_bsdf_diffuse(kg, &sd));
break;
}
case SHADER_EVAL_GLOSSY_INDIRECT:
{
shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
out = safe_divide_color(L.indirect_glossy, shader_bsdf_glossy(kg, &sd));
break;
}
case SHADER_EVAL_TRANSMISSION_INDIRECT:
{
shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
out = safe_divide_color(L.indirect_transmission, shader_bsdf_transmission(kg, &sd));
break;
}
case SHADER_EVAL_SUBSURFACE_INDIRECT:
{
#ifdef __SUBSURFACE__
shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
out = safe_divide_color(L.indirect_subsurface, shader_bsdf_subsurface(kg, &sd));
#endif
break;
}
/* extra */
case SHADER_EVAL_ENVIRONMENT:
{
/* setup ray */
Ray ray;
ray.P = make_float3(0.0f, 0.0f, 0.0f);
ray.D = normalize(P);
ray.t = 0.0f;
#ifdef __CAMERA_MOTION__
ray.time = 0.5f;
#endif
#ifdef __RAY_DIFFERENTIALS__
ray.dD = differential3_zero();
ray.dP = differential3_zero();
#endif
/* setup shader data */
shader_setup_from_background(kg, &sd, &ray, 0, 0);
/* evaluate */
int flag = 0; /* we can't know which type of BSDF this is for */
out = shader_eval_background(kg, &sd, flag, SHADER_CONTEXT_MAIN);
break;
}
default:
{
/* no real shader, returning the position of the verts for debugging */
out = normalize(P);
break;
}
}
/* write output */
output[i] = make_float4(out.x, out.y, out.z, 1.0f);
return;
}
ccl_device void kernel_shader_evaluate(KernelGlobals *kg, ccl_global uint4 *input, ccl_global float4 *output, ShaderEvalType type, int i)
{
if(type >= SHADER_EVAL_BAKE) {
kernel_bake_evaluate(kg, input, output, type, i);
return;
}
ShaderData sd;
uint4 in = input[i];
float3 out;

View File

@ -212,7 +212,9 @@ ccl_device void kernel_branched_path_integrate_direct_lighting(KernelGlobals *kg
}
}
ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray, ccl_global float *buffer,
#endif
ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray,
float3 throughput, int num_samples, PathState state, PathRadiance *L)
{
/* path iteration */
@ -378,7 +380,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray, ccl_g
}
#endif
#ifdef __EMISSION__
#if defined(__EMISSION__) && defined(__BRANCHED_PATH__)
if(kernel_data.integrator.use_direct_light) {
bool all = kernel_data.integrator.sample_all_lights_indirect;
kernel_branched_path_integrate_direct_lighting(kg, rng, &sd, &state, throughput, 1.0f, L, all);
@ -456,10 +458,6 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray, ccl_g
}
}
#endif
#ifdef __SUBSURFACE__
ccl_device_inline bool kernel_path_integrate_lighting(KernelGlobals *kg, RNG *rng,
ShaderData *sd, float3 *throughput, PathState *state, PathRadiance *L, Ray *ray)
{
@ -569,7 +567,39 @@ ccl_device_inline bool kernel_path_integrate_lighting(KernelGlobals *kg, RNG *rn
}
}
ccl_device void kernel_path_ao(KernelGlobals *kg, ShaderData *sd, PathRadiance *L, PathState *state, RNG *rng, float3 throughput)
{
/* todo: solve correlation */
float bsdf_u, bsdf_v;
path_state_rng_2D(kg, rng, state, PRNG_BSDF_U, &bsdf_u, &bsdf_v);
float ao_factor = kernel_data.background.ao_factor;
float3 ao_N;
float3 ao_bsdf = shader_bsdf_ao(kg, sd, ao_factor, &ao_N);
float3 ao_D;
float ao_pdf;
float3 ao_alpha = shader_bsdf_alpha(kg, sd);
sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
if(dot(sd->Ng, ao_D) > 0.0f && ao_pdf != 0.0f) {
Ray light_ray;
float3 ao_shadow;
light_ray.P = ray_offset(sd->P, sd->Ng);
light_ray.D = ao_D;
light_ray.t = kernel_data.background.ao_distance;
#ifdef __OBJECT_MOTION__
light_ray.time = sd->time;
#endif
light_ray.dP = sd->dP;
light_ray.dD = differential3_zero();
if(!shadow_blocked(kg, state, &light_ray, &ao_shadow))
path_radiance_accum_ao(L, throughput, ao_alpha, ao_bsdf, ao_shadow, state->bounce);
}
}
ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, Ray ray, ccl_global float *buffer)
{
@ -738,35 +768,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
#ifdef __AO__
/* ambient occlusion */
if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
/* todo: solve correlation */
float bsdf_u, bsdf_v;
path_state_rng_2D(kg, rng, &state, PRNG_BSDF_U, &bsdf_u, &bsdf_v);
float ao_factor = kernel_data.background.ao_factor;
float3 ao_N;
float3 ao_bsdf = shader_bsdf_ao(kg, &sd, ao_factor, &ao_N);
float3 ao_D;
float ao_pdf;
float3 ao_alpha = shader_bsdf_alpha(kg, &sd);
sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
if(dot(sd.Ng, ao_D) > 0.0f && ao_pdf != 0.0f) {
Ray light_ray;
float3 ao_shadow;
light_ray.P = ray_offset(sd.P, sd.Ng);
light_ray.D = ao_D;
light_ray.t = kernel_data.background.ao_distance;
#ifdef __OBJECT_MOTION__
light_ray.time = sd.time;
#endif
light_ray.dP = sd.dP;
light_ray.dD = differential3_zero();
if(!shadow_blocked(kg, &state, &light_ray, &ao_shadow))
path_radiance_accum_ao(&L, throughput, ao_alpha, ao_bsdf, ao_shadow, state.bounce);
}
kernel_path_ao(kg, &sd, &L, &state, rng, throughput);
}
#endif
@ -803,7 +805,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
hit_state.ray_t = 0.0f;
#endif
kernel_path_indirect(kg, rng, hit_ray, buffer, tp, state.num_samples, hit_state, &L);
kernel_path_indirect(kg, rng, hit_ray, tp, state.num_samples, hit_state, &L);
/* for render passes, sum and reset indirect light pass variables
* for the next samples */
@ -1022,7 +1024,7 @@ ccl_device_noinline void kernel_branched_path_integrate_lighting(KernelGlobals *
ps.ray_t = 0.0f;
#endif
kernel_path_indirect(kg, rng, bsdf_ray, buffer, tp*num_samples_inv, num_samples, ps, L);
kernel_path_indirect(kg, rng, bsdf_ray, tp*num_samples_inv, num_samples, ps, L);
/* for render passes, sum and reset indirect light pass variables
* for the next samples */
@ -1110,7 +1112,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
if(result == VOLUME_PATH_SCATTERED) {
/* todo: use all-light sampling */
if(kernel_path_integrate_scatter_lighting(kg, rng, &volume_sd, &tp, &ps, &L, &pray, num_samples_inv)) {
kernel_path_indirect(kg, rng, pray, buffer, tp*num_samples_inv, num_samples, ps, &L);
kernel_path_indirect(kg, rng, pray, tp*num_samples_inv, num_samples, ps, &L);
/* for render passes, sum and reset indirect light pass variables
* for the next samples */
@ -1150,7 +1152,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
if(result == VOLUME_PATH_SCATTERED) {
/* todo: use all-light sampling */
if(kernel_path_integrate_scatter_lighting(kg, rng, &volume_sd, &tp, &ps, &L, &pray, num_samples_inv)) {
kernel_path_indirect(kg, rng, pray, buffer, tp*num_samples_inv, num_samples, ps, &L);
kernel_path_indirect(kg, rng, pray, tp*num_samples_inv, num_samples, ps, &L);
/* for render passes, sum and reset indirect light pass variables
* for the next samples */

View File

@ -160,7 +160,35 @@ typedef uint RNG;
typedef enum ShaderEvalType {
SHADER_EVAL_DISPLACE,
SHADER_EVAL_BACKGROUND
SHADER_EVAL_BACKGROUND,
/* bake types */
SHADER_EVAL_BAKE, /* no real shade, it's used in the code to
* differentiate the type of shader eval from the above
*/
/* data passes */
SHADER_EVAL_NORMAL,
SHADER_EVAL_UV,
SHADER_EVAL_DIFFUSE_COLOR,
SHADER_EVAL_GLOSSY_COLOR,
SHADER_EVAL_TRANSMISSION_COLOR,
SHADER_EVAL_SUBSURFACE_COLOR,
SHADER_EVAL_EMISSION,
/* light passes */
SHADER_EVAL_AO,
SHADER_EVAL_COMBINED,
SHADER_EVAL_SHADOW,
SHADER_EVAL_DIFFUSE_DIRECT,
SHADER_EVAL_GLOSSY_DIRECT,
SHADER_EVAL_TRANSMISSION_DIRECT,
SHADER_EVAL_SUBSURFACE_DIRECT,
SHADER_EVAL_DIFFUSE_INDIRECT,
SHADER_EVAL_GLOSSY_INDIRECT,
SHADER_EVAL_TRANSMISSION_INDIRECT,
SHADER_EVAL_SUBSURFACE_INDIRECT,
/* extra */
SHADER_EVAL_ENVIRONMENT,
} ShaderEvalType;
/* Path Tracing
@ -281,7 +309,8 @@ typedef enum PassType {
PASS_MIST = 2097152,
PASS_SUBSURFACE_DIRECT = 4194304,
PASS_SUBSURFACE_INDIRECT = 8388608,
PASS_SUBSURFACE_COLOR = 16777216
PASS_SUBSURFACE_COLOR = 16777216,
PASS_LIGHT = 33554432, /* no real pass, used to force use_light_pass */
} PassType;
#define PASS_ALL (~0)

View File

@ -16,6 +16,7 @@ set(INC_SYS
set(SRC
attribute.cpp
background.cpp
bake.cpp
blackbody.cpp
buffers.cpp
camera.cpp
@ -43,6 +44,7 @@ set(SRC
set(SRC_HEADERS
attribute.h
bake.h
background.h
blackbody.h
buffers.h

View File

@ -0,0 +1,183 @@
/*
* Copyright 2011-2014 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 "bake.h"
CCL_NAMESPACE_BEGIN
BakeData::BakeData(const int object, const int tri_offset, const int num_pixels):
m_object(object),
m_tri_offset(tri_offset),
m_num_pixels(num_pixels)
{
m_primitive.resize(num_pixels);
m_u.resize(num_pixels);
m_v.resize(num_pixels);
}
BakeData::~BakeData()
{
m_primitive.clear();
m_u.clear();
m_v.clear();
}
void BakeData::set(int i, int prim, float uv[2])
{
m_primitive[i] = (prim == -1 ? -1 : m_tri_offset + prim);
m_u[i] = uv[0];
m_v[i] = uv[1];
}
int BakeData::object()
{
return m_object;
}
int BakeData::size()
{
return m_num_pixels;
}
bool BakeData::is_valid(int i)
{
return m_primitive[i] != -1;
}
uint4 BakeData::data(int i)
{
return make_uint4(
m_object,
m_primitive[i],
__float_as_int(m_u[i]),
__float_as_int(m_v[i])
);
}
BakeManager::BakeManager()
{
m_bake_data = NULL;
m_is_baking = false;
need_update = true;
}
BakeManager::~BakeManager()
{
if(m_bake_data)
delete m_bake_data;
}
bool BakeManager::get_baking()
{
return m_is_baking;
}
void BakeManager::set_baking(const bool value)
{
m_is_baking = value;
}
BakeData *BakeManager::init(const int object, const int tri_offset, const int num_pixels)
{
m_bake_data = new BakeData(object, tri_offset, num_pixels);
return m_bake_data;
}
bool BakeManager::bake(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress, ShaderEvalType shader_type, BakeData *bake_data, float result[])
{
size_t limit = bake_data->size();
/* setup input for device task */
device_vector<uint4> d_input;
uint4 *d_input_data = d_input.resize(limit);
size_t d_input_size = 0;
for(size_t i = 0; i < limit; i++) {
d_input_data[d_input_size++] = bake_data->data(i);
}
if(d_input_size == 0)
return false;
/* run device task */
device_vector<float4> d_output;
d_output.resize(d_input_size);
/* needs to be up to data for attribute access */
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 task(DeviceTask::SHADER);
task.shader_input = d_input.device_pointer;
task.shader_output = d_output.device_pointer;
task.shader_eval_type = shader_type;
task.shader_x = 0;
task.shader_w = d_output.size();
task.get_cancel = function_bind(&Progress::get_cancel, &progress);
device->task_add(task);
device->task_wait();
if(progress.get_cancel()) {
device->mem_free(d_input);
device->mem_free(d_output);
m_is_baking = false;
return false;
}
device->mem_copy_from(d_output, 0, 1, d_output.size(), sizeof(float4));
device->mem_free(d_input);
device->mem_free(d_output);
/* read result */
int k = 0;
float4 *offset = (float4*)d_output.data_pointer;
size_t depth = 4;
for(size_t i = 0; i < limit; i++) {
size_t index = i * depth;
float4 out = offset[k++];
if(bake_data->is_valid(i)) {
for(size_t j=0; j < 4; j++) {
result[index + j] = out[j];
}
}
}
m_is_baking = false;
return true;
}
void BakeManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
{
if(!need_update)
return;
if(progress.get_cancel()) return;
need_update = false;
}
void BakeManager::device_free(Device *device, DeviceScene *dscene)
{
}
CCL_NAMESPACE_END

View File

@ -0,0 +1,72 @@
/*
* Copyright 2011-2014 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
*/
#ifndef __BAKE_H__
#define __BAKE_H__
#include "util_vector.h"
#include "device.h"
#include "scene.h"
#include "session.h"
CCL_NAMESPACE_BEGIN
class BakeData {
public:
BakeData(const int object, const int tri_offset, const int num_pixels);
~BakeData();
void set(int i, int prim, float uv[2]);
int object();
int size();
uint4 data(int i);
bool is_valid(int i);
private:
int m_object;
int m_tri_offset;
int m_num_pixels;
vector<int>m_primitive;
vector<float>m_u;
vector<float>m_v;
};
class BakeManager {
public:
BakeManager();
~BakeManager();
bool get_baking();
void set_baking(const bool value);
BakeData *init(const int object, const int tri_offset, const int num_pixels);
bool bake(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress, ShaderEvalType shader_type, BakeData *bake_data, float result[]);
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_free(Device *device, DeviceScene *dscene);
bool need_update;
private:
BakeData *m_bake_data;
bool m_is_baking;
};
CCL_NAMESPACE_END
#endif /* __BAKE_H__ */

View File

@ -155,6 +155,9 @@ void Pass::add(PassType type, vector<Pass>& passes)
pass.components = 4;
pass.exposure = false;
break;
case PASS_LIGHT:
/* ignores */
break;
}
passes.push_back(pass);
@ -393,6 +396,10 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
kfilm->pass_shadow = kfilm->pass_stride;
kfilm->use_light_pass = 1;
break;
case PASS_LIGHT:
kfilm->use_light_pass = 1;
break;
case PASS_NONE:
break;
}

View File

@ -29,7 +29,7 @@
CCL_NAMESPACE_BEGIN
static void shade_background_pixels(Device *device, DeviceScene *dscene, int res, vector<float3>& pixels)
static void shade_background_pixels(Device *device, DeviceScene *dscene, int res, vector<float3>& pixels, Progress& progress)
{
/* create input */
int width = res;
@ -66,6 +66,7 @@ static void shade_background_pixels(Device *device, DeviceScene *dscene, int res
main_task.shader_eval_type = SHADER_EVAL_BACKGROUND;
main_task.shader_x = 0;
main_task.shader_w = width*height;
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;
@ -396,7 +397,7 @@ void LightManager::device_update_background(Device *device, DeviceScene *dscene,
assert(res > 0);
vector<float3> pixels;
shade_background_pixels(device, dscene, res, pixels);
shade_background_pixels(device, dscene, res, pixels, progress);
if(progress.get_cancel())
return;

View File

@ -119,17 +119,21 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me
task.shader_eval_type = SHADER_EVAL_DISPLACE;
task.shader_x = 0;
task.shader_w = d_output.size();
task.get_cancel = function_bind(&Progress::get_cancel, &progress);
device->task_add(task);
device->task_wait();
if(progress.get_cancel()) {
device->mem_free(d_input);
device->mem_free(d_output);
return false;
}
device->mem_copy_from(d_output, 0, 1, d_output.size(), sizeof(float4));
device->mem_free(d_input);
device->mem_free(d_output);
if(progress.get_cancel())
return false;
/* read result */
done.clear();
done.resize(mesh->verts.size(), false);

View File

@ -17,6 +17,7 @@
#include <stdlib.h>
#include "background.h"
#include "bake.h"
#include "camera.h"
#include "curves.h"
#include "device.h"
@ -54,6 +55,7 @@ Scene::Scene(const SceneParams& params_, const DeviceInfo& device_info_)
image_manager = new ImageManager();
particle_system_manager = new ParticleSystemManager();
curve_system_manager = new CurveSystemManager();
bake_manager = new BakeManager();
/* OSL only works on the CPU */
if(device_info_.type == DEVICE_CPU)
@ -103,6 +105,8 @@ void Scene::free_memory(bool final)
particle_system_manager->device_free(device, &dscene);
curve_system_manager->device_free(device, &dscene);
bake_manager->device_free(device, &dscene);
if(!params.persistent_data || final)
image_manager->device_free(device, &dscene);
@ -122,6 +126,7 @@ void Scene::free_memory(bool final)
delete particle_system_manager;
delete curve_system_manager;
delete image_manager;
delete bake_manager;
}
}
@ -208,6 +213,11 @@ void Scene::device_update(Device *device_, Progress& progress)
if(progress.get_cancel()) return;
progress.set_status("Updating Baking");
bake_manager->device_update(device, &dscene, this, progress);
if(progress.get_cancel()) return;
progress.set_status("Updating Device", "Writing constant memory");
device->const_copy_to("__data", &dscene.data, sizeof(dscene.data));
}
@ -258,7 +268,8 @@ bool Scene::need_reset()
|| integrator->need_update
|| shader_manager->need_update
|| particle_system_manager->need_update
|| curve_system_manager->need_update);
|| curve_system_manager->need_update
|| bake_manager->need_update);
}
void Scene::reset()

View File

@ -51,6 +51,8 @@ class CurveSystemManager;
class Shader;
class ShaderManager;
class Progress;
class BakeManager;
class BakeData;
/* Scene Device Data */
@ -174,6 +176,7 @@ public:
ObjectManager *object_manager;
ParticleSystemManager *particle_system_manager;
CurveSystemManager *curve_system_manager;
BakeManager *bake_manager;
/* default shaders */
int default_surface;

View File

@ -23,6 +23,7 @@
#include "integrator.h"
#include "scene.h"
#include "session.h"
#include "bake.h"
#include "util_foreach.h"
#include "util_function.h"
@ -733,10 +734,14 @@ void Session::update_scene()
cam->tag_update();
}
/* number of samples is needed by multi jittered sampling pattern */
/* number of samples is needed by multi jittered
* sampling pattern and by baking */
Integrator *integrator = scene->integrator;
BakeManager *bake_manager = scene->bake_manager;
if(integrator->sampling_pattern == SAMPLING_PATTERN_CMJ) {
if(integrator->sampling_pattern == SAMPLING_PATTERN_CMJ ||
bake_manager->get_baking())
{
int aa_samples = tile_manager.num_samples;
if(aa_samples != integrator->aa_samples) {

View File

@ -136,6 +136,7 @@ public:
void set_samples(int samples);
void set_pause(bool pause);
void update_scene();
void device_free();
protected:
struct DelayedReset {
@ -147,7 +148,6 @@ protected:
void run();
void update_scene();
void update_status_time(bool show_pause = false, bool show_done = false);
void tonemap(int sample);