diff options
52 files changed, 1140 insertions, 309 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index e8bdc5375fc..577a0c9ba05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -304,7 +304,7 @@ endif() #----------------------------------------------------------------------------- # Check for conflicting/unsupported configurations -if(NOT WITH_BLENDER AND NOT WITH_PLAYER) +if(NOT WITH_BLENDER AND NOT WITH_PLAYER AND NOT WITH_CYCLES_TEST) message(FATAL_ERROR "At least one of WITH_BLENDER or WITH_PLAYER must be enabled, nothing to do!") endif() diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp index b954ff45e27..82f1338d86b 100644 --- a/intern/cycles/app/cycles_xml.cpp +++ b/intern/cycles/app/cycles_xml.cpp @@ -284,8 +284,7 @@ static void xml_read_camera(const XMLReadState& state, pugi::xml_node node) xml_read_float(&cam->farclip, node, "farclip"); xml_read_float(&cam->aperturesize, node, "aperturesize"); // 0.5*focallength/fstop xml_read_float(&cam->focaldistance, node, "focaldistance"); - xml_read_float(&cam->shutteropen, node, "shutteropen"); - xml_read_float(&cam->shutterclose, node, "shutterclose"); + xml_read_float(&cam->shuttertime, node, "shuttertime"); if(xml_equal_string(node, "type", "orthographic")) cam->type = CAMERA_ORTHOGRAPHIC; @@ -705,7 +704,7 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node) } /* temporary for test compatibility */ - mesh->attributes.remove(Attribute::STD_VERTEX_NORMAL); + mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); } /* Patch */ @@ -766,7 +765,7 @@ static void xml_read_patch(const XMLReadState& state, pugi::xml_node node) delete patch; /* temporary for test compatibility */ - mesh->attributes.remove(Attribute::STD_VERTEX_NORMAL); + mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); } } diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 0ed08589327..8480b0a5256 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -94,6 +94,29 @@ class CyclesRender_PT_integrator(CyclesButtonsPanel, Panel): col.prop(cscene, "blur_glossy") +class CyclesRender_PT_motion_blur(CyclesButtonsPanel, Panel): + bl_label = "Motion Blur" + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + return False + + def draw_header(self, context): + rd = context.scene.render + + self.layout.prop(rd, "use_motion_blur", text="") + + def draw(self, context): + layout = self.layout + + rd = context.scene.render + layout.active = rd.use_motion_blur + + row = layout.row() + row.prop(rd, "motion_blur_shutter") + + class CyclesRender_PT_film(CyclesButtonsPanel, Panel): bl_label = "Film" @@ -202,10 +225,10 @@ class CyclesRender_PT_layers(CyclesButtonsPanel, Panel): col.prop(rl, "use_pass_combined") col.prop(rl, "use_pass_z") col.prop(rl, "use_pass_normal") + col.prop(rl, "use_pass_vector") + col.prop(rl, "use_pass_uv") col.prop(rl, "use_pass_object_index") col.prop(rl, "use_pass_material_index") - col.prop(rl, "use_pass_emit") - col.prop(rl, "use_pass_environment") col.prop(rl, "use_pass_ambient_occlusion") col.prop(rl, "use_pass_shadow") @@ -227,6 +250,9 @@ class CyclesRender_PT_layers(CyclesButtonsPanel, Panel): row.prop(rl, "use_pass_transmission_indirect", text="Indirect", toggle=True) row.prop(rl, "use_pass_transmission_color", text="Color", toggle=True) + col.prop(rl, "use_pass_emit", text="Emission") + col.prop(rl, "use_pass_environment") + class Cycles_PT_post_processing(CyclesButtonsPanel, Panel): bl_label = "Post Processing" diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp index a21b22bc35a..55a32d8fc10 100644 --- a/intern/cycles/blender/blender_camera.cpp +++ b/intern/cycles/blender/blender_camera.cpp @@ -35,6 +35,7 @@ struct BlenderCamera { float ortho_scale; float lens; + float shuttertime; float aperturesize; uint apertureblades; @@ -64,6 +65,7 @@ static void blender_camera_init(BlenderCamera *bcam) bcam->sensor_width = 32.0f; bcam->sensor_height = 18.0f; bcam->sensor_fit = BlenderCamera::AUTO; + bcam->shuttertime = 1.0f; } static float blender_camera_focal_distance(BL::Object b_ob, BL::Camera b_camera) @@ -132,6 +134,28 @@ static void blender_camera_from_object(BlenderCamera *bcam, BL::Object b_ob) } } +static Transform blender_camera_matrix(const Transform& tfm, CameraType type) +{ + Transform result; + + if(type == CAMERA_ENVIRONMENT) { + /* make it so environment camera needs to be pointed in the direction + of the positive x-axis to match an environment texture, this way + it is looking at the center of the texture */ + result = tfm * + make_transform( 0.0f, -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + -1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); + } + else { + /* note the blender camera points along the negative z-axis */ + result = tfm * transform_scale(1.0f, 1.0f, -1.0f); + } + + return transform_clear_scale(result); +} + static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int height) { /* copy camera to compare later */ @@ -224,24 +248,11 @@ static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int cam->bladesrotation = bcam->aperturerotation; /* transform */ - cam->matrix = bcam->matrix; - - if(bcam->type == CAMERA_ENVIRONMENT) { - /* make it so environment camera needs to be pointed in the direction - of the positive x-axis to match an environment texture, this way - it is looking at the center of the texture */ - cam->matrix = cam->matrix * - make_transform( 0.0f, -1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - -1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f); - } - else { - /* note the blender camera points along the negative z-axis */ - cam->matrix = cam->matrix * transform_scale(1.0f, 1.0f, -1.0f); - } - - cam->matrix = transform_clear_scale(cam->matrix); + cam->matrix = blender_camera_matrix(bcam->matrix, bcam->type); + cam->motion.pre = cam->matrix; + cam->motion.post = cam->matrix; + cam->use_motion = false; + cam->shuttertime = bcam->shuttertime; /* set update flag */ if(cam->modified(prevcam)) @@ -260,6 +271,7 @@ void BlenderSync::sync_camera(BL::Object b_override, int width, int height) bcam.pixelaspect.x = r.pixel_aspect_x(); bcam.pixelaspect.y = r.pixel_aspect_y(); + bcam.shuttertime = r.motion_blur_shutter(); /* camera object */ BL::Object b_ob = b_scene.camera(); @@ -277,6 +289,23 @@ void BlenderSync::sync_camera(BL::Object b_override, int width, int height) blender_camera_sync(cam, &bcam, width, height); } +void BlenderSync::sync_camera_motion(BL::Object b_ob, int motion) +{ + Camera *cam = scene->camera; + + Transform tfm = get_transform(b_ob.matrix_world()); + tfm = blender_camera_matrix(tfm, cam->type); + + if(tfm != cam->matrix) { + if(motion == -1) + cam->motion.pre = tfm; + else + cam->motion.post = tfm; + + cam->use_motion = true; + } +} + /* Sync 3D View Camera */ void BlenderSync::sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height) @@ -288,6 +317,7 @@ void BlenderSync::sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int bcam.nearclip = b_v3d.clip_start(); bcam.farclip = b_v3d.clip_end(); bcam.lens = b_v3d.lens(); + bcam.shuttertime = b_scene.render().motion_blur_shutter(); if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA) { /* camera view */ diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index 7caa6b3d511..f77e6551de0 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -33,30 +33,6 @@ CCL_NAMESPACE_BEGIN /* Find/Add */ -static bool mesh_need_attribute(Scene *scene, Mesh *mesh, Attribute::Standard std) -{ - if(std == Attribute::STD_NONE) - return false; - - foreach(uint shader, mesh->used_shaders) - if(scene->shaders[shader]->attributes.find(std)) - return true; - - return false; -} - -static bool mesh_need_attribute(Scene *scene, Mesh *mesh, ustring name) -{ - if(name == ustring()) - return false; - - foreach(uint shader, mesh->used_shaders) - if(scene->shaders[shader]->attributes.find(name)) - return true; - - return false; -} - static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<uint>& used_shaders) { /* create vertices */ @@ -66,7 +42,7 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector< mesh->verts.push_back(get_float3(v->co())); /* create vertex normals */ - Attribute *attr_N = mesh->attributes.add(Attribute::STD_VERTEX_NORMAL); + Attribute *attr_N = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL); float3 *N = attr_N->data_float3(); for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++N) @@ -94,8 +70,8 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector< /* create generated coordinates. todo: we should actually get the orco coordinates from modifiers, for now we use texspace loc/size which is available in the api. */ - if(mesh_need_attribute(scene, mesh, Attribute::STD_GENERATED)) { - Attribute *attr = mesh->attributes.add(Attribute::STD_GENERATED); + if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) { + Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED); float3 loc = get_float3(b_mesh.texspace_location()); float3 size = get_float3(b_mesh.texspace_size()); @@ -118,7 +94,7 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector< BL::Mesh::tessface_vertex_colors_iterator l; for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l) { - if(!mesh_need_attribute(scene, mesh, ustring(l->name().c_str()))) + if(!mesh->need_attribute(scene, ustring(l->name().c_str()))) continue; Attribute *attr = mesh->attributes.add( @@ -150,10 +126,10 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector< BL::Mesh::tessface_uv_textures_iterator l; for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) { - Attribute::Standard std = (l->active_render())? Attribute::STD_UV: Attribute::STD_NONE; + AttributeStandard std = (l->active_render())? ATTR_STD_UV: ATTR_STD_NONE; ustring name = ustring(l->name().c_str()); - if(!(mesh_need_attribute(scene, mesh, name) || mesh_need_attribute(scene, mesh, std))) + if(!(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std))) continue; Attribute *attr; @@ -329,5 +305,38 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool holdout, bool object_updated) return mesh; } +void BlenderSync::sync_mesh_motion(BL::Object b_ob, Mesh *mesh, int motion) +{ + /* todo: displacement, subdivision */ + BL::ID b_ob_data = b_ob.data(); + size_t size = mesh->verts.size(); + + /* skip objects without deforming modifiers. this is not a totally reliable, + * would need a more extensive check to see which objects are animated */ + if(!size || !ccl::object_is_deform_modified(b_ob, b_scene, preview)) + return; + + /* get derived mesh */ + BL::Mesh b_mesh = object_to_mesh(b_ob, b_scene, true, !preview); + + if(b_mesh) { + BL::Mesh::vertices_iterator v; + AttributeStandard std = (motion == -1)? ATTR_STD_MOTION_PRE: ATTR_STD_MOTION_POST; + Attribute *attr_M = mesh->attributes.add(std); + float3 *M = attr_M->data_float3(); + size_t i = 0, size = mesh->verts.size(); + + for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end() && i < size; ++v, M++, i++) + *M = get_float3(v->co()); + + /* if number of vertices changed, or if coordinates stayed the same, drop it */ + if(i != size || memcmp(M, &mesh->verts[0], sizeof(float3)*size) == 0) + mesh->attributes.remove(std); + + /* free derived mesh */ + object_remove_mesh(b_data, b_mesh); + } +} + CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 96faee19af4..b1cd778c6d3 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -16,6 +16,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "camera.h" #include "graph.h" #include "light.h" #include "mesh.h" @@ -188,11 +189,12 @@ void BlenderSync::sync_background_light() /* Object */ -void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm, uint layer_flag) +void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm, uint layer_flag, int motion) { /* light is handled separately */ if(object_is_light(b_ob)) { - sync_light(b_parent, b_index, b_ob, tfm); + if(!motion) + sync_light(b_parent, b_index, b_ob, tfm); return; } @@ -200,9 +202,31 @@ void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob, if(!object_is_mesh(b_ob)) return; - /* test if we need to sync */ + /* key to lookup object */ ObjectKey key(b_parent, b_index, b_ob); Object *object; + + /* motion vector case */ + if(motion) { + object = object_map.find(key); + + if(object) { + if(tfm != object->tfm) { + if(motion == -1) + object->motion.pre = tfm; + else + object->motion.post = tfm; + + object->use_motion = true; + } + + sync_mesh_motion(b_ob, object->mesh, motion); + } + + return; + } + + /* test if we need to sync */ bool object_updated = false; if(object_map.sync(&object, b_ob, b_parent, key)) @@ -219,6 +243,9 @@ void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob, object->name = b_ob.name().c_str(); object->pass_id = b_ob.pass_index(); object->tfm = tfm; + object->motion.pre = tfm; + object->motion.post = tfm; + object->use_motion = false; /* visibility flags for both parent */ object->visibility = object_ray_visibility(b_ob) & PATH_RAY_ALL; @@ -238,16 +265,18 @@ void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob, /* Object Loop */ -void BlenderSync::sync_objects(BL::SpaceView3D b_v3d) +void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion) { /* layer data */ uint scene_layer = render_layer.scene_layer; - /* prepare for sync */ - light_map.pre_sync(); - mesh_map.pre_sync(); - object_map.pre_sync(); - mesh_synced.clear(); + if(!motion) { + /* prepare for sync */ + light_map.pre_sync(); + mesh_map.pre_sync(); + object_map.pre_sync(); + mesh_synced.clear(); + } /* object loop */ BL::Scene::objects_iterator b_ob; @@ -270,7 +299,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d) bool dup_hide = (b_v3d)? b_dup_ob.hide(): b_dup_ob.hide_render(); if(!(b_dup->hide() || dup_hide)) - sync_object(*b_ob, b_index, b_dup_ob, tfm, ob_layer); + sync_object(*b_ob, b_index, b_dup_ob, tfm, ob_layer, motion); b_index++; } @@ -296,21 +325,50 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d) if(!hide) { /* object itself */ Transform tfm = get_transform(b_ob->matrix_world()); - sync_object(*b_ob, 0, *b_ob, tfm, ob_layer); + sync_object(*b_ob, 0, *b_ob, tfm, ob_layer, motion); } } } - sync_background_light(); + if(!motion) { + sync_background_light(); + + /* handle removed data and modified pointers */ + if(light_map.post_sync()) + scene->light_manager->tag_update(scene); + if(mesh_map.post_sync()) + scene->mesh_manager->tag_update(scene); + if(object_map.post_sync()) + scene->object_manager->tag_update(scene); + mesh_synced.clear(); + } +} + +void BlenderSync::sync_motion(BL::SpaceView3D b_v3d, BL::Object b_override) +{ + if(scene->need_motion() == Scene::MOTION_NONE) + return; + + /* get camera object here to deal with camera switch */ + BL::Object b_cam = b_scene.camera(); + if(b_override) + b_cam = b_override; + + /* go back and forth one frame */ + int frame = b_scene.frame_current(); + + for(int motion = -1; motion <= 1; motion += 2) { + scene_frame_set(b_scene, frame + motion); + + /* camera object */ + if(b_cam) + sync_camera_motion(b_cam, motion); + + /* mesh objects */ + sync_objects(b_v3d, motion); + } - /* handle removed data and modified pointers */ - if(light_map.post_sync()) - scene->light_manager->tag_update(scene); - if(mesh_map.post_sync()) - scene->mesh_manager->tag_update(scene); - if(object_map.post_sync()) - scene->object_manager->tag_update(scene); - mesh_synced.clear(); + scene_frame_set(b_scene, frame); } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 5ece7aa26e2..f79b9995165 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -91,7 +91,7 @@ void BlenderSession::create_session() /* create sync */ sync = new BlenderSync(b_data, b_scene, scene, !background); - sync->sync_data(b_v3d); + sync->sync_data(b_v3d, b_engine.camera_override()); if(b_rv3d) sync->sync_view(b_v3d, b_rv3d, width, height); @@ -130,6 +130,8 @@ static PassType get_pass_type(BL::RenderPass b_pass) return PASS_OBJECT_ID; case BL::RenderPass::type_UV: return PASS_UV; + case BL::RenderPass::type_VECTOR: + return PASS_MOTION; case BL::RenderPass::type_MATERIAL_INDEX: return PASS_MATERIAL_ID; @@ -168,7 +170,6 @@ static PassType get_pass_type(BL::RenderPass b_pass) case BL::RenderPass::type_REFRACTION: case BL::RenderPass::type_SPECULAR: case BL::RenderPass::type_REFLECTION: - case BL::RenderPass::type_VECTOR: case BL::RenderPass::type_MIST: return PASS_NONE; } @@ -209,6 +210,8 @@ void BlenderSession::render() BL::RenderPass b_pass(*b_pass_iter); PassType pass_type = get_pass_type(b_pass); + if(pass_type == PASS_MOTION && scene->integrator->motion_blur) + continue; if(pass_type != PASS_NONE) Pass::add(pass_type, passes); } @@ -219,7 +222,7 @@ void BlenderSession::render() scene->film->tag_update(scene); /* update scene */ - sync->sync_data(b_v3d, b_iter->name().c_str()); + sync->sync_data(b_v3d, b_engine.camera_override(), b_iter->name().c_str()); /* update session */ int samples = sync->get_layer_samples(); @@ -310,7 +313,7 @@ void BlenderSession::synchronize() } /* data and camera synchronize */ - sync->sync_data(b_v3d); + sync->sync_data(b_v3d, b_engine.camera_override()); if(b_rv3d) sync->sync_view(b_v3d, b_rv3d, width, height); diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index 41cd200d003..24cf10bc028 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -121,19 +121,21 @@ bool BlenderSync::sync_recalc() return recalc; } -void BlenderSync::sync_data(BL::SpaceView3D b_v3d, const char *layer) +void BlenderSync::sync_data(BL::SpaceView3D b_v3d, BL::Object b_override, const char *layer) { sync_render_layers(b_v3d, layer); sync_integrator(); sync_film(); sync_shaders(); sync_objects(b_v3d); + sync_motion(b_v3d, b_override); } /* Integrator */ void BlenderSync::sync_integrator() { + BL::RenderSettings r = b_scene.render(); PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); experimental = (RNA_enum_get(&cscene, "feature_set") != 0); @@ -160,6 +162,9 @@ void BlenderSync::sync_integrator() integrator->layer_flag = render_layer.layer; integrator->sample_clamp = get_float(cscene, "sample_clamp"); +#ifdef __MOTION__ + integrator->motion_blur = (!preview && r.use_motion_blur()); +#endif if(integrator->modified(previntegrator)) integrator->tag_update(scene); diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index ab8e4bd8d00..acdcea1ef9b 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -54,7 +54,7 @@ public: /* sync */ bool sync_recalc(); - void sync_data(BL::SpaceView3D b_v3d, const char *layer = 0); + void sync_data(BL::SpaceView3D b_v3d, BL::Object b_override, const char *layer = 0); void sync_camera(BL::Object b_override, int width, int height); void sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height); int get_layer_samples() { return render_layer.samples; } @@ -69,7 +69,8 @@ private: /* sync */ void sync_lamps(); void sync_materials(); - void sync_objects(BL::SpaceView3D b_v3d); + void sync_objects(BL::SpaceView3D b_v3d, int motion = 0); + void sync_motion(BL::SpaceView3D b_v3d, BL::Object b_override); void sync_film(); void sync_integrator(); void sync_view(); @@ -79,9 +80,11 @@ private: void sync_nodes(Shader *shader, BL::ShaderNodeTree b_ntree); Mesh *sync_mesh(BL::Object b_ob, bool holdout, bool object_updated); - void sync_object(BL::Object b_parent, int b_index, BL::Object b_object, Transform& tfm, uint layer_flag); + void sync_object(BL::Object b_parent, int b_index, BL::Object b_object, Transform& tfm, uint layer_flag, int motion); void sync_light(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm); void sync_background_light(); + void sync_mesh_motion(BL::Object b_ob, Mesh *mesh, int motion); + void sync_camera_motion(BL::Object b_ob, int motion); /* util */ void find_shader(BL::ID id, vector<uint>& used_shaders, int default_shader); diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index 67f3a3ab7d9..9184e14bc76 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -49,8 +49,10 @@ void RE_engine_update_progress(struct RenderEngine *engine, float progress); void engine_tag_redraw(void *engine); void engine_tag_update(void *engine); int rna_Object_is_modified(void *ob, void *scene, int settings); +int rna_Object_is_deform_modified(void *ob, void *scene, int settings); void BLI_timestr(double _time, char *str); void rna_ColorRamp_eval(void *coba, float position, float color[4]); +void rna_Scene_frame_set(void *scene, int frame, float subframe); } @@ -94,6 +96,16 @@ static inline bool object_is_modified(BL::Object self, BL::Scene scene, bool pre return rna_Object_is_modified(self.ptr.data, scene.ptr.data, (preview)? (1<<0): (1<<1))? true: false; } +static inline bool object_is_deform_modified(BL::Object self, BL::Scene scene, bool preview) +{ + return rna_Object_is_deform_modified(self.ptr.data, scene.ptr.data, (preview)? (1<<0): (1<<1))? true: false; +} + +static inline void scene_frame_set(BL::Scene scene, int frame) +{ + rna_Scene_frame_set(scene.ptr.data, frame, 0.0f); +} + /* Utilities */ static inline Transform get_transform(BL::Array<float, 16> array) diff --git a/intern/cycles/kernel/kernel_bvh.h b/intern/cycles/kernel/kernel_bvh.h index 523ae8ae926..5da4253bd86 100644 --- a/intern/cycles/kernel/kernel_bvh.h +++ b/intern/cycles/kernel/kernel_bvh.h @@ -57,7 +57,7 @@ __device_inline float3 bvh_inverse_direction(float3 dir) __device_inline void bvh_instance_push(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *idir, float *t, const float tmax) { - Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM); + Transform tfm = object_fetch_transform(kg, object, ray->time, OBJECT_INVERSE_TRANSFORM); *P = transform_point(&tfm, ray->P); @@ -74,7 +74,7 @@ __device_inline void bvh_instance_push(KernelGlobals *kg, int object, const Ray __device_inline void bvh_instance_pop(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *idir, float *t, const float tmax) { - Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM); + Transform tfm = object_fetch_transform(kg, object, ray->time, OBJECT_TRANSFORM); if(*t != FLT_MAX) *t *= len(transform_direction(&tfm, 1.0f/(*idir))); @@ -341,7 +341,7 @@ __device_inline float3 ray_offset(float3 P, float3 Ng) #endif } -__device_inline float3 bvh_triangle_refine(KernelGlobals *kg, const Intersection *isect, const Ray *ray) +__device_inline float3 bvh_triangle_refine(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray) { float3 P = ray->P; float3 D = ray->D; @@ -349,7 +349,11 @@ __device_inline float3 bvh_triangle_refine(KernelGlobals *kg, const Intersection #ifdef __INTERSECTION_REFINE__ if(isect->object != ~0) { - Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM); +#ifdef __MOTION__ + Transform tfm = sd->ob_itfm; +#else + Transform tfm = object_fetch_transform(kg, isect->object, ray->time, OBJECT_INVERSE_TRANSFORM); +#endif P = transform_point(&tfm, P); D = transform_direction(&tfm, D*t); @@ -366,7 +370,12 @@ __device_inline float3 bvh_triangle_refine(KernelGlobals *kg, const Intersection P = P + D*rt; if(isect->object != ~0) { - Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM); +#ifdef __MOTION__ + Transform tfm = sd->ob_tfm; +#else + Transform tfm = object_fetch_transform(kg, isect->object, ray->time, OBJECT_TRANSFORM); +#endif + P = transform_point(&tfm, P); } diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h index 99dac18d545..7b93ed7c0e6 100644 --- a/intern/cycles/kernel/kernel_camera.h +++ b/intern/cycles/kernel/kernel_camera.h @@ -63,6 +63,11 @@ __device void camera_sample_perspective(KernelGlobals *kg, float raster_x, float /* transform ray from camera to world */ Transform cameratoworld = kernel_data.cam.cameratoworld; +#ifdef __MOTION__ + if(ray->time != TIME_INVALID) + transform_motion_interpolate(&cameratoworld, &kernel_data.cam.motion, ray->time); +#endif + ray->P = transform_point(&cameratoworld, ray->P); ray->D = transform_direction(&cameratoworld, ray->D); ray->D = normalize(ray->D); @@ -101,6 +106,11 @@ __device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, floa /* transform ray from camera to world */ Transform cameratoworld = kernel_data.cam.cameratoworld; +#ifdef __MOTION__ + if(ray->time != TIME_INVALID) + transform_motion_interpolate(&cameratoworld, &kernel_data.cam.motion, ray->time); +#endif + ray->P = transform_point(&cameratoworld, ray->P); ray->D = transform_direction(&cameratoworld, ray->D); ray->D = normalize(ray->D); @@ -136,6 +146,11 @@ __device void camera_sample_environment(KernelGlobals *kg, float raster_x, float /* transform ray from camera to world */ Transform cameratoworld = kernel_data.cam.cameratoworld; +#ifdef __MOTION__ + if(ray->time != TIME_INVALID) + transform_motion_interpolate(&cameratoworld, &kernel_data.cam.motion, ray->time); +#endif + ray->P = transform_point(&cameratoworld, ray->P); ray->D = transform_direction(&cameratoworld, ray->D); ray->D = normalize(ray->D); @@ -162,14 +177,20 @@ __device void camera_sample_environment(KernelGlobals *kg, float raster_x, float /* Common */ -__device void camera_sample(KernelGlobals *kg, int x, int y, float filter_u, float filter_v, float lens_u, float lens_v, Ray *ray) +__device void camera_sample(KernelGlobals *kg, int x, int y, float filter_u, float filter_v, + float lens_u, float lens_v, float time, Ray *ray) { /* pixel filter */ float raster_x = x + kernel_tex_interp(__filter_table, filter_u, FILTER_TABLE_SIZE); float raster_y = y + kernel_tex_interp(__filter_table, filter_v, FILTER_TABLE_SIZE); +#ifdef __MOTION__ /* motion blur */ - //ray->time = lerp(time_t, kernel_data.cam.shutter_open, kernel_data.cam.shutter_close); + if(kernel_data.cam.shuttertime == 0.0f) + ray->time = TIME_INVALID; + else + ray->time = 0.5f + (time - 0.5f)*kernel_data.cam.shuttertime; +#endif /* sample */ if(kernel_data.cam.type == CAMERA_PERSPECTIVE) diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h index 764ac599991..cd7701a0c75 100644 --- a/intern/cycles/kernel/kernel_emission.h +++ b/intern/cycles/kernel/kernel_emission.h @@ -21,7 +21,7 @@ CCL_NAMESPACE_BEGIN /* Direction Emission */ __device float3 direct_emissive_eval(KernelGlobals *kg, float rando, - LightSample *ls, float u, float v, float3 I) + LightSample *ls, float u, float v, float3 I, float time) { /* setup shading at emitter */ ShaderData sd; @@ -40,7 +40,7 @@ __device float3 direct_emissive_eval(KernelGlobals *kg, float rando, else #endif { - shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v); + shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, time); ls->Ng = sd.Ng; /* no path flag, we're evaluating this for all closures. that's weak but @@ -76,7 +76,7 @@ __device bool direct_emission(KernelGlobals *kg, ShaderData *sd, int lindex, #endif { /* sample a light and position on int */ - light_sample(kg, randt, randu, randv, sd->P, &ls, &pdf); + light_sample(kg, randt, randu, randv, sd->time, sd->P, &ls, &pdf); } /* compute pdf */ @@ -87,7 +87,7 @@ __device bool direct_emission(KernelGlobals *kg, ShaderData *sd, int lindex, return false; /* evaluate closure */ - float3 light_eval = direct_emissive_eval(kg, rando, &ls, randu, randv, -ls.D); + float3 light_eval = direct_emissive_eval(kg, rando, &ls, randu, randv, -ls.D, sd->time); if(is_zero(light_eval)) return false; diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h index 42260577069..c2cf293cab3 100644 --- a/intern/cycles/kernel/kernel_light.h +++ b/intern/cycles/kernel/kernel_light.h @@ -251,7 +251,7 @@ __device float regular_light_pdf(KernelGlobals *kg, /* Triangle Light */ __device void triangle_light_sample(KernelGlobals *kg, int prim, int object, - float randu, float randv, LightSample *ls) + float randu, float randv, float time, LightSample *ls) { /* triangle, so get position, normal, shader */ ls->P = triangle_sample_MT(kg, prim, randu, randv); @@ -264,8 +264,11 @@ __device void triangle_light_sample(KernelGlobals *kg, int prim, int object, #ifdef __INSTANCING__ /* instance transform */ if(ls->object >= 0) { - object_position_transform(kg, ls->object, &ls->P); - object_normal_transform(kg, ls->object, &ls->Ng); + Transform tfm = object_fetch_transform(kg, ls->object, time, OBJECT_TRANSFORM); + Transform itfm = object_fetch_transform(kg, ls->object, time, OBJECT_INVERSE_TRANSFORM); + + ls->P = transform_point(&tfm, ls->P); + ls->Ng = transform_direction_transposed(&itfm, ls->Ng); } #endif } @@ -313,7 +316,7 @@ __device int light_distribution_sample(KernelGlobals *kg, float randt) /* Generic Light */ -__device void light_sample(KernelGlobals *kg, float randt, float randu, float randv, float3 P, LightSample *ls, float *pdf) +__device void light_sample(KernelGlobals *kg, float randt, float randu, float randv, float time, float3 P, LightSample *ls, float *pdf) { /* sample index */ int index = light_distribution_sample(kg, randt); @@ -324,7 +327,7 @@ __device void light_sample(KernelGlobals *kg, float randt, float randu, float ra if(prim >= 0) { int object = __float_as_int(l.w); - triangle_light_sample(kg, prim, object, randu, randv, ls); + triangle_light_sample(kg, prim, object, randu, randv, time, ls); } else { int point = -prim-1; diff --git a/intern/cycles/kernel/kernel_object.h b/intern/cycles/kernel/kernel_object.h index b676f58e5d4..262ca848f28 100644 --- a/intern/cycles/kernel/kernel_object.h +++ b/intern/cycles/kernel/kernel_object.h @@ -20,41 +20,87 @@ CCL_NAMESPACE_BEGIN enum ObjectTransform { OBJECT_TRANSFORM = 0, - OBJECT_INVERSE_TRANSFORM = 4, - OBJECT_NORMAL_TRANSFORM = 8, - OBJECT_PROPERTIES = 12 + OBJECT_INVERSE_TRANSFORM = 3, + OBJECT_PROPERTIES = 6, + OBJECT_TRANSFORM_MOTION_PRE = 8, + OBJECT_TRANSFORM_MOTION_POST = 12 }; -__device_inline Transform object_fetch_transform(KernelGlobals *kg, int object, enum ObjectTransform type) +__device_inline Transform object_fetch_transform(KernelGlobals *kg, int object, float time, enum ObjectTransform type) { Transform tfm; +#ifdef __MOTION__ + /* if we do motion blur */ + if(time != TIME_INVALID) { + int offset = object*OBJECT_SIZE + (int)OBJECT_TRANSFORM_MOTION_PRE; + float4 have_motion = kernel_tex_fetch(__objects, offset + 0); + + /* if this object have motion */ + if(have_motion.x != FLT_MAX) { + /* fetch motion transforms */ + MotionTransform motion; + + motion.pre.x = have_motion; + motion.pre.y = kernel_tex_fetch(__objects, offset + 1); + motion.pre.z = kernel_tex_fetch(__objects, offset + 2); + motion.pre.w = kernel_tex_fetch(__objects, offset + 3); + + motion.post.x = kernel_tex_fetch(__objects, offset + 4); + motion.post.y = kernel_tex_fetch(__objects, offset + 5); + motion.post.z = kernel_tex_fetch(__objects, offset + 6); + motion.post.w = kernel_tex_fetch(__objects, offset + 7); + + /* interpolate (todo: do only once per object) */ + transform_motion_interpolate(&tfm, &motion, time); + + /* invert */ + if(type == OBJECT_INVERSE_TRANSFORM) + tfm = transform_quick_inverse(tfm); + + return tfm; + } + } +#endif + int offset = object*OBJECT_SIZE + (int)type; tfm.x = kernel_tex_fetch(__objects, offset + 0); tfm.y = kernel_tex_fetch(__objects, offset + 1); tfm.z = kernel_tex_fetch(__objects, offset + 2); - tfm.w = kernel_tex_fetch(__objects, offset + 3); + tfm.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f); return tfm; } -__device_inline void object_position_transform(KernelGlobals *kg, int object, float3 *P) +__device_inline void object_position_transform(KernelGlobals *kg, ShaderData *sd, float3 *P) { - Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM); +#ifdef __MOTION__ + *P = transform_point(&sd->ob_tfm, *P); +#else + Transform tfm = object_fetch_transform(kg, sd->object, TIME_INVALID, OBJECT_TRANSFORM); *P = transform_point(&tfm, *P); +#endif } -__device_inline void object_normal_transform(KernelGlobals *kg, int object, float3 *N) +__device_inline void object_normal_transform(KernelGlobals *kg, ShaderData *sd, float3 *N) { - Transform tfm = object_fetch_transform(kg, object, OBJECT_NORMAL_TRANSFORM); - *N = normalize(transform_direction(&tfm, *N)); +#ifdef __MOTION__ + *N = normalize(transform_direction_transposed(&sd->ob_itfm, *N)); +#else + Transform tfm = object_fetch_transform(kg, sd->object, TIME_INVALID, OBJECT_INVERSE_TRANSFORM); + *N = normalize(transform_direction_transposed(&tfm, *N)); +#endif } -__device_inline void object_dir_transform(KernelGlobals *kg, int object, float3 *D) +__device_inline void object_dir_transform(KernelGlobals *kg, ShaderData *sd, float3 *D) { - Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM); +#ifdef __MOTION__ + *D = transform_direction(&sd->ob_tfm, *D); +#else + Transform tfm = object_fetch_transform(kg, sd->object, 0.0f, OBJECT_TRANSFORM); *D = transform_direction(&tfm, *D); +#endif } __device_inline float object_surface_area(KernelGlobals *kg, int object) diff --git a/intern/cycles/kernel/kernel_passes.h b/intern/cycles/kernel/kernel_passes.h index fd4ee17cdc1..f3ddda4a392 100644 --- a/intern/cycles/kernel/kernel_passes.h +++ b/intern/cycles/kernel/kernel_passes.h @@ -72,9 +72,14 @@ __device_inline void kernel_write_data_passes(KernelGlobals *kg, __global float kernel_write_pass_float3(buffer + kernel_data.film.pass_normal, sample, normal); } if(flag & PASS_UV) { - float3 uv = make_float3(0.0f, 0.0f, 0.0f); /* todo: request and lookup */ + float3 uv = triangle_uv(kg, sd); kernel_write_pass_float3(buffer + kernel_data.film.pass_uv, sample, uv); } + if(flag & PASS_MOTION) { + float4 speed = triangle_motion_vector(kg, sd); + kernel_write_pass_float4(buffer + kernel_data.film.pass_motion, sample, speed); + kernel_write_pass_float(buffer + kernel_data.film.pass_motion_weight, sample, 1.0f); + } } if(flag & (PASS_DIFFUSE_INDIRECT|PASS_DIFFUSE_COLOR|PASS_DIFFUSE_DIRECT)) diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 8ebac177277..b7c22087e1f 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -18,8 +18,8 @@ #include "kernel_differential.h" #include "kernel_montecarlo.h" -#include "kernel_triangle.h" #include "kernel_object.h" +#include "kernel_triangle.h" #ifdef __QBVH__ #include "kernel_qbvh.h" #else @@ -324,6 +324,9 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, R light_ray.P = ray_offset(sd.P, sd.Ng); light_ray.D = ao_D; light_ray.t = kernel_data.background.ao_distance; +#ifdef __MOTION__ + light_ray.time = sd.time; +#endif if(!shadow_blocked(kg, &state, &light_ray, &ao_shadow)) { float3 ao_bsdf = shader_bsdf_diffuse(kg, &sd)*kernel_data.background.ao_factor; @@ -346,6 +349,10 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, R BsdfEval L_light; bool is_lamp; +#ifdef __MOTION__ + light_ray.time = sd.time; +#endif + #ifdef __MULTI_LIGHT__ /* index -1 means randomly sample from distribution */ int i = (kernel_data.integrator.num_distribution)? -1: 0; @@ -449,7 +456,13 @@ __device void kernel_path_trace(KernelGlobals *kg, float lens_u = path_rng(kg, &rng, sample, PRNG_LENS_U); float lens_v = path_rng(kg, &rng, sample, PRNG_LENS_V); - camera_sample(kg, x, y, filter_u, filter_v, lens_u, lens_v, &ray); +#ifdef __MOTION__ + float time = path_rng(kg, &rng, sample, PRNG_TIME); +#else + float time = 0.0f; +#endif + + camera_sample(kg, x, y, filter_u, filter_v, lens_u, lens_v, time, &ray); /* integrate */ float4 L = kernel_path_integrate(kg, &rng, sample, ray, buffer); diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index 46ef5d2022a..b2f2a7577be 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -53,16 +53,9 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd, float3 Ng = make_float3(Ns.x, Ns.y, Ns.z); int shader = __float_as_int(Ns.w); - /* vectors */ - sd->P = bvh_triangle_refine(kg, isect, ray); - sd->Ng = Ng; - sd->N = Ng; - sd->I = -ray->D; - sd->shader = shader; - /* triangle */ #ifdef __INSTANCING__ - sd->object = isect->object; + sd->object = (isect->object == ~0)? kernel_tex_fetch(__prim_object, isect->prim): isect->object; #endif sd->prim = prim; #ifdef __UV__ @@ -70,6 +63,21 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd, sd->v = isect->v; #endif + /* matrices and time */ +#ifdef __MOTION__ + sd->ob_tfm = object_fetch_transform(kg, sd->object, ray->time, OBJECT_TRANSFORM); + sd->ob_itfm = object_fetch_transform(kg, sd->object, ray->time, OBJECT_INVERSE_TRANSFORM); + + sd->time = ray->time; +#endif + + /* vectors */ + sd->P = bvh_triangle_refine(kg, sd, isect, ray); + sd->Ng = Ng; + sd->N = Ng; + sd->I = -ray->D; + sd->shader = shader; + /* smooth normal */ if(sd->shader & SHADER_SMOOTH_NORMAL) sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v); @@ -82,19 +90,15 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd, #endif #ifdef __INSTANCING__ - if(sd->object != ~0) { + if(isect->object != ~0) { /* instance transform */ - object_normal_transform(kg, sd->object, &sd->N); - object_normal_transform(kg, sd->object, &sd->Ng); + object_normal_transform(kg, sd, &sd->N); + object_normal_transform(kg, sd, &sd->Ng); #ifdef __DPDU__ - object_dir_transform(kg, sd->object, &sd->dPdu); - object_dir_transform(kg, sd->object, &sd->dPdv); + object_dir_transform(kg, sd, &sd->dPdu); + object_dir_transform(kg, sd, &sd->dPdv); #endif } - else { - /* non-instanced object index */ - sd->object = kernel_tex_fetch(__prim_object, isect->prim); - } #endif /* backfacing test */ @@ -122,7 +126,7 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd, __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd, const float3 P, const float3 Ng, const float3 I, - int shader, int object, int prim, float u, float v) + int shader, int object, int prim, float u, float v, float time) { /* vectors */ sd->P = P; @@ -155,13 +159,20 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd, } #endif +#ifdef __MOTION__ + sd->time = time; + + sd->ob_tfm = object_fetch_transform(kg, sd->object, time, OBJECT_TRANSFORM); + sd->ob_itfm = object_fetch_transform(kg, sd->object, time, OBJECT_INVERSE_TRANSFORM); +#endif + /* smooth normal */ if(sd->shader & SHADER_SMOOTH_NORMAL) { sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v); #ifdef __INSTANCING__ if(instanced) - object_normal_transform(kg, sd->object, &sd->N); + object_normal_transform(kg, sd, &sd->N); #endif } @@ -178,8 +189,8 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd, #ifdef __INSTANCING__ if(instanced) { - object_dir_transform(kg, sd->object, &sd->dPdu); - object_dir_transform(kg, sd->object, &sd->dPdv); + object_dir_transform(kg, sd, &sd->dPdu); + object_dir_transform(kg, sd, &sd->dPdv); } #endif } @@ -229,7 +240,7 @@ __device void shader_setup_from_displace(KernelGlobals *kg, ShaderData *sd, /* watch out: no instance transform currently */ - shader_setup_from_sample(kg, sd, P, Ng, I, shader, object, prim, u, v); + shader_setup_from_sample(kg, sd, P, Ng, I, shader, object, prim, u, v, TIME_INVALID); } /* ShaderData setup from ray into background */ @@ -243,6 +254,9 @@ __device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData sd->I = -sd->P; sd->shader = kernel_data.background.shader; sd->flag = kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2); +#ifdef __MOTION__ + sd->time = ray->time; +#endif #ifdef __INSTANCING__ sd->object = ~0; diff --git a/intern/cycles/kernel/kernel_triangle.h b/intern/cycles/kernel/kernel_triangle.h index 7eaf54d14bf..1b3956c1dd4 100644 --- a/intern/cycles/kernel/kernel_triangle.h +++ b/intern/cycles/kernel/kernel_triangle.h @@ -179,5 +179,68 @@ __device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData *s } } +/* motion */ + +__device int triangle_find_attribute(KernelGlobals *kg, ShaderData *sd, uint id) +{ + /* find attribute by unique id */ + uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride; + uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset); + + while(attr_map.x != id) + attr_map = kernel_tex_fetch(__attributes_map, ++attr_offset); + + /* return result */ + return (attr_map.y == ATTR_ELEMENT_NONE)? ATTR_STD_NOT_FOUND: attr_map.z; +} + +__device float4 triangle_motion_vector(KernelGlobals *kg, ShaderData *sd) +{ + float3 motion_pre = sd->P, motion_post = sd->P; + + /* deformation motion */ + int offset_pre = triangle_find_attribute(kg, sd, ATTR_STD_MOTION_PRE); + int offset_post = triangle_find_attribute(kg, sd, ATTR_STD_MOTION_POST); + + if(offset_pre != ATTR_STD_NOT_FOUND) + motion_pre = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, offset_pre, NULL, NULL); + if(offset_post != ATTR_STD_NOT_FOUND) + motion_post = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, offset_post, NULL, NULL); + + /* object motion. note that depending on the mesh having motion vectors, this + transformation was set match the world/object space of motion_pre/post */ + Transform tfm; + + tfm = object_fetch_transform(kg, sd->object, TIME_INVALID, OBJECT_TRANSFORM_MOTION_PRE); + motion_pre = transform_point(&tfm, motion_pre); + + tfm = object_fetch_transform(kg, sd->object, TIME_INVALID, OBJECT_TRANSFORM_MOTION_POST); + motion_post = transform_point(&tfm, motion_post); + + /* camera motion */ + tfm = kernel_data.cam.worldtoraster; + float3 P = transform_perspective(&tfm, sd->P); + + tfm = kernel_data.cam.motion.pre; + motion_pre = transform_perspective(&tfm, motion_pre) - P; + + tfm = kernel_data.cam.motion.post; + motion_post = P - transform_perspective(&tfm, motion_post); + + return make_float4(motion_pre.x, motion_pre.y, motion_post.x, motion_post.y); +} + +__device float3 triangle_uv(KernelGlobals *kg, ShaderData *sd) +{ + int offset_uv = triangle_find_attribute(kg, sd, ATTR_STD_UV); + + if(offset_uv == ATTR_STD_NOT_FOUND) + return make_float3(0.0f, 0.0f, 0.0f); + + float3 uv = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, offset_uv, NULL, NULL); + uv.z = 1.0f; + return uv; +} + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 102a2bb036d..e9103087025 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -20,9 +20,12 @@ #define __KERNEL_TYPES_H__ #include "kernel_math.h" - #include "svm/svm_types.h" +#ifndef __KERNEL_GPU__ +#define __KERNEL_CPU__ +#endif + CCL_NAMESPACE_BEGIN /* constants */ @@ -30,6 +33,7 @@ CCL_NAMESPACE_BEGIN #define LIGHT_SIZE 4 #define FILTER_TABLE_SIZE 256 #define RAMP_TABLE_SIZE 256 +#define TIME_INVALID FLT_MAX /* device capabilities */ #ifdef __KERNEL_CPU__ @@ -75,6 +79,7 @@ CCL_NAMESPACE_BEGIN #define __PASSES__ #define __BACKGROUND_MIS__ #define __AO__ +//#define __MOTION__ #endif //#define __MULTI_LIGHT__ @@ -90,14 +95,21 @@ enum ShaderEvalType { SHADER_EVAL_BACKGROUND }; -/* Path Tracing */ +/* Path Tracing + * note we need to keep the u/v pairs at even values */ enum PathTraceDimension { PRNG_FILTER_U = 0, PRNG_FILTER_V = 1, PRNG_LENS_U = 2, PRNG_LENS_V = 3, +#ifdef __MOTION__ + PRNG_TIME = 4, + PRNG_UNUSED = 5, + PRNG_BASE_NUM = 6, +#else PRNG_BASE_NUM = 4, +#endif PRNG_BSDF_U = 0, PRNG_BSDF_V = 1, @@ -177,7 +189,9 @@ typedef enum PassType { PASS_EMISSION = 65536, PASS_BACKGROUND = 131072, PASS_AO = 262144, - PASS_SHADOW = 524288 + PASS_SHADOW = 524288, + PASS_MOTION = 1048576, + PASS_MOTION_WEIGHT = 2097152 } PassType; #define PASS_ALL (~0) @@ -275,6 +289,7 @@ typedef struct Ray { float3 P; float3 D; float t; + float time; #ifdef __RAY_DIFFERENTIALS__ differential3 dP; @@ -300,6 +315,21 @@ typedef enum AttributeElement { ATTR_ELEMENT_NONE } AttributeElement; +typedef enum AttributeStandard { + ATTR_STD_NONE = 0, + ATTR_STD_VERTEX_NORMAL, + ATTR_STD_FACE_NORMAL, + ATTR_STD_UV, + ATTR_STD_GENERATED, + ATTR_STD_POSITION_UNDEFORMED, + ATTR_STD_POSITION_UNDISPLACED, + ATTR_STD_MOTION_PRE, + ATTR_STD_MOTION_POST, + ATTR_STD_NUM, + + ATTR_STD_NOT_FOUND = ~0 +} AttributeStandard; + /* Closure data */ #define MAX_CLOSURE 8 @@ -365,6 +395,16 @@ typedef struct ShaderData { /* object id if there is one, ~0 otherwise */ int object; + /* motion blur sample time */ + float time; + +#ifdef __MOTION__ + /* object <-> world space transformations, cached to avoid + * re-interpolating them constantly for shading */ + Transform ob_tfm; + Transform ob_itfm; +#endif + #ifdef __RAY_DIFFERENTIALS__ /* differential of P. these are orthogonal to Ng, not N */ differential3 dP; @@ -422,8 +462,8 @@ typedef struct KernelCamera { float focaldistance; /* motion blur */ - float shutteropen; - float shutterclose; + float shuttertime; + float pad; /* clipping */ float nearclip; @@ -437,6 +477,8 @@ typedef struct KernelCamera { Transform worldtoraster; Transform worldtondc; Transform worldtocamera; + + MotionTransform motion; } KernelCamera; typedef struct KernelFilm { @@ -448,27 +490,32 @@ typedef struct KernelFilm { int pass_combined; int pass_depth; int pass_normal; - int pass_pad; + int pass_motion; + int pass_motion_weight; int pass_uv; int pass_object_id; int pass_material_id; - int pass_diffuse_color; + int pass_diffuse_color; int pass_glossy_color; int pass_transmission_color; int pass_diffuse_indirect; - int pass_glossy_indirect; + int pass_glossy_indirect; int pass_transmission_indirect; int pass_diffuse_direct; int pass_glossy_direct; - int pass_transmission_direct; + int pass_transmission_direct; int pass_emission; int pass_background; int pass_ao; + int pass_shadow; + int pass_pad1; + int pass_pad2; + int pass_pad3; } KernelFilm; typedef struct KernelBackground { diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h index 98f8734aed2..5ecda795251 100644 --- a/intern/cycles/kernel/svm/svm_tex_coord.h +++ b/intern/cycles/kernel/svm/svm_tex_coord.h @@ -33,8 +33,8 @@ __device void svm_node_tex_coord(KernelGlobals *kg, ShaderData *sd, float *stack switch(type) { case NODE_TEXCO_OBJECT: { if(sd->object != ~0) { - Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM); - data = transform_point(&tfm, sd->P); + data = sd->P; + object_position_transform(kg, sd, &data); } else data = sd->P; @@ -42,8 +42,8 @@ __device void svm_node_tex_coord(KernelGlobals *kg, ShaderData *sd, float *stack } case NODE_TEXCO_NORMAL: { if(sd->object != ~0) { - Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM); - data = transform_direction(&tfm, sd->N); + data = sd->N; + object_normal_transform(kg, sd, &data); } else data = sd->N; @@ -87,8 +87,8 @@ __device void svm_node_tex_coord_bump_dx(KernelGlobals *kg, ShaderData *sd, floa switch(type) { case NODE_TEXCO_OBJECT: { if(sd->object != ~0) { - Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM); - data = transform_point(&tfm, sd->P + sd->dP.dx); + data = sd->P + sd->dP.dx; + object_position_transform(kg, sd, &data); } else data = sd->P + sd->dP.dx; @@ -96,8 +96,8 @@ __device void svm_node_tex_coord_bump_dx(KernelGlobals *kg, ShaderData *sd, floa } case NODE_TEXCO_NORMAL: { if(sd->object != ~0) { - Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM); - data = transform_direction(&tfm, sd->N); + data = sd->N; + object_normal_transform(kg, sd, &data); } else data = sd->N; @@ -144,8 +144,8 @@ __device void svm_node_tex_coord_bump_dy(KernelGlobals *kg, ShaderData *sd, floa switch(type) { case NODE_TEXCO_OBJECT: { if(sd->object != ~0) { - Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM); - data = transform_point(&tfm, sd->P + sd->dP.dy); + data = sd->P + sd->dP.dy; + object_position_transform(kg, sd, &data); } else data = sd->P + sd->dP.dy; @@ -153,8 +153,8 @@ __device void svm_node_tex_coord_bump_dy(KernelGlobals *kg, ShaderData *sd, floa } case NODE_TEXCO_NORMAL: { if(sd->object != ~0) { - Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM); - data = normalize(transform_direction(&tfm, sd->N)); + data = sd->N; + object_normal_transform(kg, sd, &data); } else data = sd->N; diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt index db92cf4ef54..4d4fbfe6814 100644 --- a/intern/cycles/render/CMakeLists.txt +++ b/intern/cycles/render/CMakeLists.txt @@ -16,7 +16,7 @@ set(SRC buffers.cpp camera.cpp film.cpp - # film_response.cpp # XXX, why isn't this in? + # film_response.cpp (code unused) filter.cpp graph.cpp image.cpp @@ -41,7 +41,7 @@ set(SRC_HEADERS buffers.h camera.h film.h - # film_response.h # XXX, why isn't this in? + # film_response.h (code unused) filter.h graph.h image.h diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp index 9e90bf1b625..c1a089cc872 100644 --- a/intern/cycles/render/attribute.cpp +++ b/intern/cycles/render/attribute.cpp @@ -31,7 +31,7 @@ void Attribute::set(ustring name_, TypeDesc type_, Element element_) name = name_; type = type_; element = element_; - std = STD_NONE; + std = ATTR_STD_NONE; /* string and matrix not supported! */ assert(type == TypeDesc::TypeFloat || type == TypeDesc::TypeColor || @@ -81,20 +81,24 @@ bool Attribute::same_storage(TypeDesc a, TypeDesc b) return false; } -ustring Attribute::standard_name(Attribute::Standard std) +ustring Attribute::standard_name(AttributeStandard std) { - if(std == Attribute::STD_VERTEX_NORMAL) + if(std == ATTR_STD_VERTEX_NORMAL) return ustring("N"); - else if(std == Attribute::STD_FACE_NORMAL) + else if(std == ATTR_STD_FACE_NORMAL) return ustring("Ng"); - else if(std == Attribute::STD_UV) + else if(std == ATTR_STD_UV) return ustring("uv"); - else if(std == Attribute::STD_GENERATED) + else if(std == ATTR_STD_GENERATED) return ustring("generated"); - else if(std == Attribute::STD_POSITION_UNDEFORMED) + else if(std == ATTR_STD_POSITION_UNDEFORMED) return ustring("undeformed"); - else if(std == Attribute::STD_POSITION_UNDISPLACED) + else if(std == ATTR_STD_POSITION_UNDISPLACED) return ustring("undisplaced"); + else if(std == ATTR_STD_MOTION_PRE) + return ustring("motion_pre"); + else if(std == ATTR_STD_MOTION_POST) + return ustring("motion_post"); return ustring(); } @@ -164,24 +168,28 @@ void AttributeSet::remove(ustring name) } } -Attribute *AttributeSet::add(Attribute::Standard std, ustring name) +Attribute *AttributeSet::add(AttributeStandard std, ustring name) { Attribute *attr = NULL; if(name == ustring()) name = Attribute::standard_name(std); - if(std == Attribute::STD_VERTEX_NORMAL) + if(std == ATTR_STD_VERTEX_NORMAL) attr = add(name, TypeDesc::TypeNormal, Attribute::VERTEX); - else if(std == Attribute::STD_FACE_NORMAL) + else if(std == ATTR_STD_FACE_NORMAL) attr = add(name, TypeDesc::TypeNormal, Attribute::FACE); - else if(std == Attribute::STD_UV) + else if(std == ATTR_STD_UV) attr = add(name, TypeDesc::TypePoint, Attribute::CORNER); - else if(std == Attribute::STD_GENERATED) + else if(std == ATTR_STD_GENERATED) attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX); - else if(std == Attribute::STD_POSITION_UNDEFORMED) + else if(std == ATTR_STD_POSITION_UNDEFORMED) attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX); - else if(std == Attribute::STD_POSITION_UNDISPLACED) + else if(std == ATTR_STD_POSITION_UNDISPLACED) + attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX); + else if(std == ATTR_STD_MOTION_PRE) + attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX); + else if(std == ATTR_STD_MOTION_POST) attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX); else assert(0); @@ -191,7 +199,7 @@ Attribute *AttributeSet::add(Attribute::Standard std, ustring name) return attr; } -Attribute *AttributeSet::find(Attribute::Standard std) +Attribute *AttributeSet::find(AttributeStandard std) { foreach(Attribute& attr, attributes) if(attr.std == std) @@ -200,7 +208,7 @@ Attribute *AttributeSet::find(Attribute::Standard std) return NULL; } -void AttributeSet::remove(Attribute::Standard std) +void AttributeSet::remove(AttributeStandard std) { Attribute *attr = find(std); @@ -218,7 +226,7 @@ void AttributeSet::remove(Attribute::Standard std) Attribute *AttributeSet::find(AttributeRequest& req) { - if(req.std == Attribute::STD_NONE) + if(req.std == ATTR_STD_NONE) return find(req.name); else return find(req.std); @@ -240,14 +248,14 @@ void AttributeSet::clear() AttributeRequest::AttributeRequest(ustring name_) { name = name_; - std = Attribute::STD_NONE; + std = ATTR_STD_NONE; type = TypeDesc::TypeFloat; element = ATTR_ELEMENT_NONE; offset = 0; } -AttributeRequest::AttributeRequest(Attribute::Standard std_) +AttributeRequest::AttributeRequest(AttributeStandard std_) { name = ustring(); std = std_; @@ -296,7 +304,7 @@ void AttributeRequestSet::add(ustring name) requests.push_back(AttributeRequest(name)); } -void AttributeRequestSet::add(Attribute::Standard std) +void AttributeRequestSet::add(AttributeStandard std) { foreach(AttributeRequest& req, requests) if(req.std == std) @@ -308,7 +316,7 @@ void AttributeRequestSet::add(Attribute::Standard std) void AttributeRequestSet::add(AttributeRequestSet& reqs) { foreach(AttributeRequest& req, reqs.requests) { - if(req.std == Attribute::STD_NONE) + if(req.std == ATTR_STD_NONE) add(req.name); else add(req.std); @@ -324,7 +332,7 @@ bool AttributeRequestSet::find(ustring name) return false; } -bool AttributeRequestSet::find(Attribute::Standard std) +bool AttributeRequestSet::find(AttributeStandard std) { foreach(AttributeRequest& req, requests) if(req.std == std) diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h index 7af4657daa3..707d558fc79 100644 --- a/intern/cycles/render/attribute.h +++ b/intern/cycles/render/attribute.h @@ -47,19 +47,8 @@ public: CORNER }; - enum Standard { - STD_NONE = 0, - STD_VERTEX_NORMAL, - STD_FACE_NORMAL, - STD_UV, - STD_GENERATED, - STD_POSITION_UNDEFORMED, - STD_POSITION_UNDISPLACED, - STD_NUM - }; - ustring name; - Standard std; + AttributeStandard std; TypeDesc type; vector<char> buffer; @@ -82,7 +71,7 @@ public: const float *data_float() const { return (float*)data(); } static bool same_storage(TypeDesc a, TypeDesc b); - static ustring standard_name(Attribute::Standard std); + static ustring standard_name(AttributeStandard std); }; /* Attribute Set @@ -101,9 +90,9 @@ public: Attribute *find(ustring name); void remove(ustring name); - Attribute *add(Attribute::Standard std, ustring name = ustring()); - Attribute *find(Attribute::Standard std); - void remove(Attribute::Standard std); + Attribute *add(AttributeStandard std, ustring name = ustring()); + Attribute *find(AttributeStandard std); + void remove(AttributeStandard std); Attribute *find(AttributeRequest& req); @@ -120,7 +109,7 @@ public: class AttributeRequest { public: ustring name; - Attribute::Standard std; + AttributeStandard std; /* temporary variables used by MeshManager */ TypeDesc type; @@ -128,7 +117,7 @@ public: int offset; AttributeRequest(ustring name_); - AttributeRequest(Attribute::Standard std); + AttributeRequest(AttributeStandard std); }; /* AttributeRequestSet @@ -143,11 +132,11 @@ public: ~AttributeRequestSet(); void add(ustring name); - void add(Attribute::Standard std); + void add(AttributeStandard std); void add(AttributeRequestSet& reqs); bool find(ustring name); - bool find(Attribute::Standard std); + bool find(AttributeStandard std); size_t size(); void clear(); diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp index bda20a8ab9d..a80851b945a 100644 --- a/intern/cycles/render/buffers.cpp +++ b/intern/cycles/render/buffers.cpp @@ -221,6 +221,28 @@ bool RenderBuffers::get_pass(PassType type, float exposure, int sample, int comp pixels[3] = 1.0f; } } + else if(type == PASS_MOTION) { + /* need to normalize by number of samples accumulated for motion */ + pass_offset = 0; + foreach(Pass& color_pass, params.passes) { + if(color_pass.type == PASS_MOTION_WEIGHT) + break; + pass_offset += color_pass.components; + } + + float *in_weight = (float*)buffer.data_pointer + pass_offset; + + for(int i = 0; i < size; i++, in += pass_stride, in_weight += pass_stride, pixels += 4) { + float4 f = make_float4(in[0], in[1], in[2], in[3]); + float w = in_weight[0]; + float invw = (w > 0.0f)? 1.0f/w: 0.0f; + + pixels[0] = f.x*invw; + pixels[1] = f.y*invw; + pixels[2] = f.z*invw; + pixels[3] = f.w*invw; + } + } else { for(int i = 0; i < size; i++, in += pass_stride, pixels += 4) { float4 f = make_float4(in[0], in[1], in[2], in[3]); diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp index f9290dfc835..e9ca7c3a366 100644 --- a/intern/cycles/render/camera.cpp +++ b/intern/cycles/render/camera.cpp @@ -25,8 +25,7 @@ CCL_NAMESPACE_BEGIN Camera::Camera() { - shutteropen = 0.0f; - shutterclose = 1.0f; + shuttertime = 1.0f; aperturesize = 0.0f; focaldistance = 10.0f; @@ -35,6 +34,10 @@ Camera::Camera() matrix = transform_identity(); + motion.pre = transform_identity(); + motion.post = transform_identity(); + use_motion = false; + type = CAMERA_PERSPECTIVE; fov = M_PI_F/4.0f; @@ -124,7 +127,7 @@ void Camera::update() need_device_update = true; } -void Camera::device_update(Device *device, DeviceScene *dscene) +void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene) { update(); @@ -140,10 +143,28 @@ void Camera::device_update(Device *device, DeviceScene *dscene) kcam->rastertocamera = rastertocamera; kcam->cameratoworld = cameratoworld; kcam->worldtoscreen = transform_inverse(screentoworld); - kcam->worldtoraster = transform_inverse(rastertoworld); + kcam->worldtoraster = worldtoraster; kcam->worldtondc = transform_inverse(ndctoworld); kcam->worldtocamera = transform_inverse(cameratoworld); + /* camera motion */ + Scene::MotionType need_motion = scene->need_motion(); + + if(need_motion == Scene::MOTION_PASS) { + if(use_motion) { + kcam->motion.pre = transform_inverse(motion.pre * rastertocamera); + kcam->motion.post = transform_inverse(motion.post * rastertocamera); + } + else { + kcam->motion.pre = worldtoraster; + kcam->motion.post = worldtoraster; + } + } + else if(need_motion == Scene::MOTION_BLUR) { + /* todo: exact camera position will not be hit this way */ + transform_motion_decompose(&kcam->motion, &motion); + } + /* depth of field */ kcam->aperturesize = aperturesize; kcam->focaldistance = focaldistance; @@ -151,8 +172,7 @@ void Camera::device_update(Device *device, DeviceScene *dscene) kcam->bladesrotation = bladesrotation; /* motion blur */ - kcam->shutteropen = shutteropen; - kcam->shutterclose = shutterclose; + kcam->shuttertime= (need_motion == Scene::MOTION_BLUR)? shuttertime: 0.0f; /* type */ kcam->type = type; @@ -175,8 +195,7 @@ void Camera::device_free(Device *device, DeviceScene *dscene) bool Camera::modified(const Camera& cam) { - return !((shutteropen == cam.shutteropen) && - (shutterclose == cam.shutterclose) && + return !((shuttertime== cam.shuttertime) && (aperturesize == cam.aperturesize) && (blades == cam.blades) && (bladesrotation == cam.bladesrotation) && @@ -192,7 +211,9 @@ bool Camera::modified(const Camera& cam) (right == cam.right) && (bottom == cam.bottom) && (top == cam.top) && - (matrix == cam.matrix)); + (matrix == cam.matrix) && + (motion == cam.motion) && + (use_motion == cam.use_motion)); } void Camera::tag_update() diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h index cfcc5406ee3..935489711c8 100644 --- a/intern/cycles/render/camera.h +++ b/intern/cycles/render/camera.h @@ -28,6 +28,7 @@ CCL_NAMESPACE_BEGIN class Device; class DeviceScene; +class Scene; /* Camera * @@ -37,8 +38,7 @@ class DeviceScene; class Camera { public: /* motion blur */ - float shutteropen; - float shutterclose; + float shuttertime; /* depth of field */ float focaldistance; @@ -61,6 +61,10 @@ public: /* transformation */ Transform matrix; + /* motion */ + MotionTransform motion; + bool use_motion; + /* computed camera parameters */ Transform screentoworld; Transform rastertoworld; @@ -82,7 +86,7 @@ public: void update(); - void device_update(Device *device, DeviceScene *dscene); + void device_update(Device *device, DeviceScene *dscene, Scene *scene); void device_free(Device *device, DeviceScene *dscene); bool modified(const Camera& cam); diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp index cc17f86fcb6..55c89b7b1b2 100644 --- a/intern/cycles/render/film.cpp +++ b/intern/cycles/render/film.cpp @@ -67,6 +67,13 @@ void Pass::add(PassType type, vector<Pass>& passes) case PASS_UV: pass.components = 4; break; + case PASS_MOTION: + pass.components = 4; + pass.divide_type = PASS_MOTION_WEIGHT; + break; + case PASS_MOTION_WEIGHT: + pass.components = 1; + break; case PASS_OBJECT_ID: pass.components = 1; pass.filter = false; @@ -154,6 +161,15 @@ bool Pass::equals(const vector<Pass>& A, const vector<Pass>& B) return true; } +bool Pass::contains(const vector<Pass>& passes, PassType type) +{ + foreach(const Pass& pass, passes) + if(pass.type == type) + return true; + + return false; +} + /* Film */ Film::Film() @@ -196,6 +212,12 @@ void Film::device_update(Device *device, DeviceScene *dscene) case PASS_UV: kfilm->pass_uv = kfilm->pass_stride; break; + case PASS_MOTION: + kfilm->pass_motion = kfilm->pass_stride; + break; + case PASS_MOTION_WEIGHT: + kfilm->pass_motion_weight = kfilm->pass_stride; + break; case PASS_OBJECT_ID: kfilm->pass_object_id = kfilm->pass_stride; break; diff --git a/intern/cycles/render/film.h b/intern/cycles/render/film.h index 8a3dbbf1b08..c7d2ee24388 100644 --- a/intern/cycles/render/film.h +++ b/intern/cycles/render/film.h @@ -40,6 +40,7 @@ public: static void add(PassType type, vector<Pass>& passes); static bool equals(const vector<Pass>& A, const vector<Pass>& B); + static bool contains(const vector<Pass>& passes, PassType); }; class Film { diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index cc29047f048..d9486de47c9 100644 --- a/intern/cycles/render/graph.cpp +++ b/intern/cycles/render/graph.cpp @@ -120,9 +120,9 @@ void ShaderNode::attributes(AttributeRequestSet *attributes) foreach(ShaderInput *input, inputs) { if(!input->link) { if(input->default_value == ShaderInput::TEXTURE_GENERATED) - attributes->add(Attribute::STD_GENERATED); + attributes->add(ATTR_STD_GENERATED); else if(input->default_value == ShaderInput::TEXTURE_UV) - attributes->add(Attribute::STD_UV); + attributes->add(ATTR_STD_UV); } } } diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp index c1f066df10c..b26ebfd91e1 100644 --- a/intern/cycles/render/integrator.cpp +++ b/intern/cycles/render/integrator.cpp @@ -45,6 +45,7 @@ Integrator::Integrator() seed = 0; layer_flag = ~0; sample_clamp = 0.0f; + motion_blur = false; need_update = true; } @@ -125,7 +126,8 @@ bool Integrator::modified(const Integrator& integrator) filter_glossy == integrator.filter_glossy && layer_flag == integrator.layer_flag && seed == integrator.seed && - sample_clamp == integrator.sample_clamp); + sample_clamp == integrator.sample_clamp && + motion_blur == integrator.motion_blur); } void Integrator::tag_update(Scene *scene) diff --git a/intern/cycles/render/integrator.h b/intern/cycles/render/integrator.h index 0817fcaa457..afda41a857d 100644 --- a/intern/cycles/render/integrator.h +++ b/intern/cycles/render/integrator.h @@ -47,6 +47,7 @@ public: int layer_flag; float sample_clamp; + bool motion_blur; bool need_update; diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 0ce16e65621..5d96611ff26 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -113,11 +113,11 @@ void Mesh::compute_bounds() void Mesh::add_face_normals() { /* don't compute if already there */ - if(attributes.find(Attribute::STD_FACE_NORMAL)) + if(attributes.find(ATTR_STD_FACE_NORMAL)) return; /* get attributes */ - Attribute *attr_fN = attributes.add(Attribute::STD_FACE_NORMAL); + Attribute *attr_fN = attributes.add(ATTR_STD_FACE_NORMAL); float3 *fN = attr_fN->data_float3(); /* compute face normals */ @@ -145,12 +145,12 @@ void Mesh::add_face_normals() void Mesh::add_vertex_normals() { /* don't compute if already there */ - if(attributes.find(Attribute::STD_VERTEX_NORMAL)) + if(attributes.find(ATTR_STD_VERTEX_NORMAL)) return; /* get attributes */ - Attribute *attr_fN = attributes.find(Attribute::STD_FACE_NORMAL); - Attribute *attr_vN = attributes.add(Attribute::STD_VERTEX_NORMAL); + Attribute *attr_fN = attributes.find(ATTR_STD_FACE_NORMAL); + Attribute *attr_vN = attributes.add(ATTR_STD_VERTEX_NORMAL); float3 *fN = attr_fN->data_float3(); float3 *vN = attr_vN->data_float3(); @@ -179,8 +179,8 @@ void Mesh::add_vertex_normals() void Mesh::pack_normals(Scene *scene, float4 *normal, float4 *vnormal) { - Attribute *attr_fN = attributes.find(Attribute::STD_FACE_NORMAL); - Attribute *attr_vN = attributes.find(Attribute::STD_VERTEX_NORMAL); + Attribute *attr_fN = attributes.find(ATTR_STD_FACE_NORMAL); + Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL); float3 *fN = attr_fN->data_float3(); float3 *vN = attr_vN->data_float3(); @@ -348,7 +348,7 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att else osl_attr.type = TypeDesc::TypeColor; - if(req.std != Attribute::STD_NONE) { + if(req.std != ATTR_STD_NONE) { /* if standard attribute, add lookup by std:: name convention */ ustring stdname = ustring(string("std::") + Attribute::standard_name(req.std).c_str()); og->attribute_map[i][stdname] = osl_attr; @@ -371,7 +371,7 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce int attr_map_stride = 0; for(size_t i = 0; i < scene->meshes.size(); i++) - attr_map_stride = max(attr_map_stride, mesh_attributes[i].size()); + attr_map_stride = max(attr_map_stride, mesh_attributes[i].size()+1); if(attr_map_stride == 0) return; @@ -393,13 +393,12 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce AttributeRequestSet& attributes = mesh_attributes[j]; /* set object attributes */ - j = 0; + int index = i*attr_map_stride; foreach(AttributeRequest& req, attributes.requests) { - int index = i*attr_map_stride + j; uint id; - if(req.std == Attribute::STD_NONE) + if(req.std == ATTR_STD_NONE) id = scene->shader_manager->get_attribute_id(req.name); else id = scene->shader_manager->get_attribute_id(req.std); @@ -413,8 +412,14 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce else attr_map[index].w = NODE_ATTR_FLOAT3; - j++; + index++; } + + /* terminator */ + attr_map[index].x = ATTR_STD_NONE; + attr_map[index].y = 0; + attr_map[index].z = 0; + attr_map[index].w = 0; } /* copy to device */ @@ -434,6 +439,8 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, for(size_t i = 0; i < scene->meshes.size(); i++) { Mesh *mesh = scene->meshes[i]; + scene->need_global_attributes(mesh_attributes[i]); + foreach(uint sindex, mesh->used_shaders) { Shader *shader = scene->shaders[sindex]; mesh_attributes[i].add(shader->attributes); @@ -456,8 +463,8 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, Attribute *mattr = mesh->attributes.find(req); /* todo: get rid of this exception */ - if(!mattr && req.std == Attribute::STD_GENERATED) { - mattr = mesh->attributes.add(Attribute::STD_GENERATED); + if(!mattr && req.std == ATTR_STD_GENERATED) { + mattr = mesh->attributes.add(ATTR_STD_GENERATED); if(mesh->verts.size()) memcpy(mattr->data_float3(), &mesh->verts[0], sizeof(float3)*mesh->verts.size()); } @@ -489,19 +496,19 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, float *data = mattr->data_float(); req.offset = attr_float.size(); + attr_float.resize(attr_float.size() + size); + for(size_t k = 0; k < size; k++) - attr_float.push_back(data[k]); + attr_float[req.offset+k] = data[k]; } else { float3 *data = mattr->data_float3(); req.offset = attr_float3.size(); - for(size_t k = 0; k < size; k++) { - float3 f3 = data[k]; - float4 f4 = make_float4(f3.x, f3.y, f3.z, 0.0f); + attr_float3.resize(attr_float3.size() + size); - attr_float3.push_back(f4); - } + for(size_t k = 0; k < size; k++) + attr_float3[req.offset+k] = float3_to_float4(data[k]); } /* mesh vertex/triangle index is global, not per object, so we sneak @@ -712,8 +719,10 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen foreach(Shader *shader, scene->shaders) shader->need_update_attributes = false; + bool motion_blur = scene->need_motion() == Scene::MOTION_BLUR; + foreach(Object *object, scene->objects) - object->compute_bounds(); + object->compute_bounds(motion_blur); if(progress.get_cancel()) return; @@ -759,5 +768,32 @@ void MeshManager::tag_update(Scene *scene) scene->object_manager->need_update = true; } +bool Mesh::need_attribute(Scene *scene, AttributeStandard std) +{ + if(std == ATTR_STD_NONE) + return false; + + if(scene->need_global_attribute(std)) + return true; + + foreach(uint shader, used_shaders) + if(scene->shaders[shader]->attributes.find(std)) + return true; + + return false; +} + +bool Mesh::need_attribute(Scene *scene, ustring name) +{ + if(name == ustring()) + return false; + + foreach(uint shader, used_shaders) + if(scene->shaders[shader]->attributes.find(name)) + return true; + + return false; +} + CCL_NAMESPACE_END diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h index 585203484c7..047a2d2624d 100644 --- a/intern/cycles/render/mesh.h +++ b/intern/cycles/render/mesh.h @@ -98,6 +98,9 @@ public: void pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset); void compute_bvh(SceneParams *params, Progress& progress); + bool need_attribute(Scene *scene, AttributeStandard std); + bool need_attribute(Scene *scene, ustring name); + void tag_update(Scene *scene, bool rebuild); }; diff --git a/intern/cycles/render/mesh_displace.cpp b/intern/cycles/render/mesh_displace.cpp index a6f8e3f6be8..dea694a811e 100644 --- a/intern/cycles/render/mesh_displace.cpp +++ b/intern/cycles/render/mesh_displace.cpp @@ -140,11 +140,11 @@ bool MeshManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress& p * normals, as bump mapping in the shader will already alter the * vertex normal, so we start from the non-displaced vertex normals * to avoid applying the perturbation twice. */ - mesh->attributes.remove(Attribute::STD_FACE_NORMAL); + mesh->attributes.remove(ATTR_STD_FACE_NORMAL); mesh->add_face_normals(); if(mesh->displacement_method == Mesh::DISPLACE_TRUE) { - mesh->attributes.remove(Attribute::STD_VERTEX_NORMAL); + mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); mesh->add_vertex_normals(); } diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index d71438ebae1..7039f5b6412 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -1514,9 +1514,9 @@ TextureCoordinateNode::TextureCoordinateNode() void TextureCoordinateNode::attributes(AttributeRequestSet *attributes) { if(!output("Generated")->links.empty()) - attributes->add(Attribute::STD_GENERATED); + attributes->add(ATTR_STD_GENERATED); if(!output("UV")->links.empty()) - attributes->add(Attribute::STD_UV); + attributes->add(ATTR_STD_UV); ShaderNode::attributes(attributes); } @@ -1546,7 +1546,7 @@ void TextureCoordinateNode::compile(SVMCompiler& compiler) compiler.add_node(geom_node, NODE_GEOM_P, out->stack_offset); } else { - int attr = compiler.attribute(Attribute::STD_GENERATED); + int attr = compiler.attribute(ATTR_STD_GENERATED); compiler.stack_assign(out); compiler.add_node(attr_node, attr, out->stack_offset, NODE_ATTR_FLOAT3); } @@ -1560,7 +1560,7 @@ void TextureCoordinateNode::compile(SVMCompiler& compiler) out = output("UV"); if(!out->links.empty()) { - int attr = compiler.attribute(Attribute::STD_UV); + int attr = compiler.attribute(ATTR_STD_UV); compiler.stack_assign(out); compiler.add_node(attr_node, attr, out->stack_offset, NODE_ATTR_FLOAT3); } diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index 28645d856a8..ccc654965f1 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -38,15 +38,37 @@ Object::Object() visibility = ~0; pass_id = 0; bounds = BoundBox::empty; + motion.pre = transform_identity(); + motion.post = transform_identity(); + use_motion = false; } Object::~Object() { } -void Object::compute_bounds() +void Object::compute_bounds(bool motion_blur) { - bounds = mesh->bounds.transformed(&tfm); + BoundBox mbounds = mesh->bounds; + + if(motion_blur && use_motion) { + MotionTransform decomp; + transform_motion_decompose(&decomp, &motion); + + bounds = BoundBox::empty; + + /* todo: this is really terrible. according to pbrt there is a better + * way to find this iteratively, but did not find implementation yet + * or try to implement myself */ + for(float t = 0.0f; t < 1.0f; t += 1.0f/128.0f) { + Transform ttfm; + + transform_motion_interpolate(&ttfm, &decomp, t); + bounds.grow(mbounds.transformed(&ttfm)); + } + } + else + bounds = mbounds.transformed(&tfm); } void Object::apply_transform() @@ -57,8 +79,8 @@ void Object::apply_transform() for(size_t i = 0; i < mesh->verts.size(); i++) mesh->verts[i] = transform_point(&tfm, mesh->verts[i]); - Attribute *attr_fN = mesh->attributes.find(Attribute::STD_FACE_NORMAL); - Attribute *attr_vN = mesh->attributes.find(Attribute::STD_VERTEX_NORMAL); + Attribute *attr_fN = mesh->attributes.find(ATTR_STD_FACE_NORMAL); + Attribute *attr_vN = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL); Transform ntfm = transform_transpose(transform_inverse(tfm)); @@ -83,7 +105,7 @@ void Object::apply_transform() if(bounds.valid()) { mesh->compute_bounds(); - compute_bounds(); + compute_bounds(false); } tfm = transform_identity(); @@ -123,6 +145,7 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene float4 *objects = dscene->objects.resize(OBJECT_SIZE*scene->objects.size()); int i = 0; map<Mesh*, float> surface_area_map; + Scene::MotionType need_motion = scene->need_motion(); foreach(Object *ob, scene->objects) { Mesh *mesh = ob->mesh; @@ -130,7 +153,6 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene /* compute transformations */ Transform tfm = ob->tfm; Transform itfm = transform_inverse(tfm); - Transform ntfm = transform_transpose(itfm); /* compute surface area. for uniform scale we can do avoid the many transform calls and share computation for instances */ @@ -171,10 +193,38 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene /* pack in texture */ int offset = i*OBJECT_SIZE; - memcpy(&objects[offset], &tfm, sizeof(float4)*4); - memcpy(&objects[offset+4], &itfm, sizeof(float4)*4); - memcpy(&objects[offset+8], &ntfm, sizeof(float4)*4); - objects[offset+12] = make_float4(surface_area, pass_id, 0.0f, 0.0f); + memcpy(&objects[offset], &tfm, sizeof(float4)*3); + memcpy(&objects[offset+3], &itfm, sizeof(float4)*3); + objects[offset+6] = make_float4(surface_area, pass_id, 0.0f, 0.0f); + + if(need_motion == Scene::MOTION_PASS) { + /* motion transformations, is world/object space depending if mesh + comes with deformed position in object space, or if we transform + the shading point in world space */ + Transform mtfm_pre = ob->motion.pre; + Transform mtfm_post = ob->motion.post; + + if(!mesh->attributes.find(ATTR_STD_MOTION_PRE)) + mtfm_pre = mtfm_pre * itfm; + if(!mesh->attributes.find(ATTR_STD_MOTION_POST)) + mtfm_post = mtfm_post * itfm; + + memcpy(&objects[offset+8], &mtfm_pre, sizeof(float4)*4); + memcpy(&objects[offset+12], &mtfm_post, sizeof(float4)*4); + } + else if(need_motion == Scene::MOTION_BLUR) { + if(ob->use_motion) { + /* decompose transformations for interpolation */ + MotionTransform decomp; + + transform_motion_decompose(&decomp, &ob->motion); + memcpy(&objects[offset+8], &decomp, sizeof(float4)*8); + } + else { + float4 no_motion = make_float4(FLT_MAX); + memcpy(&objects[offset+8], &no_motion, sizeof(float4)); + } + } i++; @@ -225,6 +275,7 @@ void ObjectManager::apply_static_transforms(Scene *scene, Progress& progress) /* counter mesh users */ map<Mesh*, int> mesh_users; + bool motion_blur = scene->need_motion() == Scene::MOTION_BLUR; foreach(Object *object, scene->objects) { map<Mesh*, int>::iterator it = mesh_users.find(object->mesh); @@ -240,12 +291,14 @@ void ObjectManager::apply_static_transforms(Scene *scene, Progress& progress) /* apply transforms for objects with single user meshes */ foreach(Object *object, scene->objects) { if(mesh_users[object->mesh] == 1) { - if(!object->mesh->transform_applied) { - object->apply_transform(); - object->mesh->transform_applied = true; - } + if(!(motion_blur && object->use_motion)) { + if(!object->mesh->transform_applied) { + object->apply_transform(); + object->mesh->transform_applied = true; - if(progress.get_cancel()) return; + if(progress.get_cancel()) return; + } + } } } } diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h index 14da2cfb35d..e84c4b26767 100644 --- a/intern/cycles/render/object.h +++ b/intern/cycles/render/object.h @@ -44,13 +44,15 @@ public: int pass_id; vector<ParamValue> attributes; uint visibility; + MotionTransform motion; + bool use_motion; Object(); ~Object(); void tag_update(Scene *scene); - void compute_bounds(); + void compute_bounds(bool motion_blur); void apply_transform(); }; diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 079f2744e73..b6453339d41 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -128,7 +128,7 @@ void Scene::device_update(Device *device_, Progress& progress) if(progress.get_cancel()) return; progress.set_status("Updating Camera"); - camera->device_update(device, &dscene); + camera->device_update(device, &dscene, this); if(progress.get_cancel()) return; @@ -166,6 +166,33 @@ void Scene::device_update(Device *device_, Progress& progress) device->const_copy_to("__data", &dscene.data, sizeof(dscene.data)); } +Scene::MotionType Scene::need_motion() +{ + if(integrator->motion_blur) + return MOTION_BLUR; + else if(Pass::contains(film->passes, PASS_MOTION)) + return MOTION_PASS; + else + return MOTION_NONE; +} + +bool Scene::need_global_attribute(AttributeStandard std) +{ + if(std == ATTR_STD_UV) + return Pass::contains(film->passes, PASS_UV); + if(std == ATTR_STD_MOTION_PRE || ATTR_STD_MOTION_POST) + return need_motion() == MOTION_PASS; + + return false; +} + +void Scene::need_global_attributes(AttributeRequestSet& attributes) +{ + for(int std = ATTR_STD_NONE; std < ATTR_STD_NUM; std++) + if(need_global_attribute((AttributeStandard)std)) + attributes.add((AttributeStandard)std); +} + bool Scene::need_update() { return (need_reset() || film->need_update); diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index af4301b1cd9..7d4acf369fd 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -33,6 +33,7 @@ CCL_NAMESPACE_BEGIN +class AttributeRequestSet; class Background; class Camera; class Device; @@ -175,6 +176,12 @@ public: void device_update(Device *device, Progress& progress); + bool need_global_attribute(AttributeStandard std); + void need_global_attributes(AttributeRequestSet& attributes); + + enum MotionType { MOTION_NONE = 0, MOTION_PASS, MOTION_BLUR }; + MotionType need_motion(); + bool need_update(); bool need_reset(); }; diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp index c1f7b3518d2..f50709146ef 100644 --- a/intern/cycles/render/shader.cpp +++ b/intern/cycles/render/shader.cpp @@ -133,12 +133,12 @@ uint ShaderManager::get_attribute_id(ustring name) if(it != unique_attribute_id.end()) return it->second; - uint id = (uint)Attribute::STD_NUM + unique_attribute_id.size(); + uint id = (uint)ATTR_STD_NUM + unique_attribute_id.size(); unique_attribute_id[name] = id; return id; } -uint ShaderManager::get_attribute_id(Attribute::Standard std) +uint ShaderManager::get_attribute_id(AttributeStandard std) { return (uint)std; } diff --git a/intern/cycles/render/shader.h b/intern/cycles/render/shader.h index 35f3cfe27f5..48d517ce21a 100644 --- a/intern/cycles/render/shader.h +++ b/intern/cycles/render/shader.h @@ -103,7 +103,7 @@ public: /* get globally unique id for a type of attribute */ uint get_attribute_id(ustring name); - uint get_attribute_id(Attribute::Standard std); + uint get_attribute_id(AttributeStandard std); /* get shader id for mesh faces */ int get_shader_id(uint shader, Mesh *mesh = NULL, bool smooth = false); diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp index a52e30c6030..1ff3ac20d50 100644 --- a/intern/cycles/render/svm.cpp +++ b/intern/cycles/render/svm.cpp @@ -337,7 +337,7 @@ uint SVMCompiler::attribute(ustring name) return shader_manager->get_attribute_id(name); } -uint SVMCompiler::attribute(Attribute::Standard std) +uint SVMCompiler::attribute(AttributeStandard std) { return shader_manager->get_attribute_id(std); } diff --git a/intern/cycles/render/svm.h b/intern/cycles/render/svm.h index 56c930f6217..0db68f400fc 100644 --- a/intern/cycles/render/svm.h +++ b/intern/cycles/render/svm.h @@ -69,7 +69,7 @@ public: void add_node(const float4& f); void add_array(float4 *f, int num); uint attribute(ustring name); - uint attribute(Attribute::Standard std); + uint attribute(AttributeStandard std); uint encode_uchar4(uint x, uint y = 0, uint z = 0, uint w = 0); uint closure_mix_weight_offset() { return mix_weight_offset; } diff --git a/intern/cycles/subd/subd_dice.cpp b/intern/cycles/subd/subd_dice.cpp index 6b29d1ca51a..6e24bb410b5 100644 --- a/intern/cycles/subd/subd_dice.cpp +++ b/intern/cycles/subd/subd_dice.cpp @@ -39,7 +39,7 @@ EdgeDice::EdgeDice(Mesh *mesh_, int shader_, bool smooth_, float dicing_rate_) smooth = smooth_; camera = NULL; - mesh->attributes.add(Attribute::STD_VERTEX_NORMAL); + mesh->attributes.add(ATTR_STD_VERTEX_NORMAL); } void EdgeDice::reserve(int num_verts, int num_tris) @@ -49,7 +49,7 @@ void EdgeDice::reserve(int num_verts, int num_tris) mesh->reserve(vert_offset + num_verts, tri_offset + num_tris); - Attribute *attr_vN = mesh->attributes.add(Attribute::STD_VERTEX_NORMAL); + Attribute *attr_vN = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL); mesh_P = &mesh->verts[0]; mesh_N = attr_vN->data_float3(); diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index 53c1302b4a1..f09803d8b09 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -55,6 +55,10 @@ CCL_NAMESPACE_BEGIN #ifndef M_2_PI_F #define M_2_PI_F ((float)0.636619772367581343075535053490057448) #endif +#ifndef M_SQRT2_F +#define M_SQRT2_F ((float)1.41421356237309504880) +#endif + /* Scalar */ @@ -719,6 +723,45 @@ __device_inline float4 cross(const float4& a, const float4& b) #endif } +__device_inline bool is_zero(const float4& a) +{ +#ifdef __KERNEL_SSE__ + return a == make_float4(0.0f); +#else + return (a.x == 0.0f && a.y == 0.0f && a.z == 0.0f && a.w == 0.0f); +#endif +} + +__device_inline float reduce_add(const float4& a) +{ +#ifdef __KERNEL_SSE__ + float4 h = shuffle<1,0,3,2>(a) + a; + return _mm_cvtss_f32(shuffle<2,3,0,1>(h) + h); /* todo: efficiency? */ +#else + return ((a.x + a.y) + (a.z + a.w)); +#endif +} + +__device_inline float average(const float4& a) +{ + return reduce_add(a) * 0.25f; +} + +__device_inline float dot(const float4& a, const float4& b) +{ + return reduce_add(a * b); +} + +__device_inline float len(const float4 a) +{ + return sqrtf(dot(a, a)); +} + +__device_inline float4 normalize(const float4 a) +{ + return a/len(a); +} + __device_inline float4 min(float4 a, float4 b) { #ifdef __KERNEL_SSE__ @@ -790,39 +833,6 @@ __device_inline void print_float4(const char *label, const float4& a) #endif -#ifndef __KERNEL_OPENCL__ - -__device_inline bool is_zero(const float4& a) -{ -#ifdef __KERNEL_SSE__ - return a == make_float4(0.0f); -#else - return (a.x == 0.0f && a.y == 0.0f && a.z == 0.0f && a.w == 0.0f); -#endif -} - -__device_inline float reduce_add(const float4& a) -{ -#ifdef __KERNEL_SSE__ - float4 h = shuffle<1,0,3,2>(a) + a; - return _mm_cvtss_f32(shuffle<2,3,0,1>(h) + h); /* todo: efficiency? */ -#else - return ((a.x + a.y) + (a.z + a.w)); -#endif -} - -__device_inline float average(const float4& a) -{ - return reduce_add(a) * 0.25f; -} - -__device_inline float dot(const float4& a, const float4& b) -{ - return reduce_add(a * b); -} - -#endif - /* Int3 */ #ifndef __KERNEL_OPENCL__ diff --git a/intern/cycles/util/util_transform.cpp b/intern/cycles/util/util_transform.cpp index 0fd26825911..1780994da27 100644 --- a/intern/cycles/util/util_transform.cpp +++ b/intern/cycles/util/util_transform.cpp @@ -53,6 +53,8 @@ CCL_NAMESPACE_BEGIN +/* Transform Inverse */ + static bool transform_matrix4_gj_inverse(float R[][4], float M[][4]) { /* forward elimination */ @@ -151,5 +153,104 @@ Transform transform_inverse(const Transform& tfm) return tfmR; } +/* Motion Transform */ + +static float4 transform_to_quat(const Transform& tfm) +{ + double trace = tfm[0][0] + tfm[1][1] + tfm[2][2]; + float4 qt; + + if(trace > 0.0f) { + double s = sqrt(trace + 1.0); + + qt.w = (float)(s/2.0); + s = 0.5/s; + + qt.x = (float)((tfm[2][1] - tfm[1][2]) * s); + qt.y = (float)((tfm[0][2] - tfm[2][0]) * s); + qt.z = (float)((tfm[1][0] - tfm[0][1]) * s); + } + else { + int i = 0; + + if(tfm[1][1] > tfm[i][i]) + i = 1; + if(tfm[2][2] > tfm[i][i]) + i = 2; + + int j = (i + 1)%3; + int k = (j + 1)%3; + + double s = sqrt((tfm[i][i] - (tfm[j][j] + tfm[k][k])) + 1.0); + + double q[3]; + q[i] = s * 0.5; + if(s != 0.0) + s = 0.5/s; + + double w = (tfm[k][j] - tfm[j][k]) * s; + q[j] = (tfm[j][i] + tfm[i][j]) * s; + q[k] = (tfm[k][i] + tfm[i][k]) * s; + + qt.x = (float)q[0]; + qt.y = (float)q[1]; + qt.z = (float)q[2]; + qt.w = (float)w; + } + + return qt; +} + +static void transform_decompose(Transform *decomp, const Transform *tfm) +{ + /* extract translation */ + decomp->y = make_float4(tfm->x.w, tfm->y.w, tfm->z.w, 0.0f); + + /* extract rotation */ + Transform M = *tfm; + M.x.w = 0.0f; M.y.w = 0.0f; M.z.w = 0.0f; M.w.w = 1.0f; + + Transform R = M; + float norm; + int iteration = 0; + + do { + Transform Rnext; + Transform Rit = transform_inverse(transform_transpose(R)); + + for(int i = 0; i < 4; i++) + for(int j = 0; j < 4; j++) + Rnext[i][j] = 0.5f * (R[i][j] + Rit[i][j]); + + norm = 0.0f; + for(int i = 0; i < 3; i++) { + norm = max(norm, + fabsf(R[i][0] - Rnext[i][0]) + + fabsf(R[i][1] - Rnext[i][1]) + + fabsf(R[i][2] - Rnext[i][2])); + } + + R = Rnext; + iteration++; + } while(iteration < 100 && norm > 1e-4f); + + if(transform_negative_scale(R)) + R = R * transform_scale(-1.0f, -1.0f, -1.0f); /* todo: test scale */ + + decomp->x = transform_to_quat(R); + + /* extract scale and pack it */ + Transform scale = transform_inverse(R) * M; + decomp->y.w = scale.x.x; + decomp->z = make_float4(scale.x.y, scale.x.z, scale.y.x, scale.y.y); + decomp->w = make_float4(scale.y.z, scale.z.x, scale.z.y, scale.z.z); +} + +void transform_motion_decompose(MotionTransform *decomp, const MotionTransform *motion) +{ + transform_decompose(&decomp->pre, &motion->pre); + transform_decompose(&decomp->post, &motion->post); +} + CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h index aeaef7b0e21..03dfbaa441d 100644 --- a/intern/cycles/util/util_transform.h +++ b/intern/cycles/util/util_transform.h @@ -28,6 +28,8 @@ CCL_NAMESPACE_BEGIN +/* Data Types */ + typedef struct Transform { float4 x, y, z, w; /* rows */ @@ -37,6 +39,17 @@ typedef struct Transform { #endif } Transform; +typedef struct MotionTransform { + Transform pre; + Transform post; +} MotionTransform; + +/* transform decomposed in rotation/translation/scale. we use the same data + * structure as Transform, and tightly pack decomposition into it. first the + * rotation (4), then translation (3), then 3x3 scale matrix (9) */ + +/* Functions */ + __device_inline float3 transform_perspective(const Transform *t, const float3 a) { float4 b = make_float4(a.x, a.y, a.z, 1.0f); @@ -62,6 +75,15 @@ __device_inline float3 transform_direction(const Transform *t, const float3 a) return c; } +__device_inline float3 transform_direction_transposed(const Transform *t, const float3 a) +{ + float3 x = make_float3(t->x.x, t->y.x, t->z.x); + float3 y = make_float3(t->x.y, t->y.y, t->z.y); + float3 z = make_float3(t->x.z, t->y.z, t->z.z); + + return make_float3(dot(x, a), dot(y, a), dot(z, a)); +} + #ifndef __KERNEL_GPU__ __device_inline void print_transform(const char *label, const Transform& t) @@ -272,6 +294,102 @@ __device_inline Transform transform_clear_scale(const Transform& tfm) #endif +/* Motion Transform */ + +__device_inline float4 quat_interpolate(float4 q1, float4 q2, float t) +{ + float costheta = dot(q1, q2); + + if(costheta > 0.9995f) { + return normalize((1.0f - t)*q1 + t*q2); + } + else { + float theta = acosf(clamp(costheta, -1.0f, 1.0f)); + float thetap = theta * t; + float4 qperp = normalize(q2 - q1 * costheta); + return q1 * cosf(thetap) + qperp * sinf(thetap); + } +} + +__device_inline Transform transform_quick_inverse(Transform M) +{ + Transform R; + float det = M.x.x*(M.z.z*M.y.y - M.z.y*M.y.z) - M.y.x*(M.z.z*M.x.y - M.z.y*M.x.z) + M.z.x*(M.y.z*M.x.y - M.y.y*M.x.z); + + det = (det != 0.0f)? 1.0f/det: 0.0f; + + float3 Rx = det*make_float3(M.z.z*M.y.y - M.z.y*M.y.z, M.z.y*M.x.z - M.z.z*M.x.y, M.y.z*M.x.y - M.y.y*M.x.z); + float3 Ry = det*make_float3(M.z.x*M.y.z - M.z.z*M.y.x, M.z.z*M.x.x - M.z.x*M.x.z, M.y.x*M.x.z - M.y.z*M.x.x); + float3 Rz = det*make_float3(M.z.y*M.y.x - M.z.x*M.y.y, M.z.x*M.x.y - M.z.y*M.x.x, M.y.y*M.x.x - M.y.x*M.x.y); + float3 T = -make_float3(M.x.w, M.y.w, M.z.w); + + R.x = make_float4(Rx.x, Rx.y, Rx.z, dot(Rx, T)); + R.y = make_float4(Ry.x, Ry.y, Ry.z, dot(Ry, T)); + R.z = make_float4(Rz.x, Rz.y, Rz.z, dot(Rz, T)); + R.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f); + + return R; +} + +__device_inline void transform_compose(Transform *tfm, const Transform *decomp) +{ + /* rotation */ + float q0, q1, q2, q3, qda, qdb, qdc, qaa, qab, qac, qbb, qbc, qcc; + + q0 = M_SQRT2_F * decomp->x.w; + q1 = M_SQRT2_F * decomp->x.x; + q2 = M_SQRT2_F * decomp->x.y; + q3 = M_SQRT2_F * decomp->x.z; + + qda = q0*q1; + qdb = q0*q2; + qdc = q0*q3; + qaa = q1*q1; + qab = q1*q2; + qac = q1*q3; + qbb = q2*q2; + qbc = q2*q3; + qcc = q3*q3; + + float3 rotation_x = make_float3(1.0f-qbb-qcc, -qdc+qab, qdb+qac); + float3 rotation_y = make_float3(qdc+qab, 1.0f-qaa-qcc, -qda+qbc); + float3 rotation_z = make_float3(-qdb+qac, qda+qbc, 1.0f-qaa-qbb); + + /* scale */ + float3 scale_x = make_float3(decomp->y.w, decomp->z.z, decomp->w.y); + float3 scale_y = make_float3(decomp->z.x, decomp->z.w, decomp->w.z); + float3 scale_z = make_float3(decomp->z.y, decomp->w.x, decomp->w.w); + + /* compose with translation */ + tfm->x = make_float4(dot(rotation_x, scale_x), dot(rotation_x, scale_y), dot(rotation_x, scale_z), decomp->y.x); + tfm->y = make_float4(dot(rotation_y, scale_x), dot(rotation_y, scale_y), dot(rotation_y, scale_z), decomp->y.y); + tfm->z = make_float4(dot(rotation_z, scale_x), dot(rotation_z, scale_y), dot(rotation_z, scale_z), decomp->y.z); + tfm->w = make_float4(0.0f, 0.0f, 0.0f, 1.0f); +} + +__device void transform_motion_interpolate(Transform *tfm, const MotionTransform *motion, float t) +{ + Transform decomp; + + decomp.x = quat_interpolate(motion->pre.x, motion->post.x, t); + decomp.y = (1.0f - t)*motion->pre.y + t*motion->post.y; + decomp.z = (1.0f - t)*motion->pre.z + t*motion->post.z; + decomp.w = (1.0f - t)*motion->pre.w + t*motion->post.w; + + transform_compose(tfm, &decomp); +} + +#ifndef __KERNEL_GPU__ + +__device_inline bool operator==(const MotionTransform& A, const MotionTransform& B) +{ + return (A.pre == B.pre && A.post == B.post); +} + +void transform_motion_decompose(MotionTransform *decomp, const MotionTransform *motion); + +#endif + CCL_NAMESPACE_END #endif /* __UTIL_TRANSFORM_H__ */ diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 971320765e9..4fced71d7f2 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -152,6 +152,7 @@ int object_insert_ptcache(struct Object *ob); struct KeyBlock *object_insert_shape_key(struct Scene *scene, struct Object *ob, const char *name, int from_mix); int object_is_modified(struct Scene *scene, struct Object *ob); +int object_is_deform_modified(struct Scene *scene, struct Object *ob); void object_relink(struct Object *ob); diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 9959edaac16..830184513d1 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -2982,8 +2982,7 @@ KeyBlock *object_insert_shape_key(Scene *scene, Object *ob, const char *name, in } /* most important if this is modified it should _always_ return True, in certain - * cases false positives are hard to avoid (shape keys for eg) - */ + * cases false positives are hard to avoid (shape keys for example) */ int object_is_modified(Scene *scene, Object *ob) { int flag= 0; @@ -2998,13 +2997,38 @@ int object_is_modified(Scene *scene, Object *ob) md && (flag != (eModifierMode_Render | eModifierMode_Realtime)); md=md->next) { - if ((flag & eModifierMode_Render) == 0 && modifier_isEnabled(scene, md, eModifierMode_Render)) { + if ((flag & eModifierMode_Render) == 0 && modifier_isEnabled(scene, md, eModifierMode_Render)) flag |= eModifierMode_Render; - } - if ((flag & eModifierMode_Realtime) == 0 && modifier_isEnabled(scene, md, eModifierMode_Realtime)) { + if ((flag & eModifierMode_Realtime) == 0 && modifier_isEnabled(scene, md, eModifierMode_Realtime)) + flag |= eModifierMode_Realtime; + } + } + + return flag; +} + +/* test if object is affected by deforming modifiers (for motion blur). again + * most important is to avoid false positives, this is to skip computations + * and we can still if there was actual deformation afterwards */ +int object_is_deform_modified(Scene *scene, Object *ob) +{ + ModifierData *md; + int flag= 0; + + /* cloth */ + for (md=modifiers_getVirtualModifierList(ob); + md && (flag != (eModifierMode_Render | eModifierMode_Realtime)); + md=md->next) + { + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + if (mti->type == eModifierTypeType_OnlyDeform) { + if (!(flag & eModifierMode_Render) && modifier_isEnabled(scene, md, eModifierMode_Render)) + flag |= eModifierMode_Render; + + if (!(flag & eModifierMode_Realtime) && modifier_isEnabled(scene, md, eModifierMode_Realtime)) flag |= eModifierMode_Realtime; - } } } diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index d09dedb4f4c..cb0f1d307aa 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -476,6 +476,11 @@ int rna_Object_is_modified(Object *ob, Scene *scene, int settings) return object_is_modified(scene, ob) & settings; } +int rna_Object_is_deform_modified(Object *ob, Scene *scene, int settings) +{ + return object_is_deform_modified(scene, ob) & settings; +} + #ifndef NDEBUG void rna_Object_dm_info(struct Object *ob, int type, char *result) { @@ -644,6 +649,14 @@ void RNA_api_object(StructRNA *srna) parm = RNA_def_boolean(func, "result", 0, "", "Object visibility"); RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "is_deform_modified", "rna_Object_is_deform_modified"); + RNA_def_function_ui_description(func, "Determine if this object is modified by a deformation from the base mesh data"); + parm = RNA_def_pointer(func, "scene", "Scene", "", ""); + RNA_def_property_flag(parm, PROP_REQUIRED|PROP_NEVER_NULL); + parm = RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Modifier settings to apply"); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm = RNA_def_boolean(func, "result", 0, "", "Object visibility"); + RNA_def_function_return(func, parm); #ifndef NDEBUG /* mesh */ diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index 08ed7625a01..c92a29cec3c 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -50,7 +50,7 @@ -static void rna_Scene_frame_set(Scene *scene, int frame, float subframe) +void rna_Scene_frame_set(Scene *scene, int frame, float subframe) { scene->r.cfra = frame; scene->r.subframe = subframe; |