Cycles Bake
authorDalai Felinto <dfelinto@gmail.com>
Thu, 2 Jan 2014 21:05:07 +0000 (19:05 -0200)
committerDalai Felinto <dfelinto@gmail.com>
Sat, 3 May 2014 00:19:09 +0000 (21:19 -0300)
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

22 files changed:
intern/cycles/blender/addon/__init__.py
intern/cycles/blender/addon/engine.py
intern/cycles/blender/addon/properties.py
intern/cycles/blender/addon/ui.py
intern/cycles/blender/blender_python.cpp
intern/cycles/blender/blender_session.cpp
intern/cycles/blender/blender_session.h
intern/cycles/device/device_cpu.cpp
intern/cycles/kernel/kernel_accumulate.h
intern/cycles/kernel/kernel_displace.h
intern/cycles/kernel/kernel_path.h
intern/cycles/kernel/kernel_types.h
intern/cycles/render/CMakeLists.txt
intern/cycles/render/bake.cpp [new file with mode: 0644]
intern/cycles/render/bake.h [new file with mode: 0644]
intern/cycles/render/film.cpp
intern/cycles/render/light.cpp
intern/cycles/render/mesh_displace.cpp
intern/cycles/render/scene.cpp
intern/cycles/render/scene.h
intern/cycles/render/session.cpp
intern/cycles/render/session.h

index 9f42cc9bb0083d310c0857b666f453d5dcfa0c75..27d986900c8c32315af3bec98f19c6d0c50b4b6c 100644 (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:
index b9ce65588df939a2a1bc5ab3fa53c202953a4535..25a9e97a99b19b238bfb17a5cabb4a3bebc2a2de 100644 (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()
index 2b05c2148eb2e38163b0f6434e1bd264e9766c73..7205a2723955f7c91cfb2628ffb20b858494e1e1 100644 (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
index f35cb1abd2e9bf3e3db837ad8d6cabda3ce79586..5c8115b66123ef7cddd8ee74e4e653d711e1fc08 100644 (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"
index 8b04a869a8584099d5b6a4c29a697b8be82f27d8..658fccaf12e43dc4d7aa0d96ab957503dc645340 100644 (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, ""},
index f5e696bc582e2a3962181b809ff2fbd8f989270b..6f959d426801587ce660039e3f0680e47e08526a 100644 (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;
index d30e3eda870cd2a2af2cf46edd396b198a5bdc5a..0e44493d674fc7669f4ac9ca0c3514fadb4fb160 100644 (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);
 
index e14e403d82b6221e9bc39abee678535d13ef0724..c9cc7592028bdedc1fcfeb15d7eb667e2e6135d1 100644 (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;
                        }
                }
index 582a220ab3c66a62f7732431da0af4ff12baab56..82450b730976f810c361b88b7e55d0806d62f173 100644 (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
 
index 1935f72ce951757eeaf30bdedc42a99e4642b261..a2709e711d2d356e5c248bf742c3a6f365eb4150 100644 (file)
 
 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;
index 1ca6bd38ba9623f639ec76e5ca95796139e7b1d5..e71b58aa70906363c342bbc1924aed51748b8375 100644 (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 */
index f83345925ea3290cb7c754ea3a02323f3c873a47..b3656c38cae8166a52857d3c24c9340e0f04245e 100644 (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)
index 7d00ed921641b66318c70d8de65278aaf1962cc9..449c139198009b9a3129f8f28759eacf33e7dd4a 100644 (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
diff --git a/intern/cycles/render/bake.cpp b/intern/cycles/render/bake.cpp
new file mode 100644 (file)
index 0000000..2e3022e
--- /dev/null
@@ -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
diff --git a/intern/cycles/render/bake.h b/intern/cycles/render/bake.h
new file mode 100644 (file)
index 0000000..830a951
--- /dev/null
@@ -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__ */
+
index 30ad86a8d4cd9c65051d5d6fa32470c74dce2646..c1aefbcfbbcb25a2dbf2a802bba693a7d3ae8a5a 100644 (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;
                }
index dd5694582e60c4c0600c2997bcccb34f605e04e5..a5e3fabb19daea4f954f9587407e67b77102df9e 100644 (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;
index 09d3ce6a588f3612083827e36358b909240b5a2b..661fd9c66c1ff16a1a8fce34df277b6eabf03e00 100644 (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);
index 2ed4efe7f2b05f3d010d0f61a799b0c41bd3afc3..4a42b2c9e3510c0cc5d219b5ca387cbb36cee22c 100644 (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()
index b6a4d6c04362d3969a829bb66fa1ad72e4bbc21f..c913b4c59daacd882fa26fbd19f0ea90ce002f86 100644 (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;
index 9cf7f49754c2d58b4b76ac0f3d6d3b4bdd1c5fe3..28b44df6b368dbfdcafc1d529ee040dcebfe058f 100644 (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) {
index 8c597c431bb545e58267b080eb9e5655fdea822e..1e62515865244ea2bbd9872e663886c0e57efb08 100644 (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);