diff options
author | Tamito Kajiyama <rd6t-kjym@asahi-net.or.jp> | 2013-01-06 02:24:05 +0400 |
---|---|---|
committer | Tamito Kajiyama <rd6t-kjym@asahi-net.or.jp> | 2013-01-06 02:24:05 +0400 |
commit | feccbaabbd39c18b2f552964ebd8dfab4eeaed89 (patch) | |
tree | 0069f654883a7a02dd320649ce61bd7933748111 /intern | |
parent | a22096e8019c461128a0907e4026859996ec1b5c (diff) | |
parent | 37ba969c74840142682cf22f34610f3b65b86cf4 (diff) |
Merged changes in the trunk up to revision 53584.
Conflicts resolved:
release/scripts/startup/bl_ui/properties_render.py
source/blender/blenloader/intern/readfile.c
source/blender/editors/interface/interface_templates.c
source/blender/makesrna/RNA_enum_types.h
Also made additional code updates for:
r53355 UIList - Python-extendable list of UI items
r53460 Alpha premul pipeline cleanup
Diffstat (limited to 'intern')
71 files changed, 3771 insertions, 652 deletions
diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt index 88363758364..710e8ba6a90 100644 --- a/intern/cycles/blender/CMakeLists.txt +++ b/intern/cycles/blender/CMakeLists.txt @@ -24,6 +24,7 @@ set(SRC blender_mesh.cpp blender_object.cpp blender_particles.cpp + blender_curves.cpp blender_python.cpp blender_session.cpp blender_shader.cpp diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py index 6d1b6d4f56e..dddf7bafb14 100644 --- a/intern/cycles/blender/addon/__init__.py +++ b/intern/cycles/blender/addon/__init__.py @@ -21,7 +21,7 @@ bl_info = { "name": "Cycles Render Engine", "author": "", - "blender": (2, 6, 5), + "blender": (2, 60, 5), "location": "Info header, render engine menu", "description": "Cycles Render Engine integration", "warning": "", diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 26fc7a81936..2bc4afe969e 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -64,6 +64,38 @@ enum_panorama_types = ( "Similar to most fisheye modern lens, takes sensor dimensions into consideration"), ) +enum_curve_presets = ( + ('CUSTOM', "Custom", "Set general parameters"), + ('TANGENT_SHADING', "Tangent Normal", "Use planar geometry and tangent normals"), + ('TRUE_NORMAL', "True Normal", "Use true normals (good for thin strands)"), + ('ACCURATE_PRESET', "Accurate", "Use best settings (suitable for glass materials)"), + ) + +enum_curve_primitives = ( + ('TRIANGLES', "Triangles", "Create triangle geometry around strands"), + ('LINE_SEGMENTS', "Line Segments", "Use line segment primitives"), + ('CURVE_SEGMENTS', "?Curve Segments?", "Use curve segment primitives (not implemented)"), + ) + +enum_triangle_curves = ( + ('CAMERA', "Planes", "Create individual triangles forming planes that face camera"), + ('RIBBONS', "Ribbons", "Create individual triangles forming ribbon"), + ('TESSELLATED', "Tessellated", "Create mesh surrounding each strand"), + ) + +enum_line_curves = ( + ('ACCURATE', "Accurate", "Always take into consideration strand width for intersections"), + ('QT_CORRECTED', "Corrected", "Ignore width for initial intersection and correct later"), + ('ENDCORRECTED', "Correct found", "Ignore width for all intersections and only correct closest"), + ('QT_UNCORRECTED', "Uncorrected", "Calculate intersections without considering width"), + ) + +enum_curves_interpolation = ( + ('LINEAR', "Linear interpolation", "Use Linear interpolation between segments"), + ('CARDINAL', "Cardinal interpolation", "Use cardinal interpolation between segments"), + ('BSPLINE', "B-spline interpolation", "Use b-spline interpolation between segments"), + ) + class CyclesRenderSettings(bpy.types.PropertyGroup): @classmethod def register(cls): @@ -237,7 +269,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): ) cls.film_transparent = BoolProperty( name="Transparent", - description="World background is transparent", + description="World background is transparent with premultiplied alpha", default=False, ) @@ -573,6 +605,157 @@ class CyclesMeshSettings(bpy.types.PropertyGroup): del bpy.types.Curve.cycles del bpy.types.MetaBall.cycles +class CyclesCurveRenderSettings(bpy.types.PropertyGroup): + @classmethod + def register(cls): + bpy.types.Scene.cycles_curves = PointerProperty( + name="Cycles Hair Rendering Settings", + description="Cycles hair rendering settings", + type=cls, + ) + cls.preset = EnumProperty( + name="Mode", + description="Hair rendering mode", + items=enum_curve_presets, + default='TRUE_NORMAL', + ) + cls.primitive = EnumProperty( + name="Primitive", + description="Type of primitive used for hair rendering", + items=enum_curve_primitives, + default='LINE_SEGMENTS', + ) + cls.triangle_method = EnumProperty( + name="Mesh Geometry", + description="Method for creating triangle geometry", + items=enum_triangle_curves, + default='CAMERA', + ) + cls.line_method = EnumProperty( + name="Intersection Method", + description="Method for line segment intersection", + items=enum_line_curves, + default='ACCURATE', + ) + cls.interpolation = EnumProperty( + name="Interpolation", + description="Interpolation method", + items=enum_curves_interpolation, + default='BSPLINE', + ) + cls.use_backfacing = BoolProperty( + name="Check back-faces", + description="Test back-faces of strands", + default=False, + ) + cls.use_encasing = BoolProperty( + name="Exclude encasing", + description="Ignore strands encasing a ray's initial location", + default=True, + ) + cls.use_tangent_normal_geometry = BoolProperty( + name="Tangent normal geometry", + description="Use the tangent normal for actual normal", + default=False, + ) + cls.use_tangent_normal = BoolProperty( + name="Tangent normal default", + description="Use the tangent normal for all normals", + default=False, + ) + cls.use_tangent_normal_correction = BoolProperty( + name="Strand slope correction", + description="Correct the tangent normal for the strand's slope", + default=False, + ) + cls.use_cache = BoolProperty( + name="Export Cached data", + default=True, + ) + cls.use_parents = BoolProperty( + name="Use parent strands", + description="Use parents with children", + default=False, + ) + cls.use_smooth = BoolProperty( + name="Smooth Strands", + description="Use vertex normals", + default=True, + ) + cls.use_joined = BoolProperty( + name="Join", + description="Fill gaps between segments (requires more memory)", + default=False, + ) + cls.use_curves = BoolProperty( + name="Use Cycles Hair Rendering", + description="Activate Cycles hair rendering for particle system", + default=True, + ) + cls.segments = IntProperty( + name="Segments", + description="Number of segments between path keys (note that this combines with the 'draw step' value)", + min=1, max=64, + default=1, + ) + cls.resolution = IntProperty( + name="Resolution", + description="Resolution of generated mesh", + min=3, max=64, + default=3, + ) + cls.normalmix = FloatProperty( + name="Normal mix", + description="Scale factor for tangent normal removal (zero gives ray normal)", + min=0, max=2.0, + default=1, + ) + cls.encasing_ratio = FloatProperty( + name="Encasing ratio", + description="Scale factor for encasing strand width", + min=0, max=100.0, + default=1.01, + ) + + @classmethod + def unregister(cls): + del bpy.types.Scene.cycles_curves + +class CyclesCurveSettings(bpy.types.PropertyGroup): + @classmethod + def register(cls): + bpy.types.ParticleSettings.cycles = PointerProperty( + name="Cycles Hair Settings", + description="Cycles hair settings", + type=cls, + ) + cls.root_width = FloatProperty( + name="Root Size Multiplier", + description="Multiplier of particle size for the strand's width at root", + min=0.0, max=1000.0, + default=1.0, + ) + cls.tip_width = FloatProperty( + name="Tip Size Multiplier", + description="Multiplier of particle size for the strand's width at tip", + min=0.0, max=1000.0, + default=0.0, + ) + cls.shape = FloatProperty( + name="Strand Shape", + description="Strand shape parameter", + min=-1.0, max=1.0, + default=0.0, + ) + cls.use_closetip = BoolProperty( + name="Close tip", + description="Set tip radius to zero", + default=True, + ) + + @classmethod + def unregister(cls): + del bpy.types.ParticleSettings.cycles def register(): bpy.utils.register_class(CyclesRenderSettings) @@ -582,6 +765,8 @@ def register(): bpy.utils.register_class(CyclesWorldSettings) bpy.utils.register_class(CyclesVisibilitySettings) bpy.utils.register_class(CyclesMeshSettings) + bpy.utils.register_class(CyclesCurveRenderSettings) + bpy.utils.register_class(CyclesCurveSettings) def unregister(): @@ -592,3 +777,5 @@ def unregister(): bpy.utils.unregister_class(CyclesWorldSettings) bpy.utils.unregister_class(CyclesMeshSettings) bpy.utils.unregister_class(CyclesVisibilitySettings) + bpy.utils.unregister_class(CyclesCurveRenderSettings) + bpy.utils.unregister_class(CyclesCurveSettings) diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 7b19fde8f71..554a9204c7f 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -290,7 +290,7 @@ class CyclesRender_PT_layers(CyclesButtonsPanel, Panel): rd = scene.render row = layout.row() - row.template_list(rd, "layers", rd.layers, "active_index", rows=2) + row.template_list("RENDER_UL_renderlayers", "", rd, "layers", rd.layers, "active_index", rows=2) col = row.column(align=True) col.operator("scene.render_layer_add", icon='ZOOMIN', text="") @@ -407,7 +407,7 @@ class Cycles_PT_context_material(CyclesButtonsPanel, Panel): if ob: row = layout.row() - row.template_list(ob, "material_slots", ob, "active_material_index", rows=2) + row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=2) col = row.column(align=True) col.operator("object.material_slot_add", icon='ZOOMIN', text="") @@ -962,7 +962,7 @@ class CyclesParticle_PT_textures(CyclesButtonsPanel, Panel): part = psys.settings row = layout.row() - row.template_list(part, "texture_slots", part, "active_texture_index", rows=2) + row.template_list("TEXTURE_UL_texslots", "", part, "texture_slots", part, "active_texture_index", rows=2) col = row.column(align=True) col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP' @@ -975,6 +975,89 @@ class CyclesParticle_PT_textures(CyclesButtonsPanel, Panel): slot = part.texture_slots[part.active_texture_index] layout.template_ID(slot, "texture", new="texture.new") +class CyclesRender_PT_CurveRendering(CyclesButtonsPanel, Panel): + bl_label = "Cycles Hair Rendering" + bl_context = "particle" + + @classmethod + def poll(cls, context): + psys = context.particle_system + device_type = context.user_preferences.system.compute_device_type + experimental = context.scene.cycles.feature_set == 'EXPERIMENTAL' and (context.scene.cycles.device == 'CPU' or device_type == 'NONE') + return CyclesButtonsPanel.poll(context) and experimental and psys + + def draw_header(self, context): + cscene = context.scene.cycles_curves + self.layout.prop(cscene, "use_curves", text="") + + def draw(self, context): + layout = self.layout + + scene = context.scene + cscene = scene.cycles_curves + + layout.active = cscene.use_curves + + layout.prop(cscene, "preset", text="Mode") + + if cscene.preset == 'CUSTOM': + layout.prop(cscene, "primitive", text="Primitive") + + if cscene.primitive == 'TRIANGLES': + layout.prop(cscene, "triangle_method", text="Method") + if cscene.triangle_method == 'TESSELLATED': + layout.prop(cscene, "resolution", text="Resolution") + layout.prop(cscene, "use_smooth", text="Smooth") + elif cscene.primitive == 'LINE_SEGMENTS': + layout.prop(cscene, "use_backfacing", text="Check back-faces") + + row = layout.row() + row.prop(cscene, "use_encasing", text="Exclude encasing") + sub = row.row() + sub.active = cscene.use_encasing + sub.prop(cscene, "encasing_ratio", text="Ratio for encasing") + + layout.prop(cscene, "line_method", text="Method") + layout.prop(cscene, "use_tangent_normal", text="Use tangent normal as default") + layout.prop(cscene, "use_tangent_normal_geometry", text="Use tangent normal geometry") + layout.prop(cscene, "use_tangent_normal_correction", text="Correct tangent normal for slope") + layout.prop(cscene, "interpolation", text="Interpolation") + + row = layout.row() + row.prop(cscene, "segments", text="Segments") + row.prop(cscene, "normalmix", text="Ray Mix") + + row = layout.row() + row.prop(cscene, "use_cache", text="Export cache with children") + if cscene.use_cache: + row.prop(cscene, "use_parents", text="Include parents") + +class CyclesParticle_PT_CurveSettings(CyclesButtonsPanel, Panel): + bl_label = "Cycles Hair Settings" + bl_context = "particle" + + @classmethod + def poll(cls, context): + use_curves = context.scene.cycles_curves.use_curves and context.particle_system + device_type = context.user_preferences.system.compute_device_type + experimental = context.scene.cycles.feature_set == 'EXPERIMENTAL' and (context.scene.cycles.device == 'CPU' or device_type == 'NONE') + return CyclesButtonsPanel.poll(context) and experimental and use_curves + + def draw(self, context): + layout = self.layout + + psys = context.particle_settings + cpsys = psys.cycles + + row = layout.row() + row.prop(cpsys, "shape", text="Shape") + row.prop(cpsys, "use_closetip", text="Close tip") + + layout.label(text="Width multiplier:") + row = layout.row() + row.prop(cpsys, "root_width", text="Root") + row.prop(cpsys, "tip_width", text="Tip") + class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel): bl_label = "Simplify" diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp new file mode 100644 index 00000000000..4fad7d45162 --- /dev/null +++ b/intern/cycles/blender/blender_curves.cpp @@ -0,0 +1,1130 @@ +/* + * Copyright 2011, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "attribute.h" +#include "mesh.h" +#include "object.h" +#include "scene.h" +#include "curves.h" + +#include "blender_sync.h" +#include "blender_util.h" + +#include "util_foreach.h" + +CCL_NAMESPACE_BEGIN + +/* Utilities */ + +/* Hair curve functions */ + +void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, float3 *v4, const float w[4]); +void interp_weights(float t, float data[4], int type); +float shaperadius(float shape, float root, float tip, float time); +void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData, int interpolation); +bool ObtainParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData); +bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents); +bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, int vcol_num); +bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents); +void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments, float3 RotCam); +void ExportCurveTriangleRibbons(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments); +void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int resolution, int segments); +void ExportCurveSegments(Mesh *mesh, ParticleCurveData *CData, int interpolation, int segments); +void ExportCurveTriangleUVs(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments, int vert_offset, int resol); + +ParticleCurveData::ParticleCurveData() +{ +} + +ParticleCurveData::~ParticleCurveData() +{ + psys_firstcurve.clear(); + psys_curvenum.clear(); + psys_shader.clear(); + psys_rootradius.clear(); + psys_tipradius.clear(); + psys_shape.clear(); + + curve_firstkey.clear(); + curve_keynum.clear(); + curve_length.clear(); + curve_uv.clear(); + curve_vcol.clear(); + + curvekey_co.clear(); + curvekey_time.clear(); +} + +void interp_weights(float t, float data[4], int type) +{ + float t2, t3, fc; + + if(type == CURVE_LINEAR) { + data[0] = 0.0f; + data[1] = -t + 1.0f; + data[2] = t; + data[3] = 0.0f; + } + else if(type == CURVE_CARDINAL) { + t2 = t * t; + t3 = t2 * t; + fc = 0.71f; + + data[0] = -fc * t3 + 2.0f * fc * t2 - fc * t; + data[1] = (2.0f - fc) * t3 + (fc - 3.0f) * t2 + 1.0f; + data[2] = (fc - 2.0f) * t3 + (3.0f - 2.0f * fc) * t2 + fc * t; + data[3] = fc * t3 - fc * t2; + } + else if(type == CURVE_BSPLINE) { + t2 = t * t; + t3 = t2 * t; + + data[0] = -0.16666666f * t3 + 0.5f * t2 - 0.5f * t + 0.16666666f; + data[1] = 0.5f * t3 - t2 + 0.66666666f; + data[2] = -0.5f * t3 + 0.5f * t2 + 0.5f * t + 0.16666666f; + data[3] = 0.16666666f * t3; + } +} + +void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, float3 *v4, const float w[4]) +{ + p->x = v1->x * w[0] + v2->x * w[1] + v3->x * w[2] + v4->x * w[3]; + p->y = v1->y * w[0] + v2->y * w[1] + v3->y * w[2] + v4->y * w[3]; + p->z = v1->z * w[0] + v2->z * w[1] + v3->z * w[2] + v4->z * w[3]; +} + +float shaperadius(float shape, float root, float tip, float time) +{ + float radius = 1.0f - time; + if(shape != 0.0f) { + if(shape < 0.0f) + radius = (float)pow(1.0f - time, 1.f + shape); + else + radius = (float)pow(1.0f - time, 1.f / (1.f - shape)); + } + return (radius * (root - tip)) + tip; +} + +/* curve functions */ + +void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData, int interpolation) +{ + float3 ckey_loc1 = CData->curvekey_co[key]; + float3 ckey_loc2 = ckey_loc1; + float3 ckey_loc3 = CData->curvekey_co[key+1]; + float3 ckey_loc4 = ckey_loc3; + + if(key > CData->curve_firstkey[curve]) + ckey_loc1 = CData->curvekey_co[key - 1]; + + if(key < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) + ckey_loc4 = CData->curvekey_co[key + 2]; + + + float time1 = CData->curvekey_time[key]/CData->curve_length[curve]; + float time2 = CData->curvekey_time[key + 1]/CData->curve_length[curve]; + + float dfra = (time2 - time1) / (float)segno; + + if(time) + *time = (dfra * seg) + time1; + + float t[4]; + + interp_weights((float)seg / (float)segno, t, interpolation); + + if(keyloc) + curveinterp_v3_v3v3v3v3(keyloc, &ckey_loc1, &ckey_loc2, &ckey_loc3, &ckey_loc4, t); +} + +bool ObtainParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData) +{ + + int curvenum = 0; + int keyno = 0; + + if(!(mesh && b_mesh && b_ob && CData)) + return false; + + BL::Object::modifiers_iterator b_mod; + for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) { + if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (b_mod->show_viewport()) && (b_mod->show_render())) { + + BL::ParticleSystemModifier psmd(b_mod->ptr); + + BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr); + + BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr); + + if((b_psys.settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys.settings().type()==BL::ParticleSettings::type_HAIR)) { + + int mi = clamp(b_psys.settings().material()-1, 0, mesh->used_shaders.size()-1); + int shader = mesh->used_shaders[mi]; + + int totcurves = b_psys.particles.length(); + + if(totcurves == 0) + continue; + + PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles"); + + CData->psys_firstcurve.push_back(curvenum); + CData->psys_curvenum.push_back(totcurves); + CData->psys_shader.push_back(shader); + + float radius = b_psys.settings().particle_size() * 0.5f; + + CData->psys_rootradius.push_back(radius * get_float(cpsys, "root_width")); + CData->psys_tipradius.push_back(radius * get_float(cpsys, "tip_width")); + CData->psys_shape.push_back(get_float(cpsys, "shape")); + CData->psys_closetip.push_back(get_boolean(cpsys, "use_closetip")); + + BL::ParticleSystem::particles_iterator b_pa; + for(b_psys.particles.begin(b_pa); b_pa != b_psys.particles.end(); ++b_pa) { + CData->curve_firstkey.push_back(keyno); + + int keylength = b_pa->hair_keys.length(); + CData->curve_keynum.push_back(keylength); + + float curve_length = 0.0f; + float3 pcKey; + int step_no = 0; + BL::Particle::hair_keys_iterator b_cKey; + for(b_pa->hair_keys.begin(b_cKey); b_cKey != b_pa->hair_keys.end(); ++b_cKey) { + float nco[3]; + b_cKey->co_object( *b_ob, psmd, *b_pa, nco); + float3 cKey = make_float3(nco[0],nco[1],nco[2]); + if(step_no > 0) + curve_length += len(cKey - pcKey); + CData->curvekey_co.push_back(cKey); + CData->curvekey_time.push_back(curve_length); + pcKey = cKey; + keyno++; + step_no++; + } + + CData->curve_length.push_back(curve_length); + /*add uvs*/ + BL::Mesh::tessface_uv_textures_iterator l; + b_mesh->tessface_uv_textures.begin(l); + + float3 uv = make_float3(0.0f, 0.0f, 0.0f); + if(b_mesh->tessface_uv_textures.length()) + b_pa->uv_on_emitter(psmd,&uv.x); + CData->curve_uv.push_back(uv); + + curvenum++; + + } + } + } + } + + return true; + +} + +bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents) +{ + + int curvenum = 0; + int keyno = 0; + + if(!(mesh && b_mesh && b_ob && CData)) + return false; + + Transform tfm = get_transform(b_ob->matrix_world()); + Transform itfm = transform_quick_inverse(tfm); + + BL::Object::modifiers_iterator b_mod; + for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) { + if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (b_mod->show_viewport()) && (b_mod->show_render())) { + BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr); + + BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr); + + BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr); + + if((b_psys.settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys.settings().type()==BL::ParticleSettings::type_HAIR)) { + + int mi = clamp(b_psys.settings().material()-1, 0, mesh->used_shaders.size()-1); + int shader = mesh->used_shaders[mi]; + int draw_step = b_psys.settings().draw_step(); + int ren_step = (int)pow((float)2.0f,(float)draw_step); + /*b_psys.settings().render_step(draw_step);*/ + + int totparts = b_psys.particles.length(); + int totchild = b_psys.child_particles.length() * b_psys.settings().draw_percentage() / 100; + int totcurves = totchild; + + if(use_parents || b_psys.settings().child_type() == 0) + totcurves += totparts; + + if(totcurves == 0) + continue; + + PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles"); + + CData->psys_firstcurve.push_back(curvenum); + CData->psys_curvenum.push_back(totcurves); + CData->psys_shader.push_back(shader); + + float radius = b_psys.settings().particle_size() * 0.5f; + + CData->psys_rootradius.push_back(radius * get_float(cpsys, "root_width")); + CData->psys_tipradius.push_back(radius * get_float(cpsys, "tip_width")); + CData->psys_shape.push_back(get_float(cpsys, "shape")); + CData->psys_closetip.push_back(get_boolean(cpsys, "use_closetip")); + + int pa_no = 0; + if(!use_parents && !(b_psys.settings().child_type() == 0)) + pa_no = totparts; + + for(; pa_no < totparts+totchild; pa_no++) { + + CData->curve_firstkey.push_back(keyno); + CData->curve_keynum.push_back(ren_step+1); + + float curve_length = 0.0f; + float3 pcKey; + for(int step_no = 0; step_no <= ren_step; step_no++) { + float nco[3]; + b_psys.co_hair(*b_ob, psmd, pa_no, step_no, nco); + float3 cKey = make_float3(nco[0],nco[1],nco[2]); + cKey = transform_point(&itfm, cKey); + if(step_no > 0) + curve_length += len(cKey - pcKey); + CData->curvekey_co.push_back(cKey); + CData->curvekey_time.push_back(curve_length); + pcKey = cKey; + keyno++; + } + CData->curve_length.push_back(curve_length); + + curvenum++; + + } + } + + } + } + + return true; + +} + +bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents) +{ + int keyno = 0; + + if(!(mesh && b_mesh && b_ob && CData)) + return false; + + Transform tfm = get_transform(b_ob->matrix_world()); + Transform itfm = transform_quick_inverse(tfm); + + BL::Object::modifiers_iterator b_mod; + for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) { + if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (b_mod->show_viewport()) && (b_mod->show_render())) { + BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr); + + BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr); + + BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr); + + if((b_psys.settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys.settings().type()==BL::ParticleSettings::type_HAIR)) { + + int mi = clamp(b_psys.settings().material()-1, 0, mesh->used_shaders.size()-1); + int shader = mesh->used_shaders[mi]; + int draw_step = b_psys.settings().draw_step(); + int ren_step = (int)pow((float)2.0f,(float)draw_step); + /*b_psys.settings().render_step(draw_step);*/ + + int totparts = b_psys.particles.length(); + int totchild = b_psys.child_particles.length() * b_psys.settings().draw_percentage() / 100; + int totcurves = totchild; + + if (use_parents || b_psys.settings().child_type() == 0) + totcurves += totparts; + + if (totcurves == 0) + continue; + + int pa_no = 0; + if(!use_parents && !(b_psys.settings().child_type() == 0)) + pa_no = totparts; + + BL::ParticleSystem::particles_iterator b_pa; + b_psys.particles.begin(b_pa); + for(; pa_no < totparts+totchild; pa_no++) { + + /*add uvs*/ + BL::Mesh::tessface_uv_textures_iterator l; + b_mesh->tessface_uv_textures.begin(l); + + float3 uv = make_float3(0.0f, 0.0f, 0.0f); + if(b_mesh->tessface_uv_textures.length()) + b_psys.uv_on_emitter(psmd, *b_pa, pa_no, &uv.x); + CData->curve_uv.push_back(uv); + + if(pa_no < totparts && b_pa != b_psys.particles.end()) + ++b_pa; + + } + } + + } + } + + return true; + +} + +bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, int vcol_num) +{ + int keyno = 0; + + if(!(mesh && b_mesh && b_ob && CData)) + return false; + + Transform tfm = get_transform(b_ob->matrix_world()); + Transform itfm = transform_quick_inverse(tfm); + + BL::Object::modifiers_iterator b_mod; + for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) { + if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (b_mod->show_viewport()) && (b_mod->show_render())) { + BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr); + + BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr); + + BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr); + + if((b_psys.settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys.settings().type()==BL::ParticleSettings::type_HAIR)) { + + int mi = clamp(b_psys.settings().material()-1, 0, mesh->used_shaders.size()-1); + int shader = mesh->used_shaders[mi]; + int draw_step = b_psys.settings().draw_step(); + int ren_step = (int)pow((float)2.0f,(float)draw_step); + /*b_psys.settings().render_step(draw_step);*/ + + int totparts = b_psys.particles.length(); + int totchild = b_psys.child_particles.length() * b_psys.settings().draw_percentage() / 100; + int totcurves = totchild; + + if (use_parents || b_psys.settings().child_type() == 0) + totcurves += totparts; + + if (totcurves == 0) + continue; + + int pa_no = 0; + if(!use_parents && !(b_psys.settings().child_type() == 0)) + pa_no = totparts; + + BL::ParticleSystem::particles_iterator b_pa; + b_psys.particles.begin(b_pa); + for(; pa_no < totparts+totchild; pa_no++) { + + /*add uvs*/ + BL::Mesh::tessface_vertex_colors_iterator l; + b_mesh->tessface_vertex_colors.begin(l); + + float3 vcol = make_float3(0.0f, 0.0f, 0.0f); + if(b_mesh->tessface_vertex_colors.length()) + b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x); + CData->curve_vcol.push_back(vcol); + + if(pa_no < totparts && b_pa != b_psys.particles.end()) + ++b_pa; + + } + } + + } + } + + return true; + +} + +void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments, float3 RotCam) +{ + int vertexno = mesh->verts.size(); + int vertexindex = vertexno; + + for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { + for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { + + for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { + + int subv = 1; + float3 xbasis; + + float3 v1; + + if(curvekey == CData->curve_firstkey[curve]) { + subv = 0; + v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey]; + } + else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) + v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[max(curvekey - 2, CData->curve_firstkey[curve])]; + else + v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey - 1]; + + + for (; subv <= segments; subv++) { + + float3 ickey_loc = make_float3(0.0f,0.0f,0.0f); + float time = 0.0f; + + if ((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0)) + ickey_loc = CData->curvekey_co[curvekey]; + else + InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation); + + float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time); + + if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) + radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f); + + if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) && (subv == segments)) + radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f); + + xbasis = normalize(cross(v1,RotCam - ickey_loc)); + float3 ickey_loc_shfl = ickey_loc - radius * xbasis; + float3 ickey_loc_shfr = ickey_loc + radius * xbasis; + mesh->verts.push_back(ickey_loc_shfl); + mesh->verts.push_back(ickey_loc_shfr); + if(subv!=0) { + mesh->add_triangle(vertexindex-2, vertexindex, vertexindex-1, CData->psys_shader[sys], use_smooth); + mesh->add_triangle(vertexindex+1, vertexindex-1, vertexindex, CData->psys_shader[sys], use_smooth); + } + vertexindex += 2; + } + } + } + } + + mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0); + mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); + mesh->attributes.remove(ATTR_STD_FACE_NORMAL); + mesh->add_face_normals(); + mesh->add_vertex_normals(); + mesh->attributes.remove(ATTR_STD_FACE_NORMAL); + + /* texture coords still needed */ +} + +void ExportCurveTriangleRibbons(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments) +{ + int vertexno = mesh->verts.size(); + int vertexindex = vertexno; + + for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { + for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { + + float3 firstxbasis = cross(make_float3(1.0f,0.0f,0.0f),CData->curvekey_co[CData->curve_firstkey[curve]+1] - CData->curvekey_co[CData->curve_firstkey[curve]]); + if(len_squared(firstxbasis)!= 0.0f) + firstxbasis = normalize(firstxbasis); + else + firstxbasis = normalize(cross(make_float3(0.0f,1.0f,0.0f),CData->curvekey_co[CData->curve_firstkey[curve]+1] - CData->curvekey_co[CData->curve_firstkey[curve]])); + + for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { + + float3 xbasis = firstxbasis; + float3 v1; + float3 v2; + + if(curvekey == CData->curve_firstkey[curve]) { + v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1]; + v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey]; + } + else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) { + v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; + v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])]; + } + else { + v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey]; + v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; + } + + xbasis = cross(v1,v2); + + if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) { + firstxbasis = normalize(xbasis); + break; + } + } + + for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { + + int subv = 1; + float3 v1; + float3 v2; + float3 xbasis; + + if(curvekey == CData->curve_firstkey[curve]) { + subv = 0; + v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1]; + v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey]; + } + else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) { + v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; + v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])]; + } + else { + v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey]; + v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; + } + + xbasis = cross(v1,v2); + + if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) { + xbasis = normalize(xbasis); + firstxbasis = xbasis; + } + else + xbasis = firstxbasis; + + for (; subv <= segments; subv++) { + + float3 ickey_loc = make_float3(0.0f,0.0f,0.0f); + float time = 0.0f; + + if ((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0)) + ickey_loc = CData->curvekey_co[curvekey]; + else + InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation); + + float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time); + + if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) + radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f); + + if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) && (subv == segments)) + radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f); + + float3 ickey_loc_shfl = ickey_loc - radius * xbasis; + float3 ickey_loc_shfr = ickey_loc + radius * xbasis; + mesh->verts.push_back(ickey_loc_shfl); + mesh->verts.push_back(ickey_loc_shfr); + if(subv!=0) { + mesh->add_triangle(vertexindex-2, vertexindex, vertexindex-1, CData->psys_shader[sys], use_smooth); + mesh->add_triangle(vertexindex+1, vertexindex-1, vertexindex, CData->psys_shader[sys], use_smooth); + } + vertexindex += 2; + } + } + } + } + + mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0); + mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); + mesh->attributes.remove(ATTR_STD_FACE_NORMAL); + mesh->add_face_normals(); + mesh->add_vertex_normals(); + mesh->attributes.remove(ATTR_STD_FACE_NORMAL); + /* texture coords still needed */ + +} + +void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int resolution, int segments) +{ + int vertexno = mesh->verts.size(); + int vertexindex = vertexno; + + for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { + for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { + + float3 firstxbasis = cross(make_float3(1.0f,0.0f,0.0f),CData->curvekey_co[CData->curve_firstkey[curve]+1] - CData->curvekey_co[CData->curve_firstkey[curve]]); + if(len_squared(firstxbasis)!= 0.0f) + firstxbasis = normalize(firstxbasis); + else + firstxbasis = normalize(cross(make_float3(0.0f,1.0f,0.0f),CData->curvekey_co[CData->curve_firstkey[curve]+1] - CData->curvekey_co[CData->curve_firstkey[curve]])); + + + for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { + + float3 xbasis = firstxbasis; + float3 v1; + float3 v2; + + if(curvekey == CData->curve_firstkey[curve]) { + v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1]; + v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey]; + } + else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) { + v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; + v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])]; + } + else { + v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey]; + v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; + } + + xbasis = cross(v1,v2); + + if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) { + firstxbasis = normalize(xbasis); + break; + } + } + + for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { + + int subv = 1; + float3 xbasis; + float3 ybasis; + float3 v1; + float3 v2; + + if(curvekey == CData->curve_firstkey[curve]) { + subv = 0; + v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1]; + v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey]; + } + else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) { + v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; + v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])]; + } + else { + v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey]; + v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; + } + + xbasis = cross(v1,v2); + + if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) { + xbasis = normalize(xbasis); + firstxbasis = xbasis; + } + else + xbasis = firstxbasis; + + ybasis = normalize(cross(xbasis,v2)); + + for (; subv <= segments; subv++) { + + float3 ickey_loc = make_float3(0.0f,0.0f,0.0f); + float time = 0.0f; + + if ((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0)) + ickey_loc = CData->curvekey_co[curvekey]; + else + InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation); + + float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time); + + if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) + radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f); + + if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) && (subv == segments)) + radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f); + + float angle = 2 * M_PI_F / (float)resolution; + for(int section = 0 ; section < resolution; section++) { + float3 ickey_loc_shf = ickey_loc + radius * (cosf(angle * section) * xbasis + sinf(angle * section) * ybasis); + mesh->verts.push_back(ickey_loc_shf); + } + + if(subv!=0) { + for(int section = 0 ; section < resolution - 1; section++) { + mesh->add_triangle(vertexindex - resolution + section, vertexindex + section, vertexindex - resolution + section + 1, CData->psys_shader[sys], use_smooth); + mesh->add_triangle(vertexindex + section + 1, vertexindex - resolution + section + 1, vertexindex + section, CData->psys_shader[sys], use_smooth); + } + mesh->add_triangle(vertexindex-1, vertexindex + resolution - 1, vertexindex - resolution, CData->psys_shader[sys], use_smooth); + mesh->add_triangle(vertexindex, vertexindex - resolution , vertexindex + resolution - 1, CData->psys_shader[sys], use_smooth); + } + vertexindex += resolution; + } + } + } + } + + mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0); + mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); + mesh->attributes.remove(ATTR_STD_FACE_NORMAL); + mesh->add_face_normals(); + mesh->add_vertex_normals(); + mesh->attributes.remove(ATTR_STD_FACE_NORMAL); + + /* texture coords still needed */ +} + +static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData, int interpolation, int segments) +{ + int num_keys = 0; + int num_curves = 0; + + if(!(mesh->curves.empty() && mesh->curve_keys.empty())) + return; + + Attribute *attr_uv = NULL, *attr_intercept = NULL; + + if(mesh->need_attribute(scene, ATTR_STD_UV)) + attr_uv = mesh->curve_attributes.add(ATTR_STD_UV); + if(mesh->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT)) + attr_intercept = mesh->curve_attributes.add(ATTR_STD_CURVE_INTERCEPT); + + for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { + + if(CData->psys_curvenum[sys] == 0) + continue; + + for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { + + if(CData->curve_keynum[curve] <= 1) + continue; + + size_t num_curve_keys = 0; + + for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { + + int subv = 1; + if(curvekey == CData->curve_firstkey[curve]) + subv = 0; + + for (; subv <= segments; subv++) { + + float3 ickey_loc = make_float3(0.0f,0.0f,0.0f); + float time = 0.0f; + + if((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0)) + ickey_loc = CData->curvekey_co[curvekey]; + else + InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation); + + float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time); + + if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2)) + radius =0.0f; + + mesh->add_curve_key(ickey_loc, radius); + if(attr_intercept) + attr_intercept->add(time); + + num_curve_keys++; + } + } + + mesh->add_curve(num_keys, num_curve_keys, CData->psys_shader[sys]); + if(attr_uv) + attr_uv->add(CData->curve_uv[curve]); + + num_keys += num_curve_keys; + num_curves++; + } + } + + /* check allocation*/ + if((mesh->curve_keys.size() != num_keys) || (mesh->curves.size() != num_curves)) { + /* allocation failed -> clear data */ + mesh->curve_keys.clear(); + mesh->curves.clear(); + mesh->curve_attributes.clear(); + } +} + +void ExportCurveTriangleUVs(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments, int vert_offset, int resol) +{ + float time = 0.0f; + float prevtime = 0.0f; + + Attribute *attr = mesh->attributes.find(ATTR_STD_UV); + if (attr == NULL) + return; + + float3 *uvdata = attr->data_float3(); + + int vertexindex = vert_offset; + + for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { + for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { + + for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { + + int subv = 1; + + if (curvekey == CData->curve_firstkey[curve]) + subv = 0; + + for (; subv <= segments; subv++) { + + float3 ickey_loc = make_float3(0.0f,0.0f,0.0f); + + InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation); + + if(subv!=0) { + for(int section = 0 ; section < resol; section++) { + uvdata[vertexindex] = CData->curve_uv[curve]; + uvdata[vertexindex].z = prevtime; + vertexindex++; + uvdata[vertexindex] = CData->curve_uv[curve]; + uvdata[vertexindex].z = time; + vertexindex++; + uvdata[vertexindex] = CData->curve_uv[curve]; + uvdata[vertexindex].z = prevtime; + vertexindex++; + uvdata[vertexindex] = CData->curve_uv[curve]; + uvdata[vertexindex].z = time; + vertexindex++; + uvdata[vertexindex] = CData->curve_uv[curve]; + uvdata[vertexindex].z = prevtime; + vertexindex++; + uvdata[vertexindex] = CData->curve_uv[curve]; + uvdata[vertexindex].z = time; + vertexindex++; + } + } + + prevtime = time; + } + } + } + } + +} +/* Hair Curve Sync */ + +void BlenderSync::sync_curve_settings() +{ + PointerRNA csscene = RNA_pointer_get(&b_scene.ptr, "cycles_curves"); + + int preset = get_enum(csscene, "preset"); + + CurveSystemManager *curve_system_manager = scene->curve_system_manager; + CurveSystemManager prev_curve_system_manager = *curve_system_manager; + + curve_system_manager->use_curves = get_boolean(csscene, "use_curves"); + + if(preset == CURVE_CUSTOM) { + /*custom properties*/ + curve_system_manager->primitive = get_enum(csscene, "primitive"); + curve_system_manager->line_method = get_enum(csscene, "line_method"); + curve_system_manager->interpolation = get_enum(csscene, "interpolation"); + curve_system_manager->triangle_method = get_enum(csscene, "triangle_method"); + curve_system_manager->resolution = get_int(csscene, "resolution"); + curve_system_manager->segments = get_int(csscene, "segments"); + curve_system_manager->use_smooth = get_boolean(csscene, "use_smooth"); + + curve_system_manager->normalmix = get_float(csscene, "normalmix"); + curve_system_manager->encasing_ratio = get_float(csscene, "encasing_ratio"); + + curve_system_manager->use_cache = get_boolean(csscene, "use_cache"); + curve_system_manager->use_parents = get_boolean(csscene, "use_parents"); + curve_system_manager->use_encasing = get_boolean(csscene, "use_encasing"); + curve_system_manager->use_backfacing = get_boolean(csscene, "use_backfacing"); + curve_system_manager->use_joined = get_boolean(csscene, "use_joined"); + curve_system_manager->use_tangent_normal = get_boolean(csscene, "use_tangent_normal"); + curve_system_manager->use_tangent_normal_geometry = get_boolean(csscene, "use_tangent_normal_geometry"); + curve_system_manager->use_tangent_normal_correction = get_boolean(csscene, "use_tangent_normal_correction"); + } + else { + curve_system_manager->primitive = CURVE_LINE_SEGMENTS; + curve_system_manager->interpolation = CURVE_CARDINAL; + curve_system_manager->normalmix = 1.0f; + curve_system_manager->encasing_ratio = 1.01f; + curve_system_manager->use_cache = true; + curve_system_manager->use_parents = false; + curve_system_manager->segments = 1; + curve_system_manager->use_joined = false; + + switch(preset) { + case CURVE_TANGENT_SHADING: + /*tangent shading*/ + curve_system_manager->line_method = CURVE_UNCORRECTED; + curve_system_manager->use_encasing = true; + curve_system_manager->use_backfacing = false; + curve_system_manager->use_tangent_normal = true; + curve_system_manager->use_tangent_normal_geometry = true; + curve_system_manager->use_tangent_normal_correction = false; + break; + case CURVE_TRUE_NORMAL: + /*True Normal*/ + curve_system_manager->line_method = CURVE_CORRECTED; + curve_system_manager->use_encasing = true; + curve_system_manager->use_backfacing = false; + curve_system_manager->use_tangent_normal = false; + curve_system_manager->use_tangent_normal_geometry = false; + curve_system_manager->use_tangent_normal_correction = false; + break; + case CURVE_ACCURATE_PRESET: + /*Accurate*/ + curve_system_manager->line_method = CURVE_ACCURATE; + curve_system_manager->use_encasing = false; + curve_system_manager->use_backfacing = true; + curve_system_manager->use_tangent_normal = false; + curve_system_manager->use_tangent_normal_geometry = false; + curve_system_manager->use_tangent_normal_correction = false; + break; + } + + } + + if(curve_system_manager->modified_mesh(prev_curve_system_manager)) + { + BL::BlendData::objects_iterator b_ob; + + for(b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) { + if(object_is_mesh(*b_ob)) { + BL::Object::particle_systems_iterator b_psys; + for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) { + if((b_psys->settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys->settings().type()==BL::ParticleSettings::type_HAIR)) { + BL::ID key = BKE_object_is_modified(*b_ob)? *b_ob: b_ob->data(); + mesh_map.set_recalc(key); + object_map.set_recalc(*b_ob); + } + } + } + } + } + + if(curve_system_manager->modified(prev_curve_system_manager)) + curve_system_manager->tag_update(scene); + +} + +void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool object_updated) +{ + /* Clear stored curve data */ + mesh->curve_keys.clear(); + mesh->curves.clear(); + mesh->curve_attributes.clear(); + + /* obtain general settings */ + bool use_curves = scene->curve_system_manager->use_curves; + + if(!(use_curves && b_ob.mode() == b_ob.mode_OBJECT)) { + mesh->compute_bounds(); + return; + } + + int primitive = scene->curve_system_manager->primitive; + int interpolation = scene->curve_system_manager->interpolation; + int triangle_method = scene->curve_system_manager->triangle_method; + int resolution = scene->curve_system_manager->resolution; + int segments = scene->curve_system_manager->segments; + bool use_smooth = scene->curve_system_manager->use_smooth; + bool use_cache = scene->curve_system_manager->use_cache; + bool use_parents = scene->curve_system_manager->use_parents; + bool export_tgs = scene->curve_system_manager->use_joined; + + /* extract particle hair data - should be combined with connecting to mesh later*/ + + ParticleCurveData CData; + + if(use_cache) { + ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, use_parents); + ObtainCacheParticleUV(mesh, &b_mesh, &b_ob, &CData, use_parents); + } + else + ObtainParticleData(mesh, &b_mesh, &b_ob, &CData); + + /* attach strands to mesh */ + BL::Object b_CamOb = b_scene.camera(); + float3 RotCam = make_float3(0.0f, 0.0f, 0.0f); + if(b_CamOb) { + Transform ctfm = get_transform(b_CamOb.matrix_world()); + Transform tfm = get_transform(b_ob.matrix_world()); + Transform itfm = transform_quick_inverse(tfm); + RotCam = transform_point(&itfm, make_float3(ctfm.x.w, ctfm.y.w, ctfm.z.w)); + } + + if(primitive == CURVE_TRIANGLES){ + int vert_num = mesh->triangles.size() * 3; + if(triangle_method == CURVE_CAMERA) { + ExportCurveTrianglePlanes(mesh, &CData, interpolation, use_smooth, segments, RotCam); + ExportCurveTriangleUVs(mesh, &CData, interpolation, use_smooth, segments, vert_num, 1); + } + else if(triangle_method == CURVE_RIBBONS) { + ExportCurveTriangleRibbons(mesh, &CData, interpolation, use_smooth, segments); + ExportCurveTriangleUVs(mesh, &CData, interpolation, use_smooth, segments, vert_num, 1); + } + else { + ExportCurveTriangleGeometry(mesh, &CData, interpolation, use_smooth, resolution, segments); + ExportCurveTriangleUVs(mesh, &CData, interpolation, use_smooth, segments, vert_num, resolution); + } + + } + else { + ExportCurveSegments(scene, mesh, &CData, interpolation, segments); + int ckey_num = mesh->curve_keys.size(); + + /*export tangents or curve data? - not functional yet*/ + if(export_tgs && ckey_num > 1) { + Attribute *attr_tangent = mesh->curve_attributes.add(ATTR_STD_CURVE_TANGENT); + float3 *data_tangent = attr_tangent->data_float3(); + + for(int ck = 0; ck < ckey_num; ck++) { + float3 tg = normalize(normalize(mesh->curve_keys[min(ck + 1, ckey_num - 1)].co - mesh->curve_keys[ck].co) - + normalize(mesh->curve_keys[max(ck - 1, 0)].co - mesh->curve_keys[ck].co)); + + data_tangent[ck] = tg; + } + } + + /* generated coordinates from first key. we should ideally get this from + * blender to handle deforming objects */ + if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) { + float3 loc, size; + mesh_texture_space(b_mesh, loc, size); + + Attribute *attr_generated = mesh->curve_attributes.add(ATTR_STD_GENERATED); + float3 *generated = attr_generated->data_float3(); + size_t i = 0; + + foreach(Mesh::Curve& curve, mesh->curves) { + float3 co = mesh->curve_keys[curve.first_key].co; + generated[i++] = co*size - loc; + } + } + + /* create vertex color attributes */ + BL::Mesh::tessface_vertex_colors_iterator l; + int vcol_num = 0; + + for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l, vcol_num++) { + if(!mesh->need_attribute(scene, ustring(l->name().c_str()))) + continue; + + /*error occurs with more than one vertex colour attribute so avoided*/ + if(vcol_num!=0) + break; + + Attribute *attr_vcol = mesh->curve_attributes.add( + ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CURVE); + + ObtainCacheParticleVcol(mesh, &b_mesh, &b_ob, &CData, use_parents, 0); + + float3 *vcol = attr_vcol->data_float3(); + + if(vcol) { + for(size_t curve = 0; curve < CData.curve_vcol.size() ;curve++) + vcol[curve] = color_srgb_to_scene_linear(CData.curve_vcol[curve]); + } + + } + + } + + mesh->compute_bounds(); +} + + +CCL_NAMESPACE_END + diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index c9748756d43..1dd7800dfa4 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -147,7 +147,7 @@ static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer b_la if(active_render) attr = mesh->attributes.add(ATTR_STD_UV_TANGENT, name); else - attr = mesh->attributes.add(name, TypeDesc::TypeVector, Attribute::CORNER); + attr = mesh->attributes.add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER); float3 *tangent = attr->data_float3(); @@ -161,7 +161,7 @@ static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer b_la if(active_render) attr_sign = mesh->attributes.add(ATTR_STD_UV_TANGENT_SIGN, name_sign); else - attr_sign = mesh->attributes.add(name_sign, TypeDesc::TypeFloat, Attribute::CORNER); + attr_sign = mesh->attributes.add(name_sign, TypeDesc::TypeFloat, ATTR_ELEMENT_CORNER); tangent_sign = attr_sign->data_float(); } @@ -223,10 +223,19 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector< int shader = used_shaders[mi]; bool smooth = f->use_smooth(); - mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth); - - if(n == 4) - mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth); + if(n == 4) { + if(len_squared(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) == 0.0f || + len_squared(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]])) == 0.0f) { + mesh->add_triangle(vi[0], vi[1], vi[3], shader, smooth); + mesh->add_triangle(vi[2], vi[3], vi[1], shader, smooth); + } + else { + mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth); + mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth); + } + } + else + mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth); nverts.push_back(n); } @@ -240,7 +249,7 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector< continue; Attribute *attr = mesh->attributes.add( - ustring(l->name().c_str()), TypeDesc::TypeColor, Attribute::CORNER); + ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER); BL::MeshColorLayer::data_iterator c; float3 *fdata = attr->data_float3(); @@ -279,7 +288,7 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector< if(active_render) attr = mesh->attributes.add(std, name); else - attr = mesh->attributes.add(name, TypeDesc::TypePoint, Attribute::CORNER); + attr = mesh->attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER); BL::MeshTextureFaceLayer::data_iterator t; float3 *fdata = attr->data_float3(); @@ -319,14 +328,9 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector< * is available in the api. */ 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()); - if(size.x != 0.0f) size.x = 0.5f/size.x; - if(size.y != 0.0f) size.y = 0.5f/size.y; - if(size.z != 0.0f) size.z = 0.5f/size.z; - - loc = loc*size - make_float3(0.5f, 0.5f, 0.5f); + float3 loc, size; + mesh_texture_space(b_mesh, loc, size); float3 *generated = attr->data_float3(); size_t i = 0; @@ -376,7 +380,7 @@ static void create_subd_mesh(Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, con /* Sync */ -Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated) +Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris) { /* test if we can instance or if the object is modified */ BL::ID b_ob_data = b_ob.data(); @@ -435,16 +439,24 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated) PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles"); vector<Mesh::Triangle> oldtriangle = mesh->triangles; + + /* compares curve_keys rather than strands in order to handle quick hair adjustsments in dynamic BVH - other methods could probably do this better*/ + vector<Mesh::CurveKey> oldcurve_keys = mesh->curve_keys; mesh->clear(); mesh->used_shaders = used_shaders; mesh->name = ustring(b_ob_data.name().c_str()); if(b_mesh) { - if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision")) - create_subd_mesh(mesh, b_mesh, &cmesh, used_shaders); - else - create_mesh(scene, mesh, b_mesh, used_shaders); + if(!(hide_tris && experimental && is_cpu)) { + if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision")) + create_subd_mesh(mesh, b_mesh, &cmesh, used_shaders); + else + create_mesh(scene, mesh, b_mesh, used_shaders); + } + + if(experimental && is_cpu) + sync_curves(mesh, b_mesh, b_ob, object_updated); /* free derived mesh */ b_data.meshes.remove(b_mesh); @@ -471,6 +483,13 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated) if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0) rebuild = true; } + + if(oldcurve_keys.size() != mesh->curve_keys.size()) + rebuild = true; + else if(oldcurve_keys.size()) { + if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(Mesh::CurveKey)*oldcurve_keys.size()) != 0) + rebuild = true; + } mesh->tag_update(scene, rebuild); diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 38f27bcf2af..ad701266c5b 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -196,7 +196,7 @@ void BlenderSync::sync_background_light() /* Object */ -Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_ob, Transform& tfm, uint layer_flag, int motion) +Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_ob, Transform& tfm, uint layer_flag, int motion, bool hide_tris) { BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent); @@ -247,7 +247,7 @@ Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_P bool use_holdout = (layer_flag & render_layer.holdout_layer) != 0; /* mesh sync */ - object->mesh = sync_mesh(b_ob, object_updated); + object->mesh = sync_mesh(b_ob, object_updated, hide_tris); /* sspecial case not tracked by object update flags */ if(use_holdout != object->use_holdout) { @@ -390,7 +390,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion) BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_dup->persistent_id(); /* sync object and mesh or light data */ - Object *object = sync_object(*b_ob, persistent_id.data, *b_dup, tfm, ob_layer, motion); + Object *object = sync_object(*b_ob, persistent_id.data, *b_dup, tfm, ob_layer, motion, false); /* sync possible particle data, note particle_id * starts counting at 1, first is dummy particle */ @@ -412,9 +412,23 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion) /* check if we should render or hide particle emitter */ BL::Object::particle_systems_iterator b_psys; - for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) - if(b_psys->settings().use_render_emitter()) + bool hair_present = false; + bool show_emitter = false; + bool hide_tris = false; + + for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) { + + if((b_psys->settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys->settings().type()==BL::ParticleSettings::type_HAIR)) + hair_present = true; + + if(b_psys->settings().use_render_emitter()) { hide = false; + show_emitter = true; + } + } + + if(hair_present && !show_emitter) + hide_tris = true; /* hide original object for duplis */ BL::Object parent = b_ob->parent(); @@ -424,7 +438,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion) if(!hide) { /* object itself */ Transform tfm = get_transform(b_ob->matrix_world()); - sync_object(*b_ob, NULL, PointerRNA_NULL, tfm, ob_layer, motion); + sync_object(*b_ob, NULL, PointerRNA_NULL, tfm, ob_layer, motion, hide_tris); } } diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index b8ed942f5b6..770b71afcdc 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -96,7 +96,7 @@ void BlenderSession::create_session() session->set_pause(BlenderSync::get_session_pause(b_scene, background)); /* create sync */ - sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress); + sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress, session_params.device.type == DEVICE_CPU); sync->sync_data(b_v3d, b_engine.camera_override()); if(b_rv3d) @@ -107,6 +107,8 @@ void BlenderSession::create_session() /* set buffer parameters */ BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, b_v3d, b_rv3d, scene->camera, width, height); session->reset(buffer_params, session_params.samples); + + b_engine.use_highlight_tiles(session_params.progressive_refine == false); } void BlenderSession::reset_session(BL::BlendData b_data_, BL::Scene b_scene_) @@ -143,12 +145,14 @@ void BlenderSession::reset_session(BL::BlendData b_data_, BL::Scene b_scene_) session->stats.mem_peak = session->stats.mem_used; /* sync object should be re-created */ - sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress); + sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress, session_params.device.type == DEVICE_CPU); sync->sync_data(b_v3d, b_engine.camera_override()); sync->sync_camera(b_engine.camera_override(), width, height); BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, PointerRNA_NULL, PointerRNA_NULL, scene->camera, width, height); session->reset(buffer_params, session_params.samples); + + b_engine.use_highlight_tiles(session_params.progressive_refine == false); } void BlenderSession::free_session() @@ -252,7 +256,15 @@ void BlenderSession::do_write_update_render_tile(RenderTile& rtile, bool do_upda if (do_update_only) { /* update only needed */ - update_render_result(b_rr, b_rlay, rtile); + + if (rtile.sample != 0) { + /* sample would be zero at initial tile update, which is only needed + * to tag tile form blender side as IN PROGRESS for proper highlight + * no buffers should be sent to blender yet + */ + update_render_result(b_rr, b_rlay, rtile); + } + end_render_result(b_engine, b_rr, true); } else { diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 848a9a199f9..ddbd7f935e4 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -447,6 +447,10 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen node = new ParticleInfoNode(); break; } + case BL::ShaderNode::type_HAIR_INFO: { + node = new HairInfoNode(); + break; + } case BL::ShaderNode::type_BUMP: { node = new BumpNode(); break; diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index d455bdbe8e2..b9860ca90f2 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -28,6 +28,7 @@ #include "object.h" #include "scene.h" #include "shader.h" +#include "curves.h" #include "device.h" @@ -41,7 +42,7 @@ CCL_NAMESPACE_BEGIN /* Constructor */ -BlenderSync::BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_, Scene *scene_, bool preview_, Progress &progress_) +BlenderSync::BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_, Scene *scene_, bool preview_, Progress &progress_, bool is_cpu_) : b_engine(b_engine_), b_data(b_data_), b_scene(b_scene_), shader_map(&scene_->shaders), @@ -56,6 +57,7 @@ BlenderSync::BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL:: { scene = scene_; preview = preview_; + is_cpu = is_cpu_; } BlenderSync::~BlenderSync() @@ -141,6 +143,7 @@ void BlenderSync::sync_data(BL::SpaceView3D b_v3d, BL::Object b_override, const sync_integrator(); sync_film(); sync_shaders(); + sync_curve_settings(); sync_objects(b_v3d); sync_motion(b_v3d, b_override); } diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index d3d21fbdf72..5050743f1cf 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -50,7 +50,7 @@ class ShaderNode; class BlenderSync { public: - BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data, BL::Scene b_scene, Scene *scene_, bool preview_, Progress &progress_); + BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data, BL::Scene b_scene, Scene *scene_, bool preview_, Progress &progress_, bool is_cpu_); ~BlenderSync(); /* sync */ @@ -78,10 +78,12 @@ private: void sync_world(bool update_all); void sync_render_layers(BL::SpaceView3D b_v3d, const char *layer); void sync_shaders(); + void sync_curve_settings(); void sync_nodes(Shader *shader, BL::ShaderNodeTree b_ntree); - Mesh *sync_mesh(BL::Object b_ob, bool object_updated); - Object *sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_object, Transform& tfm, uint layer_flag, int motion); + Mesh *sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris); + void sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool object_updated); + Object *sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_object, Transform& tfm, uint layer_flag, int motion, bool hide_tris); void sync_light(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::Object b_ob, Transform& tfm); void sync_background_light(); void sync_mesh_motion(BL::Object b_ob, Mesh *mesh, int motion); @@ -113,6 +115,7 @@ private: Scene *scene; bool preview; bool experimental; + bool is_cpu; struct RenderLayerInfo { RenderLayerInfo() diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index fbcbe15ec5a..88c98860794 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -242,6 +242,20 @@ static inline string blender_absolute_path(BL::BlendData b_data, BL::ID b_id, co return path; } +/* Texture Space */ + +static inline void mesh_texture_space(BL::Mesh b_mesh, float3& loc, float3& size) +{ + loc = get_float3(b_mesh.texspace_location()); + size = get_float3(b_mesh.texspace_size()); + + if(size.x != 0.0f) size.x = 0.5f/size.x; + if(size.y != 0.0f) size.y = 0.5f/size.y; + if(size.z != 0.0f) size.z = 0.5f/size.z; + + loc = loc*size - make_float3(0.5f, 0.5f, 0.5f); +} + /* ID Map * * Utility class to keep in sync with blender data. diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp index b58a34f9942..412b44031e6 100644 --- a/intern/cycles/bvh/bvh.cpp +++ b/intern/cycles/bvh/bvh.cpp @@ -75,6 +75,8 @@ bool BVH::cache_read(CacheData& key) foreach(Object *ob, objects) { key.add(ob->mesh->verts); key.add(ob->mesh->triangles); + key.add(ob->mesh->curve_keys); + key.add(ob->mesh->curves); key.add(&ob->bounds, sizeof(ob->bounds)); key.add(&ob->visibility, sizeof(ob->visibility)); key.add(&ob->mesh->transform_applied, sizeof(bool)); @@ -91,6 +93,7 @@ bool BVH::cache_read(CacheData& key) value.read(pack.nodes); value.read(pack.object_node); value.read(pack.tri_woop); + value.read(pack.prim_segment); value.read(pack.prim_visibility); value.read(pack.prim_index); value.read(pack.prim_object); @@ -112,6 +115,7 @@ void BVH::cache_write(CacheData& key) value.add(pack.nodes); value.add(pack.object_node); value.add(pack.tri_woop); + value.add(pack.prim_segment); value.add(pack.prim_visibility); value.add(pack.prim_index); value.add(pack.prim_object); @@ -157,10 +161,11 @@ void BVH::build(Progress& progress) } /* build nodes */ + vector<int> prim_segment; vector<int> prim_index; vector<int> prim_object; - BVHBuild bvh_build(objects, prim_index, prim_object, params, progress); + BVHBuild bvh_build(objects, prim_segment, prim_index, prim_object, params, progress); BVHNode *root = bvh_build.run(); if(progress.get_cancel()) { @@ -169,6 +174,7 @@ void BVH::build(Progress& progress) } /* todo: get rid of this copy */ + pack.prim_segment = prim_segment; pack.prim_index = prim_index; pack.prim_object = prim_object; @@ -182,8 +188,8 @@ void BVH::build(Progress& progress) } /* pack triangles */ - progress.set_substatus("Packing BVH triangles"); - pack_triangles(); + progress.set_substatus("Packing BVH triangles and strands"); + pack_primitives(); if(progress.get_cancel()) { root->deleteSubtree(); @@ -215,8 +221,8 @@ void BVH::build(Progress& progress) void BVH::refit(Progress& progress) { - progress.set_substatus("Packing BVH triangles"); - pack_triangles(); + progress.set_substatus("Packing BVH primitives"); + pack_primitives(); if(progress.get_cancel()) return; @@ -263,7 +269,52 @@ void BVH::pack_triangle(int idx, float4 woop[3]) } } -void BVH::pack_triangles() +/* Curves*/ + +void BVH::pack_curve_segment(int idx, float4 woop[3]) +{ + int tob = pack.prim_object[idx]; + const Mesh *mesh = objects[tob]->mesh; + int tidx = pack.prim_index[idx]; + int segment = pack.prim_segment[idx]; + int k0 = mesh->curves[tidx].first_key + segment; + int k1 = mesh->curves[tidx].first_key + segment + 1; + float3 v0 = mesh->curve_keys[k0].co; + float3 v1 = mesh->curve_keys[k1].co; + + float3 d0 = v1 - v0; + float l = len(d0); + + /*Plan + *Transform tfm = make_transform( + * location <3> , l, + * extra curve data <3> , StrID, + * nextkey, flags/tip?, 0, 0); + */ + Attribute *attr_tangent = mesh->curve_attributes.find(ATTR_STD_CURVE_TANGENT); + float3 tg0 = make_float3(1.0f, 0.0f, 0.0f); + float3 tg1 = make_float3(1.0f, 0.0f, 0.0f); + + if(attr_tangent) { + const float3 *data_tangent = attr_tangent->data_float3(); + + tg0 = data_tangent[k0]; + tg1 = data_tangent[k1]; + } + + Transform tfm = make_transform( + tg0.x, tg0.y, tg0.z, l, + tg1.x, tg1.y, tg1.z, 0, + 0, 0, 0, 0, + 0, 0, 0, 1); + + woop[0] = tfm.x; + woop[1] = tfm.y; + woop[2] = tfm.z; + +} + +void BVH::pack_primitives() { int nsize = TRI_NODE_SIZE; size_t tidx_size = pack.prim_index.size(); @@ -277,7 +328,11 @@ void BVH::pack_triangles() if(pack.prim_index[i] != -1) { float4 woop[3]; - pack_triangle(i, woop); + if(pack.prim_segment[i] != ~0) + pack_curve_segment(i, woop); + else + pack_triangle(i, woop); + memcpy(&pack.tri_woop[i * nsize], woop, sizeof(float4)*3); int tob = pack.prim_object[i]; @@ -300,11 +355,15 @@ void BVH::pack_instances(size_t nodes_size) /* adjust primitive index to point to the triangle in the global array, for * meshes with transform applied and already in the top level BVH */ for(size_t i = 0; i < pack.prim_index.size(); i++) - if(pack.prim_index[i] != -1) - pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset; + if(pack.prim_index[i] != -1) { + if(pack.prim_segment[i] != ~0) + pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->curve_offset; + else + pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset; + } /* track offsets of instanced BVH data in global array */ - size_t tri_offset = pack.prim_index.size(); + size_t prim_offset = pack.prim_index.size(); size_t nodes_offset = nodes_size; /* clear array that gives the node indexes for instanced objects */ @@ -339,6 +398,7 @@ void BVH::pack_instances(size_t nodes_size) mesh_map.clear(); pack.prim_index.resize(prim_index_size); + pack.prim_segment.resize(prim_index_size); pack.prim_object.resize(prim_index_size); pack.prim_visibility.resize(prim_index_size); pack.tri_woop.resize(tri_woop_size); @@ -346,6 +406,7 @@ void BVH::pack_instances(size_t nodes_size) pack.object_node.resize(objects.size()); int *pack_prim_index = (pack.prim_index.size())? &pack.prim_index[0]: NULL; + int *pack_prim_segment = (pack.prim_segment.size())? &pack.prim_segment[0]: NULL; int *pack_prim_object = (pack.prim_object.size())? &pack.prim_object[0]: NULL; uint *pack_prim_visibility = (pack.prim_visibility.size())? &pack.prim_visibility[0]: NULL; float4 *pack_tri_woop = (pack.tri_woop.size())? &pack.tri_woop[0]: NULL; @@ -376,6 +437,7 @@ void BVH::pack_instances(size_t nodes_size) int noffset = nodes_offset/nsize; int mesh_tri_offset = mesh->tri_offset; + int mesh_curve_offset = mesh->curve_offset; /* fill in node indexes for instances */ if((bvh->pack.is_leaf.size() != 0) && bvh->pack.is_leaf[0]) @@ -389,10 +451,16 @@ void BVH::pack_instances(size_t nodes_size) if(bvh->pack.prim_index.size()) { size_t bvh_prim_index_size = bvh->pack.prim_index.size(); int *bvh_prim_index = &bvh->pack.prim_index[0]; + int *bvh_prim_segment = &bvh->pack.prim_segment[0]; uint *bvh_prim_visibility = &bvh->pack.prim_visibility[0]; for(size_t i = 0; i < bvh_prim_index_size; i++) { - pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset; + if(bvh->pack.prim_segment[i] != ~0) + pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_curve_offset; + else + pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset; + + pack_prim_segment[pack_prim_index_offset] = bvh_prim_segment[i]; pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i]; pack_prim_object[pack_prim_index_offset] = 0; // unused for instances pack_prim_index_offset++; @@ -401,7 +469,7 @@ void BVH::pack_instances(size_t nodes_size) /* merge triangle intersection data */ if(bvh->pack.tri_woop.size()) { - memcpy(pack_tri_woop+pack_tri_woop_offset, &bvh->pack.tri_woop[0], + memcpy(pack_tri_woop + pack_tri_woop_offset, &bvh->pack.tri_woop[0], bvh->pack.tri_woop.size()*sizeof(float4)); pack_tri_woop_offset += bvh->pack.tri_woop.size(); } @@ -420,8 +488,8 @@ void BVH::pack_instances(size_t nodes_size) int4 data = bvh_nodes[i + nsize_bbox]; if(bvh_is_leaf && bvh_is_leaf[j]) { - data.x += tri_offset; - data.y += tri_offset; + data.x += prim_offset; + data.y += prim_offset; } else { data.x += (data.x < 0)? -noffset: noffset; @@ -443,7 +511,7 @@ void BVH::pack_instances(size_t nodes_size) } nodes_offset += bvh->pack.nodes.size(); - tri_offset += bvh->pack.prim_index.size(); + prim_offset += bvh->pack.prim_index.size(); } } @@ -544,25 +612,38 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility if(leaf) { /* refit leaf node */ - for(int tri = c0; tri < c1; tri++) { - int tidx = pack.prim_index[tri]; - int tob = pack.prim_object[tri]; + for(int prim = c0; prim < c1; prim++) { + int pidx = pack.prim_index[prim]; + int tob = pack.prim_object[prim]; Object *ob = objects[tob]; - if(tidx == -1) { + if(pidx == -1) { /* object instance */ bbox.grow(ob->bounds); } else { - /* triangles */ + /* primitives */ const Mesh *mesh = ob->mesh; - int tri_offset = (params.top_level)? mesh->tri_offset: 0; - const int *vidx = mesh->triangles[tidx - tri_offset].v; - const float3 *vpos = &mesh->verts[0]; - bbox.grow(vpos[vidx[0]]); - bbox.grow(vpos[vidx[1]]); - bbox.grow(vpos[vidx[2]]); + if(pack.prim_segment[prim] != ~0) { + /* curves */ + int str_offset = (params.top_level)? mesh->curve_offset: 0; + int k0 = mesh->curves[pidx - str_offset].first_key + pack.prim_segment[prim]; // XXX! + int k1 = k0 + 1; + + bbox.grow(mesh->curve_keys[k0].co, mesh->curve_keys[k0].radius); + bbox.grow(mesh->curve_keys[k1].co, mesh->curve_keys[k1].radius); + } + else { + /* triangles */ + int tri_offset = (params.top_level)? mesh->tri_offset: 0; + const int *vidx = mesh->triangles[pidx - tri_offset].v; + const float3 *vpos = &mesh->verts[0]; + + bbox.grow(vpos[vidx[0]]); + bbox.grow(vpos[vidx[1]]); + bbox.grow(vpos[vidx[2]]); + } } visibility |= ob->visibility; diff --git a/intern/cycles/bvh/bvh.h b/intern/cycles/bvh/bvh.h index 549f1e3ac1d..00c146143b8 100644 --- a/intern/cycles/bvh/bvh.h +++ b/intern/cycles/bvh/bvh.h @@ -51,7 +51,9 @@ struct PackedBVH { /* object index to BVH node index mapping for instances */ array<int> object_node; /* precomputed triangle intersection data, one triangle is 4x float4 */ - array<float4> tri_woop; + array<float4> tri_woop; + /* primitive type - triangle or strand (should be moved to flag?) */ + array<int> prim_segment; /* visibility visibilitys for primitives */ array<uint> prim_visibility; /* mapping from BVH primitive index to true primitive index, as primitives @@ -101,9 +103,10 @@ protected: bool cache_read(CacheData& key); void cache_write(CacheData& key); - /* triangles */ - void pack_triangles(); + /* triangles and strands*/ + void pack_primitives(); void pack_triangle(int idx, float4 woop[3]); + void pack_curve_segment(int idx, float4 woop[3]); /* merge instance BVH's */ void pack_instances(size_t nodes_size); diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index 705b805a3a9..38fb1a15a13 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -48,9 +48,10 @@ public: /* Constructor / Destructor */ BVHBuild::BVHBuild(const vector<Object*>& objects_, - vector<int>& prim_index_, vector<int>& prim_object_, + vector<int>& prim_segment_, vector<int>& prim_index_, vector<int>& prim_object_, const BVHParams& params_, Progress& progress_) : objects(objects_), + prim_segment(prim_segment_), prim_index(prim_index_), prim_object(prim_object_), params(params_), @@ -73,25 +74,55 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, BoundBox bounds = BoundBox::empty; for(int k = 0; k < 3; k++) { - float3 pt = mesh->verts[t.v[k]]; - bounds.grow(pt); + float3 co = mesh->verts[t.v[k]]; + bounds.grow(co); } if(bounds.valid()) { - references.push_back(BVHReference(bounds, j, i)); + references.push_back(BVHReference(bounds, j, i, ~0)); root.grow(bounds); center.grow(bounds.center2()); } } + + for(uint j = 0; j < mesh->curves.size(); j++) { + Mesh::Curve curve = mesh->curves[j]; + + for(int k = 0; k < curve.num_keys - 1; k++) { + BoundBox bounds = BoundBox::empty; + + float3 co0 = mesh->curve_keys[curve.first_key + k].co; + float3 co1 = mesh->curve_keys[curve.first_key + k + 1].co; + + bounds.grow(co0, mesh->curve_keys[curve.first_key + k].radius); + bounds.grow(co1, mesh->curve_keys[curve.first_key + k + 1].radius); + + if(bounds.valid()) { + references.push_back(BVHReference(bounds, j, i, k)); + root.grow(bounds); + center.grow(bounds.center2()); + } + } + } } void BVHBuild::add_reference_object(BoundBox& root, BoundBox& center, Object *ob, int i) { - references.push_back(BVHReference(ob->bounds, -1, i)); + references.push_back(BVHReference(ob->bounds, -1, i, false)); root.grow(ob->bounds); center.grow(ob->bounds.center2()); } +static size_t count_curve_segments(Mesh *mesh) +{ + size_t num = 0, num_curves = mesh->curves.size(); + + for(size_t i = 0; i < num_curves; i++) + num += mesh->curves[i].num_keys - 1; + + return num; +} + void BVHBuild::add_references(BVHRange& root) { /* reserve space for references */ @@ -99,13 +130,17 @@ void BVHBuild::add_references(BVHRange& root) foreach(Object *ob, objects) { if(params.top_level) { - if(ob->mesh->transform_applied) + if(ob->mesh->transform_applied) { num_alloc_references += ob->mesh->triangles.size(); + num_alloc_references += count_curve_segments(ob->mesh); + } else num_alloc_references++; } - else + else { num_alloc_references += ob->mesh->triangles.size(); + num_alloc_references += count_curve_segments(ob->mesh); + } } references.reserve(num_alloc_references); @@ -162,6 +197,7 @@ BVHNode* BVHBuild::run() progress_total = references.size(); progress_original_total = progress_total; + prim_segment.resize(references.size()); prim_index.resize(references.size()); prim_object.resize(references.size()); @@ -319,10 +355,12 @@ BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start, if(start == prim_index.size()) { assert(params.use_spatial_split); + prim_segment.push_back(ref->prim_segment()); prim_index.push_back(ref->prim_index()); prim_object.push_back(ref->prim_object()); } else { + prim_segment[start] = ref->prim_segment(); prim_index[start] = ref->prim_index(); prim_object[start] = ref->prim_object(); } @@ -345,6 +383,7 @@ BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start, BVHNode* BVHBuild::create_leaf_node(const BVHRange& range) { + vector<int>& p_segment = prim_segment; vector<int>& p_index = prim_index; vector<int>& p_object = prim_object; BoundBox bounds = BoundBox::empty; @@ -358,10 +397,12 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range) if(range.start() + num == prim_index.size()) { assert(params.use_spatial_split); + p_segment.push_back(ref.prim_segment()); p_index.push_back(ref.prim_index()); p_object.push_back(ref.prim_object()); } else { + p_segment[range.start() + num] = ref.prim_segment(); p_index[range.start() + num] = ref.prim_index(); p_object[range.start() + num] = ref.prim_object(); } diff --git a/intern/cycles/bvh/bvh_build.h b/intern/cycles/bvh/bvh_build.h index 44ef918b326..3df4da1739a 100644 --- a/intern/cycles/bvh/bvh_build.h +++ b/intern/cycles/bvh/bvh_build.h @@ -44,6 +44,7 @@ public: /* Constructor/Destructor */ BVHBuild( const vector<Object*>& objects, + vector<int>& prim_segment, vector<int>& prim_index, vector<int>& prim_object, const BVHParams& params, @@ -87,6 +88,7 @@ protected: int num_original_references; /* output primitive indexes and objects */ + vector<int>& prim_segment; vector<int>& prim_index; vector<int>& prim_object; diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h index a78496d841d..f7bc79f71e6 100644 --- a/intern/cycles/bvh/bvh_params.h +++ b/intern/cycles/bvh/bvh_params.h @@ -98,19 +98,22 @@ class BVHReference public: __forceinline BVHReference() {} - __forceinline BVHReference(const BoundBox& bounds_, int prim_index_, int prim_object_) + __forceinline BVHReference(const BoundBox& bounds_, int prim_index_, int prim_object_, int prim_segment) : rbounds(bounds_) { rbounds.min.w = __int_as_float(prim_index_); rbounds.max.w = __int_as_float(prim_object_); + segment = prim_segment; } __forceinline const BoundBox& bounds() const { return rbounds; } __forceinline int prim_index() const { return __float_as_int(rbounds.min.w); } __forceinline int prim_object() const { return __float_as_int(rbounds.max.w); } + __forceinline int prim_segment() const { return segment; } protected: BoundBox rbounds; + uint segment; }; /* BVH Range diff --git a/intern/cycles/bvh/bvh_sort.cpp b/intern/cycles/bvh/bvh_sort.cpp index bef384be592..91994be5b96 100644 --- a/intern/cycles/bvh/bvh_sort.cpp +++ b/intern/cycles/bvh/bvh_sort.cpp @@ -43,6 +43,8 @@ public: else if(ra.prim_object() > rb.prim_object()) return false; else if(ra.prim_index() < rb.prim_index()) return true; else if(ra.prim_index() > rb.prim_index()) return false; + else if(ra.prim_segment() < rb.prim_segment()) return true; + else if(ra.prim_segment() > rb.prim_segment()) return false; return false; } diff --git a/intern/cycles/bvh/bvh_split.cpp b/intern/cycles/bvh/bvh_split.cpp index 263c5834428..03ff69d7b6d 100644 --- a/intern/cycles/bvh/bvh_split.cpp +++ b/intern/cycles/bvh/bvh_split.cpp @@ -252,14 +252,41 @@ void BVHSpatialSplit::split_reference(BVHBuild *builder, BVHReference& left, BVH /* loop over vertices/edges. */ Object *ob = builder->objects[ref.prim_object()]; const Mesh *mesh = ob->mesh; - const int *inds = mesh->triangles[ref.prim_index()].v; - const float3 *verts = &mesh->verts[0]; - const float3* v1 = &verts[inds[2]]; - - for(int i = 0; i < 3; i++) { - const float3* v0 = v1; - int vindex = inds[i]; - v1 = &verts[vindex]; + + if (ref.prim_segment() == ~0) { + const int *inds = mesh->triangles[ref.prim_index()].v; + const float3 *verts = &mesh->verts[0]; + const float3* v1 = &verts[inds[2]]; + + for(int i = 0; i < 3; i++) { + const float3* v0 = v1; + int vindex = inds[i]; + v1 = &verts[vindex]; + float v0p = (*v0)[dim]; + float v1p = (*v1)[dim]; + + /* insert vertex to the boxes it belongs to. */ + if(v0p <= pos) + left_bounds.grow(*v0); + + if(v0p >= pos) + right_bounds.grow(*v0); + + /* edge intersects the plane => insert intersection to both boxes. */ + if((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) { + float3 t = lerp(*v0, *v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f)); + left_bounds.grow(t); + right_bounds.grow(t); + } + } + } + else { + /* curve split: NOTE - Currently ignores curve width and needs to be fixed.*/ + const int k0 = mesh->curves[ref.prim_index()].first_key + ref.prim_segment(); + const int k1 = k0 + 1; + const float3* v0 = &mesh->curve_keys[k0].co; + const float3* v1 = &mesh->curve_keys[k1].co; + float v0p = (*v0)[dim]; float v1p = (*v1)[dim]; @@ -270,6 +297,12 @@ void BVHSpatialSplit::split_reference(BVHBuild *builder, BVHReference& left, BVH if(v0p >= pos) right_bounds.grow(*v0); + if(v1p <= pos) + left_bounds.grow(*v1); + + if(v1p >= pos) + right_bounds.grow(*v1); + /* edge intersects the plane => insert intersection to both boxes. */ if((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) { float3 t = lerp(*v0, *v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f)); @@ -284,9 +317,9 @@ void BVHSpatialSplit::split_reference(BVHBuild *builder, BVHReference& left, BVH left_bounds.intersect(ref.bounds()); right_bounds.intersect(ref.bounds()); - /* set referecnes */ - left = BVHReference(left_bounds, ref.prim_index(), ref.prim_object()); - right = BVHReference(right_bounds, ref.prim_index(), ref.prim_object()); + /* set references */ + left = BVHReference(left_bounds, ref.prim_index(), ref.prim_object(), ref.prim_segment()); + right = BVHReference(right_bounds, ref.prim_index(), ref.prim_object(), ref.prim_segment()); } CCL_NAMESPACE_END diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index 9840687b76a..7b31b9ba157 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -84,6 +84,7 @@ public: /* info */ DeviceInfo info; virtual const string& error_message() { return error_msg; } + bool have_error() { return !error_message().empty(); } /* statistics */ Stats &stats; diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index 14f8cfa8767..040f3044457 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -124,7 +124,7 @@ public: if(error_msg == "") \ error_msg = message; \ fprintf(stderr, "%s\n", message.c_str()); \ - cuda_abort(); \ + /*cuda_abort();*/ \ } \ } @@ -326,7 +326,8 @@ public: void mem_copy_to(device_memory& mem) { cuda_push_context(); - cuda_assert(cuMemcpyHtoD(cuda_device_ptr(mem.device_pointer), (void*)mem.data_pointer, mem.memory_size())) + if(mem.device_pointer) + cuda_assert(cuMemcpyHtoD(cuda_device_ptr(mem.device_pointer), (void*)mem.data_pointer, mem.memory_size())) cuda_pop_context(); } @@ -336,8 +337,13 @@ public: size_t size = elem*w*h; cuda_push_context(); - cuda_assert(cuMemcpyDtoH((uchar*)mem.data_pointer + offset, - (CUdeviceptr)((uchar*)mem.device_pointer + offset), size)) + if(mem.device_pointer) { + cuda_assert(cuMemcpyDtoH((uchar*)mem.data_pointer + offset, + (CUdeviceptr)((uchar*)mem.device_pointer + offset), size)) + } + else { + memset((char*)mem.data_pointer + offset, 0, size); + } cuda_pop_context(); } @@ -346,7 +352,8 @@ public: memset((void*)mem.data_pointer, 0, mem.memory_size()); cuda_push_context(); - cuda_assert(cuMemsetD8(cuda_device_ptr(mem.device_pointer), 0, mem.memory_size())) + if(mem.device_pointer) + cuda_assert(cuMemsetD8(cuda_device_ptr(mem.device_pointer), 0, mem.memory_size())) cuda_pop_context(); } @@ -390,13 +397,18 @@ public: default: assert(0); return; } - CUtexref texref; + CUtexref texref = NULL; cuda_push_context(); cuda_assert(cuModuleGetTexRef(&texref, cuModule, name)) + if(!texref) { + cuda_pop_context(); + return; + } + if(interpolation) { - CUarray handle; + CUarray handle = NULL; CUDA_ARRAY_DESCRIPTOR desc; desc.Width = mem.data_width; @@ -406,6 +418,11 @@ public: cuda_assert(cuArrayCreate(&handle, &desc)) + if(!handle) { + cuda_pop_context(); + return; + } + if(mem.data_height > 1) { CUDA_MEMCPY2D param; memset(¶m, 0, sizeof(param)); @@ -481,6 +498,9 @@ public: void path_trace(RenderTile& rtile, int sample) { + if(have_error()) + return; + cuda_push_context(); CUfunction cuPathTrace; @@ -546,6 +566,9 @@ public: void tonemap(DeviceTask& task, device_ptr buffer, device_ptr rgba) { + if(have_error()) + return; + cuda_push_context(); CUfunction cuFilmConvert; @@ -615,6 +638,9 @@ public: void shader(DeviceTask& task) { + if(have_error()) + return; + cuda_push_context(); CUfunction cuDisplace; diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index fde881c0a06..6d5b9a063a0 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -20,12 +20,12 @@ set(SRC set(SRC_HEADERS kernel.h kernel_accumulate.h - kernel_attribute.h kernel_bvh.h kernel_camera.h kernel_compat_cpu.h kernel_compat_cuda.h kernel_compat_opencl.h + kernel_curve.h kernel_differential.h kernel_displace.h kernel_emission.h @@ -37,6 +37,7 @@ set(SRC_HEADERS kernel_object.h kernel_passes.h kernel_path.h + kernel_primitive.h kernel_projection.h kernel_random.h kernel_shader.h diff --git a/intern/cycles/kernel/kernel_attribute.h b/intern/cycles/kernel/kernel_attribute.h deleted file mode 100644 index b7ad731c883..00000000000 --- a/intern/cycles/kernel/kernel_attribute.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __KERNEL_ATTRIBUTE_CL__ -#define __KERNEL_ATTRIBUTE_CL__ - -CCL_NAMESPACE_BEGIN - -/* note: declared in kernel.h, have to add it here because kernel.h is not available */ -bool kernel_osl_use(KernelGlobals *kg); - -__device_inline int find_attribute(KernelGlobals *kg, ShaderData *sd, uint id) -{ -#ifdef __OSL__ - if (kg->osl) { - return OSLShader::find_attribute(kg, sd, id); - } - else -#endif - { - /* for SVM, 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) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z; - } -} - -CCL_NAMESPACE_END - -#endif /* __KERNEL_ATTRIBUTE_CL__ */ diff --git a/intern/cycles/kernel/kernel_bvh.h b/intern/cycles/kernel/kernel_bvh.h index d70485fd6cf..2cb29207b05 100644 --- a/intern/cycles/kernel/kernel_bvh.h +++ b/intern/cycles/kernel/kernel_bvh.h @@ -205,6 +205,145 @@ __device_inline void bvh_triangle_intersect(KernelGlobals *kg, Intersection *ise } } +#ifdef __HAIR__ +__device_inline void bvh_curve_intersect(KernelGlobals *kg, Intersection *isect, + float3 P, float3 idir, uint visibility, int object, int curveAddr, int segment) +{ + /* curve Intersection check */ + + int flags = kernel_data.curve_kernel_data.curveflags; + + int prim = kernel_tex_fetch(__prim_index, curveAddr); + float4 v00 = kernel_tex_fetch(__curves, prim); + + int k0 = __float_as_int(v00.x) + segment; + int k1 = k0 + 1; + + float4 P1 = kernel_tex_fetch(__curve_keys, k0); + float4 P2 = kernel_tex_fetch(__curve_keys, k1); + + float l = len(P2 - P1); + float r1 = P1.w; + float r2 = P2.w; + float mr = max(r1,r2); + float3 p1 = float4_to_float3(P1); + float3 p2 = float4_to_float3(P2); + float3 dif = P - p1; + float3 dir = 1.0f/idir; + + float sp_r = mr + 0.5f * l; + float3 sphere_dif = P - ((p1 + p2) * 0.5f); + float sphere_b = dot(dir,sphere_dif); + sphere_dif = sphere_dif - sphere_b * dir; + sphere_b = dot(dir,sphere_dif); + float sdisc = sphere_b * sphere_b - len_squared(sphere_dif) + sp_r * sp_r; + if(sdisc < 0.0f) + return; + + /* obtain parameters and test midpoint distance for suitable modes*/ + float3 tg = (p2 - p1) / l; + float gd = (r2 - r1) / l; + float dirz = dot(dir,tg); + float difz = dot(dif,tg); + + float a = 1.0f - (dirz*dirz*(1 + gd*gd)); + float halfb = (dot(dir,dif) - dirz*(difz + gd*(difz*gd + r1))); + + float tcentre = -halfb/a; + float zcentre = difz + (dirz * tcentre); + + if((tcentre > isect->t) && !(flags & CURVE_KN_ACCURATE)) + return; + if((zcentre < 0 || zcentre > l) && !(flags & CURVE_KN_ACCURATE) && !(flags & CURVE_KN_INTERSECTCORRECTION)) + return; + + /* test minimum separation*/ + float3 cprod = cross(tg, dir); + float3 cprod2 = cross(tg, dif); + float cprodsq = len_squared(cprod); + float cprod2sq = len_squared(cprod2); + float distscaled = dot(cprod,dif); + + if(cprodsq == 0) + distscaled = cprod2sq; + else + distscaled = (distscaled*distscaled)/cprodsq; + + if(distscaled > mr*mr) + return; + + /* calculate true intersection*/ + float3 tdif = P - p1 + tcentre * dir; + float tdifz = dot(tdif,tg); + float tb = 2*(dot(dir,tdif) - dirz*(tdifz + gd*(tdifz*gd + r1))); + float tc = dot(tdif,tdif) - tdifz * tdifz * (1 + gd*gd) - r1*r1 - 2*r1*tdifz*gd; + float td = tb*tb - 4*a*tc; + + if (td < 0.0f) + return; + + float rootd = 0.0f; + float correction = 0.0f; + if(flags & CURVE_KN_ACCURATE) { + rootd = sqrtf(td); + correction = ((-tb - rootd)/(2*a)); + } + + float t = tcentre + correction; + + if(t < isect->t) { + + if(flags & CURVE_KN_INTERSECTCORRECTION) { + rootd = sqrtf(td); + correction = ((-tb - rootd)/(2*a)); + t = tcentre + correction; + } + + float z = zcentre + (dirz * correction); + bool backface = false; + + if(flags & CURVE_KN_BACKFACING && (t < 0.0f || z < 0 || z > l)) { + backface = true; + correction = ((-tb + rootd)/(2*a)); + t = tcentre + correction; + z = zcentre + (dirz * correction); + } + + if(t > 0.0f && t < isect->t && z >= 0 && z <= l) { + + if (flags & CURVE_KN_ENCLOSEFILTER) { + + float enc_ratio = kernel_data.curve_kernel_data.encasing_ratio; + if((dot(P - p1, tg) > -r1 * enc_ratio) && (dot(P - p2, tg) < r2 * enc_ratio)) { + float a2 = 1.0f - (dirz*dirz*(1 + gd*gd*enc_ratio*enc_ratio)); + float c2 = dot(dif,dif) - difz * difz * (1 + gd*gd*enc_ratio*enc_ratio) - r1*r1*enc_ratio*enc_ratio - 2*r1*difz*gd*enc_ratio; + if(a2*c2 < 0.0f) + return; + } + } + +#ifdef __VISIBILITY_FLAG__ + /* visibility flag test. we do it here under the assumption + * that most triangles are culled by node flags */ + if(kernel_tex_fetch(__prim_visibility, curveAddr) & visibility) +#endif + { + /* record intersection */ + isect->prim = curveAddr; + isect->segment = segment; + isect->object = object; + isect->u = z/l; + isect->v = td/(4*a*a); + isect->t = t; + + if(backface) + isect->u = -isect->u; + } + } + } +} +#endif + __device_inline bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect) { /* traversal stack in CUDA thread-local memory */ @@ -281,10 +420,16 @@ __device_inline bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint nodeAddr = traversalStack[stackPtr]; --stackPtr; - /* triangle intersection */ + /* primitive intersection */ while(primAddr < primAddr2) { - /* intersect ray against triangle */ - bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr); + /* intersect ray against primitive */ +#ifdef __HAIR__ + uint segment = kernel_tex_fetch(__prim_segment, primAddr); + if(segment != ~0) + bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment); + else +#endif + bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr); /* shadow ray early termination */ if(visibility == PATH_RAY_SHADOW_OPAQUE && isect->prim != ~0) @@ -401,10 +546,16 @@ __device_inline bool bvh_intersect_motion(KernelGlobals *kg, const Ray *ray, con nodeAddr = traversalStack[stackPtr]; --stackPtr; - /* triangle intersection */ + /* primitive intersection */ while(primAddr < primAddr2) { - /* intersect ray against triangle */ - bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr); + /* intersect ray against primitive */ +#ifdef __HAIR__ + uint segment = kernel_tex_fetch(__prim_segment, primAddr); + if(segment != ~0) + bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment); + else +#endif + bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr); /* shadow ray early termination */ if(visibility == PATH_RAY_SHADOW_OPAQUE && isect->prim != ~0) @@ -457,12 +608,15 @@ __device_inline float3 ray_offset(float3 P, float3 Ng) { #ifdef __INTERSECTION_REFINE__ const float epsilon_f = 1e-5f; + /* ideally this should match epsilon_f, but instancing/mblur + * precision makes it problematic */ + const float epsilon_test = 1e-1f; const int epsilon_i = 32; float3 res; /* x component */ - if(fabsf(P.x) < epsilon_f) { + if(fabsf(P.x) < epsilon_test) { res.x = P.x + Ng.x*epsilon_f; } else { @@ -472,7 +626,7 @@ __device_inline float3 ray_offset(float3 P, float3 Ng) } /* y component */ - if(fabsf(P.y) < epsilon_f) { + if(fabsf(P.y) < epsilon_test) { res.y = P.y + Ng.y*epsilon_f; } else { @@ -482,7 +636,7 @@ __device_inline float3 ray_offset(float3 P, float3 Ng) } /* z component */ - if(fabsf(P.z) < epsilon_f) { + if(fabsf(P.z) < epsilon_test) { res.z = P.z + Ng.z*epsilon_f; } else { @@ -542,5 +696,105 @@ __device_inline float3 bvh_triangle_refine(KernelGlobals *kg, ShaderData *sd, co #endif } +#ifdef __HAIR__ +__device_inline float3 bvh_curve_refine(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray, float t) +{ + int flag = kernel_data.curve_kernel_data.curveflags; + float3 P = ray->P; + float3 D = ray->D; + + if(isect->object != ~0) { +#ifdef __OBJECT_MOTION__ + Transform tfm = sd->ob_itfm; +#else + Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM); +#endif + + P = transform_point(&tfm, P); + D = transform_direction(&tfm, D*t); + D = normalize_len(D, &t); + } + + int prim = kernel_tex_fetch(__prim_index, isect->prim); + float4 v00 = kernel_tex_fetch(__curves, prim); + + int k0 = __float_as_int(v00.x) + isect->segment; + int k1 = k0 + 1; + + float4 P1 = kernel_tex_fetch(__curve_keys, k0); + float4 P2 = kernel_tex_fetch(__curve_keys, k1); + float l = len(P2 - P1); + float r1 = P1.w; + float r2 = P2.w; + float3 tg = float4_to_float3(P2 - P1) / l; + float3 dif = P - float4_to_float3(P1) + t * D; + float gd = ((r2 - r1)/l); + + P = P + D*t; + + dif = P - float4_to_float3(P1); + + #ifdef __UV__ + sd->u = dot(dif,tg)/l; + sd->v = 0.0f; + #endif + + if (flag & CURVE_KN_TRUETANGENTGNORMAL) { + sd->Ng = -(D - tg * (dot(tg,D) * kernel_data.curve_kernel_data.normalmix)); + sd->Ng = normalize(sd->Ng); + if (flag & CURVE_KN_NORMALCORRECTION) + { + //sd->Ng = normalize(sd->Ng); + sd->Ng = sd->Ng - gd * tg; + sd->Ng = normalize(sd->Ng); + } + } + else { + sd->Ng = (dif - tg * sd->u * l) / (P1.w + sd->u * l * gd); + if (gd != 0.0f) { + sd->Ng = sd->Ng - gd * tg ; + sd->Ng = normalize(sd->Ng); + } + } + + sd->N = sd->Ng; + + if (flag & CURVE_KN_TANGENTGNORMAL && !(flag & CURVE_KN_TRUETANGENTGNORMAL)) { + sd->N = -(D - tg * (dot(tg,D) * kernel_data.curve_kernel_data.normalmix)); + sd->N = normalize(sd->N); + if (flag & CURVE_KN_NORMALCORRECTION) { + //sd->N = normalize(sd->N); + sd->N = sd->N - gd * tg; + sd->N = normalize(sd->N); + } + } + if (!(flag & CURVE_KN_TANGENTGNORMAL) && flag & CURVE_KN_TRUETANGENTGNORMAL) { + sd->N = (dif - tg * sd->u * l) / (P1.w + sd->u * l * gd); + if (gd != 0.0f) { + sd->N = sd->N - gd * tg ; + sd->N = normalize(sd->N); + } + } + + #ifdef __DPDU__ + /* dPdu/dPdv */ + sd->dPdu = tg; + sd->dPdv = cross(tg,sd->Ng); + #endif + + if(isect->object != ~0) { +#ifdef __OBJECT_MOTION__ + Transform tfm = sd->ob_tfm; +#else + Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM); +#endif + + P = transform_point(&tfm, P); + } + + return P; +} +#endif + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_curve.h b/intern/cycles/kernel/kernel_curve.h new file mode 100644 index 00000000000..e065717888c --- /dev/null +++ b/intern/cycles/kernel/kernel_curve.h @@ -0,0 +1,141 @@ +/* + * Copyright 2011, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +CCL_NAMESPACE_BEGIN + +#ifdef __HAIR__ + +/* curve attributes */ + +__device float curve_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy) +{ + if(elem == ATTR_ELEMENT_CURVE) { +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = 0.0f; + if(dy) *dy = 0.0f; +#endif + + return kernel_tex_fetch(__attributes_float, offset + sd->prim); + } + else if(elem == ATTR_ELEMENT_CURVE_KEY) { + float4 curvedata = kernel_tex_fetch(__curves, sd->prim); + int k0 = __float_as_int(curvedata.x) + sd->segment; + int k1 = k0 + 1; + + float f0 = kernel_tex_fetch(__attributes_float, offset + k0); + float f1 = kernel_tex_fetch(__attributes_float, offset + k1); + +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = sd->du.dx*(f1 - f0); + if(dy) *dy = 0.0f; +#endif + + return (1.0f - sd->u)*f0 + sd->u*f1; + } + else { +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = 0.0f; + if(dy) *dy = 0.0f; +#endif + + return 0.0f; + } +} + +__device float3 curve_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy) +{ + if(elem == ATTR_ELEMENT_CURVE) { + /* idea: we can't derive any useful differentials here, but for tiled + * mipmap image caching it would be useful to avoid reading the highest + * detail level always. maybe a derivative based on the hair density + * could be computed somehow? */ +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f); + if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f); +#endif + + return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + sd->prim)); + } + else if(elem == ATTR_ELEMENT_CURVE_KEY) { + float4 curvedata = kernel_tex_fetch(__curves, sd->prim); + int k0 = __float_as_int(curvedata.x) + sd->segment; + int k1 = k0 + 1; + + float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + k0)); + float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + k1)); + +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = sd->du.dx*(f1 - f0); + if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f); +#endif + + return (1.0f - sd->u)*f0 + sd->u*f1; + } + else { +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f); + if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f); +#endif + + return make_float3(0.0f, 0.0f, 0.0f); + } +} + +/* hair info node functions */ + +__device float curve_thickness(KernelGlobals *kg, ShaderData *sd) +{ + float r = 0.0f; + + if(sd->segment != ~0) { + float4 curvedata = kernel_tex_fetch(__curves, sd->prim); + int k0 = __float_as_int(curvedata.x) + sd->segment; + int k1 = k0 + 1; + + float4 P1 = kernel_tex_fetch(__curve_keys, k0); + float4 P2 = kernel_tex_fetch(__curve_keys, k1); + r = (P2.w - P1.w) * sd->u + P1.w; + } + + return r*2.0f; +} + +__device float3 curve_tangent_normal(KernelGlobals *kg, ShaderData *sd) +{ + float3 tgN = make_float3(0.0f,0.0f,0.0f); + + if(sd->segment != ~0) { + float normalmix = kernel_data.curve_kernel_data.normalmix; + + tgN = -(-sd->I - sd->dPdu * (dot(sd->dPdu,-sd->I) * normalmix / len_squared(sd->dPdu))); + tgN = normalize(tgN); + + /* need to find suitable scaled gd for corrected normal */ +#if 0 + if (kernel_data.curve_kernel_data.use_tangent_normal_correction) + tgN = normalize(tgN - gd * sd->dPdu); +#endif + } + + return tgN; +} + +#endif + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h index e56633c9358..d5506ad1dd0 100644 --- a/intern/cycles/kernel/kernel_emission.h +++ b/intern/cycles/kernel/kernel_emission.h @@ -47,7 +47,13 @@ __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, t, time); +#ifdef __HAIR__ + if(ls->type == LIGHT_STRAND) + shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time, ls->prim); + else +#endif + shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time); + ls->Ng = sd.Ng; /* no path flag, we're evaluating this for all closures. that's weak but @@ -150,7 +156,11 @@ __device float3 indirect_emission(KernelGlobals *kg, ShaderData *sd, float t, in /* evaluate emissive closure */ float3 L = shader_emissive_eval(kg, sd); +#ifdef __HAIR__ + if(!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_SAMPLE_AS_LIGHT) && (sd->segment == ~0)) { +#else if(!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_SAMPLE_AS_LIGHT)) { +#endif /* multiple importance sampling, get triangle light pdf, * and compute weight with respect to BSDF pdf */ float pdf = triangle_light_pdf(kg, sd->Ng, sd->I, t); diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h index 97ae2d3db87..ea0e4d014fe 100644 --- a/intern/cycles/kernel/kernel_light.h +++ b/intern/cycles/kernel/kernel_light.h @@ -326,6 +326,61 @@ __device float triangle_light_pdf(KernelGlobals *kg, return (t*t*kernel_data.integrator.pdf_triangles)/cos_pi; } +#ifdef __HAIR__ +/* Strand Light */ + +__device void curve_segment_light_sample(KernelGlobals *kg, int prim, int object, + int segment, float randu, float randv, float time, LightSample *ls) +{ + /* this strand code needs completion */ + float4 v00 = kernel_tex_fetch(__curves, prim); + + int k0 = __float_as_int(v00.x) + segment; + int k1 = k0 + 1; + + float4 P1 = kernel_tex_fetch(__curve_keys, k0); + float4 P2 = kernel_tex_fetch(__curve_keys, k1); + + float l = len(P2 - P1); + + float r1 = P1.w; + float r2 = P2.w; + float3 tg = float4_to_float3(P2 - P1) / l; + float3 xc = make_float3(tg.x * tg.z, tg.y * tg.z, -(tg.x * tg.x + tg.y * tg.y)); + if (dot(xc, xc) == 0.0f) + xc = make_float3(tg.x * tg.y, -(tg.x * tg.x + tg.z * tg.z), tg.z * tg.y); + xc = normalize(xc); + float3 yc = cross(tg, xc); + float gd = ((r2 - r1)/l); + + /* normal currently ignores gradient */ + ls->Ng = sinf(2 * M_PI_F * randv) * xc + cosf(2 * M_PI_F * randv) * yc; + ls->P = randu * l * tg + (gd * l + r1) * ls->Ng; + ls->object = object; + ls->prim = prim; + ls->t = 0.0f; + ls->type = LIGHT_STRAND; + ls->eval_fac = 1.0f; + ls->shader = __float_as_int(v00.z); + +#ifdef __INSTANCING__ + /* instance transform */ + if(ls->object >= 0) { +#ifdef __OBJECT_MOTION__ + Transform itfm; + Transform tfm = object_fetch_transform_motion_test(kg, object, time, &itfm); +#else + Transform tfm = object_fetch_transform(kg, ls->object, OBJECT_TRANSFORM); + Transform itfm = object_fetch_transform(kg, ls->object, OBJECT_INVERSE_TRANSFORM); +#endif + + ls->P = transform_point(&tfm, ls->P); + ls->Ng = normalize(transform_direction(&tfm, ls->Ng)); + } +#endif +} +#endif + /* Light Distribution */ __device int light_distribution_sample(KernelGlobals *kg, float randt) @@ -365,10 +420,19 @@ __device void light_sample(KernelGlobals *kg, float randt, float randu, float ra /* fetch light data */ float4 l = kernel_tex_fetch(__light_distribution, index); int prim = __float_as_int(l.y); +#ifdef __HAIR__ + int segment = __float_as_int(l.z); +#endif if(prim >= 0) { int object = __float_as_int(l.w); - triangle_light_sample(kg, prim, object, randu, randv, time, ls); + +#ifdef __HAIR__ + if (segment != ~0) + curve_segment_light_sample(kg, prim, object, segment, randu, randv, time, ls); + else +#endif + triangle_light_sample(kg, prim, object, randu, randv, time, ls); } else { int point = -prim-1; diff --git a/intern/cycles/kernel/kernel_passes.h b/intern/cycles/kernel/kernel_passes.h index 7f8b611ba14..727639386ed 100644 --- a/intern/cycles/kernel/kernel_passes.h +++ b/intern/cycles/kernel/kernel_passes.h @@ -70,11 +70,11 @@ __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 = triangle_uv(kg, sd); + float3 uv = primitive_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); + float4 speed = primitive_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); } diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 8da21751cbe..20feaf50a2e 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -24,9 +24,10 @@ #include "kernel_montecarlo.h" #include "kernel_projection.h" #include "kernel_object.h" -#include "kernel_attribute.h" -#include "kernel_projection.h" #include "kernel_triangle.h" +#include "kernel_curve.h" +#include "kernel_primitive.h" +#include "kernel_projection.h" #ifdef __QBVH__ #include "kernel_qbvh.h" #else diff --git a/intern/cycles/kernel/kernel_primitive.h b/intern/cycles/kernel/kernel_primitive.h new file mode 100644 index 00000000000..0851af21e87 --- /dev/null +++ b/intern/cycles/kernel/kernel_primitive.h @@ -0,0 +1,185 @@ +/* + * Copyright 2011, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __KERNEL_ATTRIBUTE_CL__ +#define __KERNEL_ATTRIBUTE_CL__ + +CCL_NAMESPACE_BEGIN + +/* attribute lookup */ + +__device_inline int find_attribute(KernelGlobals *kg, ShaderData *sd, uint id, AttributeElement *elem) +{ + if(sd->object == ~0) + return (int)ATTR_STD_NOT_FOUND; + +#ifdef __OSL__ + if (kg->osl) { + return OSLShader::find_attribute(kg, sd, id, elem); + } + else +#endif + { + /* for SVM, find attribute by unique id */ + uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride; +#ifdef __HAIR__ + attr_offset = (sd->segment == ~0)? attr_offset: attr_offset + ATTR_PRIM_CURVE; +#endif + uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset); + + while(attr_map.x != id) { + attr_offset += ATTR_PRIM_TYPES; + attr_map = kernel_tex_fetch(__attributes_map, attr_offset); + } + + *elem = (AttributeElement)attr_map.y; + + /* return result */ + return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z; + } +} + +__device float primitive_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy) +{ +#ifdef __HAIR__ + if(sd->segment == ~0) +#endif + return triangle_attribute_float(kg, sd, elem, offset, dx, dy); +#ifdef __HAIR__ + else + return curve_attribute_float(kg, sd, elem, offset, dx, dy); +#endif +} + +__device float3 primitive_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy) +{ +#ifdef __HAIR__ + if(sd->segment == ~0) +#endif + return triangle_attribute_float3(kg, sd, elem, offset, dx, dy); +#ifdef __HAIR__ + else + return curve_attribute_float3(kg, sd, elem, offset, dx, dy); +#endif +} + +__device float3 primitive_uv(KernelGlobals *kg, ShaderData *sd) +{ + AttributeElement elem_uv; + int offset_uv = find_attribute(kg, sd, ATTR_STD_UV, &elem_uv); + + if(offset_uv == ATTR_STD_NOT_FOUND) + return make_float3(0.0f, 0.0f, 0.0f); + + float3 uv = primitive_attribute_float3(kg, sd, elem_uv, offset_uv, NULL, NULL); + uv.z = 1.0f; + return uv; +} + +__device float3 primitive_tangent(KernelGlobals *kg, ShaderData *sd) +{ +#ifdef __HAIR__ + if(sd->segment != ~0) + return normalize(sd->dPdu); +#endif + + /* try to create spherical tangent from generated coordinates */ + AttributeElement attr_elem; + int attr_offset = find_attribute(kg, sd, ATTR_STD_GENERATED, &attr_elem); + + if(attr_offset != ATTR_STD_NOT_FOUND) { + float3 data = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL); + data = make_float3(-(data.y - 0.5f), (data.x - 0.5f), 0.0f); + object_normal_transform(kg, sd, &data); + return cross(sd->N, normalize(cross(data, sd->N)));; + } + else { + /* otherwise use surface derivatives */ + return normalize(sd->dPdu); + } +} + +/* motion */ + +__device float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *sd) +{ + float3 motion_pre = sd->P, motion_post = sd->P; + + /* deformation motion */ + AttributeElement elem_pre, elem_post; + int offset_pre = find_attribute(kg, sd, ATTR_STD_MOTION_PRE, &elem_pre); + int offset_post = find_attribute(kg, sd, ATTR_STD_MOTION_POST, &elem_post); + + if(offset_pre != ATTR_STD_NOT_FOUND) + motion_pre = primitive_attribute_float3(kg, sd, elem_pre, offset_pre, NULL, NULL); + if(offset_post != ATTR_STD_NOT_FOUND) + motion_post = primitive_attribute_float3(kg, sd, elem_post, 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_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_PRE); + motion_pre = transform_point(&tfm, motion_pre); + + tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_POST); + motion_post = transform_point(&tfm, motion_post); + + float3 P; + + /* camera motion, for perspective/orthographic motion.pre/post will be a + * world-to-raster matrix, for panorama it's world-to-camera */ + if (kernel_data.cam.type != CAMERA_PANORAMA) { + tfm = kernel_data.cam.worldtoraster; + P = transform_perspective(&tfm, sd->P); + + tfm = kernel_data.cam.motion.pre; + motion_pre = transform_perspective(&tfm, motion_pre); + + tfm = kernel_data.cam.motion.post; + motion_post = transform_perspective(&tfm, motion_post); + } + else { + tfm = kernel_data.cam.worldtocamera; + P = normalize(transform_point(&tfm, sd->P)); + P = float2_to_float3(direction_to_panorama(kg, P)); + P.x *= kernel_data.cam.width; + P.y *= kernel_data.cam.height; + + tfm = kernel_data.cam.motion.pre; + motion_pre = normalize(transform_point(&tfm, motion_pre)); + motion_pre = float2_to_float3(direction_to_panorama(kg, motion_pre)); + motion_pre.x *= kernel_data.cam.width; + motion_pre.y *= kernel_data.cam.height; + + tfm = kernel_data.cam.motion.post; + motion_post = normalize(transform_point(&tfm, motion_post)); + motion_post = float2_to_float3(direction_to_panorama(kg, motion_post)); + motion_post.x *= kernel_data.cam.width; + motion_post.y *= kernel_data.cam.height; + } + + motion_pre = motion_pre - P; + motion_post = P - motion_post; + + return make_float4(motion_pre.x, motion_pre.y, motion_post.x, motion_post.y); +} + +CCL_NAMESPACE_END + +#endif /* __KERNEL_ATTRIBUTE_CL__ */ diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index 47b4d02e5bf..0a5a2ab54b0 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -56,24 +56,11 @@ __device_noinline void shader_setup_object_transforms(KernelGlobals *kg, ShaderD __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray) { - /* fetch triangle data */ - int prim = kernel_tex_fetch(__prim_index, isect->prim); - float4 Ns = kernel_tex_fetch(__tri_normal, prim); - float3 Ng = make_float3(Ns.x, Ns.y, Ns.z); - int shader = __float_as_int(Ns.w); - - /* triangle */ #ifdef __INSTANCING__ sd->object = (isect->object == ~0)? kernel_tex_fetch(__prim_object, isect->prim): isect->object; #endif - sd->prim = prim; -#ifdef __UV__ - sd->u = isect->u; - sd->v = isect->v; -#endif - sd->flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*2); - sd->flag |= kernel_tex_fetch(__object_flag, sd->object); + sd->flag = kernel_tex_fetch(__object_flag, sd->object); /* matrices and time */ #ifdef __OBJECT_MOTION__ @@ -81,23 +68,63 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd, 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; + sd->prim = kernel_tex_fetch(__prim_index, isect->prim); sd->ray_length = isect->t; - /* smooth normal */ - if(sd->shader & SHADER_SMOOTH_NORMAL) - sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v); +#ifdef __HAIR__ + if(kernel_tex_fetch(__prim_segment, isect->prim) != ~0) { + /* Strand Shader setting*/ + float4 curvedata = kernel_tex_fetch(__curves, sd->prim); + + sd->shader = __float_as_int(curvedata.z); + sd->segment = isect->segment; + + float tcorr = isect->t; + if(kernel_data.curve_kernel_data.curveflags & CURVE_KN_POSTINTERSECTCORRECTION) { + tcorr = (isect->u < 0)? tcorr + sqrtf(isect->v) : tcorr - sqrtf(isect->v); + sd->ray_length = tcorr; + } + + sd->P = bvh_curve_refine(kg, sd, isect, ray, tcorr); + } + else { +#endif + /* fetch triangle data */ + float4 Ns = kernel_tex_fetch(__tri_normal, sd->prim); + float3 Ng = make_float3(Ns.x, Ns.y, Ns.z); + sd->shader = __float_as_int(Ns.w); + +#ifdef __HAIR__ + sd->segment = ~0; +#endif + +#ifdef __UV__ + sd->u = isect->u; + sd->v = isect->v; +#endif + + /* vectors */ + sd->P = bvh_triangle_refine(kg, sd, isect, ray); + sd->Ng = Ng; + sd->N = Ng; + + /* smooth normal */ + if(sd->shader & SHADER_SMOOTH_NORMAL) + sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v); #ifdef __DPDU__ - /* dPdu/dPdv */ - triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim); + /* dPdu/dPdv */ + triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim); +#endif + +#ifdef __HAIR__ + } #endif + sd->I = -ray->D; + + sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2); + #ifdef __INSTANCING__ if(isect->object != ~0) { /* instance transform */ @@ -135,7 +162,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, float t, float time) + int shader, int object, int prim, float u, float v, float t, float time, int segment = ~0) { /* vectors */ sd->P = P; @@ -143,11 +170,15 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd, sd->Ng = Ng; sd->I = I; sd->shader = shader; +#ifdef __HAIR__ + sd->segment = segment; +#endif /* primitive */ #ifdef __INSTANCING__ sd->object = object; #endif + /* currently no access to bvh prim index for strand sd->prim - this will cause errors with needs fixing*/ sd->prim = prim; #ifdef __UV__ sd->u = u; @@ -183,8 +214,13 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd, #endif /* smooth normal */ +#ifdef __HAIR__ + if(sd->shader & SHADER_SMOOTH_NORMAL && sd->segment == ~0) { + sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v); +#else if(sd->shader & SHADER_SMOOTH_NORMAL) { sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v); +#endif #ifdef __INSTANCING__ if(instanced) @@ -194,10 +230,17 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd, #ifdef __DPDU__ /* dPdu/dPdv */ +#ifdef __HAIR__ + if(sd->prim == ~0 || sd->segment != ~0) { + sd->dPdu = make_float3(0.0f, 0.0f, 0.0f); + sd->dPdv = make_float3(0.0f, 0.0f, 0.0f); + } +#else if(sd->prim == ~0) { sd->dPdu = make_float3(0.0f, 0.0f, 0.0f); sd->dPdv = make_float3(0.0f, 0.0f, 0.0f); } +#endif else { triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim); @@ -279,6 +322,9 @@ __device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData sd->object = ~0; #endif sd->prim = ~0; +#ifdef __HAIR__ + sd->segment = ~0; +#endif #ifdef __UV__ sd->u = 0.0f; sd->v = 0.0f; @@ -732,8 +778,20 @@ __device void shader_eval_displacement(KernelGlobals *kg, ShaderData *sd, Shader __device bool shader_transparent_shadow(KernelGlobals *kg, Intersection *isect) { int prim = kernel_tex_fetch(__prim_index, isect->prim); - float4 Ns = kernel_tex_fetch(__tri_normal, prim); - int shader = __float_as_int(Ns.w); + int shader = 0; + +#ifdef __HAIR__ + if(kernel_tex_fetch(__prim_segment, isect->prim) == ~0) { +#endif + float4 Ns = kernel_tex_fetch(__tri_normal, prim); + shader = __float_as_int(Ns.w); +#ifdef __HAIR__ + } + else { + float4 str = kernel_tex_fetch(__curves, prim); + shader = __float_as_int(str.z); + } +#endif int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*2); return (flag & SD_HAS_SURFACE_TRANSPARENT) != 0; diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h index 29f6b3f072c..e27de95e7ab 100644 --- a/intern/cycles/kernel/kernel_textures.h +++ b/intern/cycles/kernel/kernel_textures.h @@ -27,6 +27,7 @@ /* bvh */ KERNEL_TEX(float4, texture_float4, __bvh_nodes) KERNEL_TEX(float4, texture_float4, __tri_woop) +KERNEL_TEX(uint, texture_uint, __prim_segment) KERNEL_TEX(uint, texture_uint, __prim_visibility) KERNEL_TEX(uint, texture_uint, __prim_index) KERNEL_TEX(uint, texture_uint, __prim_object) @@ -42,6 +43,10 @@ KERNEL_TEX(float4, texture_float4, __tri_vnormal) KERNEL_TEX(float4, texture_float4, __tri_vindex) KERNEL_TEX(float4, texture_float4, __tri_verts) +/* curves */ +KERNEL_TEX(float4, texture_float4, __curves) +KERNEL_TEX(float4, texture_float4, __curve_keys) + /* attributes */ KERNEL_TEX(uint4, texture_uint4, __attributes_map) KERNEL_TEX(float, texture_float, __attributes_float) diff --git a/intern/cycles/kernel/kernel_triangle.h b/intern/cycles/kernel/kernel_triangle.h index 570ae52d6c2..d346137760f 100644 --- a/intern/cycles/kernel/kernel_triangle.h +++ b/intern/cycles/kernel/kernel_triangle.h @@ -190,82 +190,5 @@ __device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData *s } } -/* motion */ - -__device float4 triangle_motion_vector(KernelGlobals *kg, ShaderData *sd) -{ - float3 motion_pre = sd->P, motion_post = sd->P; - - /* deformation motion */ - int offset_pre = find_attribute(kg, sd, ATTR_STD_MOTION_PRE); - int offset_post = 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_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_PRE); - motion_pre = transform_point(&tfm, motion_pre); - - tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_POST); - motion_post = transform_point(&tfm, motion_post); - - float3 P; - - /* camera motion, for perspective/orthographic motion.pre/post will be a - * world-to-raster matrix, for panorama it's world-to-camera */ - if (kernel_data.cam.type != CAMERA_PANORAMA) { - tfm = kernel_data.cam.worldtoraster; - P = transform_perspective(&tfm, sd->P); - - tfm = kernel_data.cam.motion.pre; - motion_pre = transform_perspective(&tfm, motion_pre); - - tfm = kernel_data.cam.motion.post; - motion_post = transform_perspective(&tfm, motion_post); - } - else { - tfm = kernel_data.cam.worldtocamera; - P = normalize(transform_point(&tfm, sd->P)); - P = float2_to_float3(direction_to_panorama(kg, P)); - P.x *= kernel_data.cam.width; - P.y *= kernel_data.cam.height; - - tfm = kernel_data.cam.motion.pre; - motion_pre = normalize(transform_point(&tfm, motion_pre)); - motion_pre = float2_to_float3(direction_to_panorama(kg, motion_pre)); - motion_pre.x *= kernel_data.cam.width; - motion_pre.y *= kernel_data.cam.height; - - tfm = kernel_data.cam.motion.post; - motion_post = normalize(transform_point(&tfm, motion_post)); - motion_post = float2_to_float3(direction_to_panorama(kg, motion_post)); - motion_post.x *= kernel_data.cam.width; - motion_post.y *= kernel_data.cam.height; - } - - motion_pre = motion_pre - P; - motion_post = P - 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 = 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 d11b96503d9..2bd6b5859f3 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -47,6 +47,7 @@ CCL_NAMESPACE_BEGIN #define __OSL__ #endif #define __NON_PROGRESSIVE__ +#define __HAIR__ #endif #ifdef __KERNEL_CUDA__ @@ -116,7 +117,6 @@ CCL_NAMESPACE_BEGIN #define __ANISOTROPIC__ #define __OBJECT_MOTION__ #endif - //#define __SOBOL_FULL_SCREEN__ /* Shader Evaluation */ @@ -292,7 +292,8 @@ typedef enum LightType { LIGHT_BACKGROUND, LIGHT_AREA, LIGHT_AO, - LIGHT_SPOT + LIGHT_SPOT, + LIGHT_STRAND } LightType; /* Camera Type */ @@ -343,18 +344,44 @@ typedef struct Intersection { float t, u, v; int prim; int object; + int segment; } Intersection; /* Attributes */ +#define ATTR_PRIM_TYPES 2 +#define ATTR_PRIM_CURVE 1 + typedef enum AttributeElement { + ATTR_ELEMENT_NONE, + ATTR_ELEMENT_VALUE, ATTR_ELEMENT_FACE, ATTR_ELEMENT_VERTEX, ATTR_ELEMENT_CORNER, - ATTR_ELEMENT_VALUE, - ATTR_ELEMENT_NONE + ATTR_ELEMENT_CURVE, + ATTR_ELEMENT_CURVE_KEY } AttributeElement; +typedef enum AttributeStandard { + ATTR_STD_NONE = 0, + ATTR_STD_VERTEX_NORMAL, + ATTR_STD_FACE_NORMAL, + ATTR_STD_UV, + ATTR_STD_UV_TANGENT, + ATTR_STD_UV_TANGENT_SIGN, + ATTR_STD_GENERATED, + ATTR_STD_POSITION_UNDEFORMED, + ATTR_STD_POSITION_UNDISPLACED, + ATTR_STD_MOTION_PRE, + ATTR_STD_MOTION_POST, + ATTR_STD_PARTICLE, + ATTR_STD_CURVE_TANGENT, + ATTR_STD_CURVE_INTERCEPT, + ATTR_STD_NUM, + + ATTR_STD_NOT_FOUND = ~0 +} AttributeStandard; + /* Closure data */ #define MAX_CLOSURE 8 @@ -436,6 +463,11 @@ typedef struct ShaderData { /* primitive id if there is one, ~0 otherwise */ int prim; + +#ifdef __HAIR__ + /* for curves, segment number in curve, ~0 for triangles */ + int segment; +#endif /* parametric coordinates * - barycentric weights for triangles */ float u, v; @@ -650,6 +682,29 @@ typedef struct KernelBVH { int pad2; } KernelBVH; +typedef enum CurveFlag { + /* runtime flags */ + CURVE_KN_BACKFACING = 1, /* backside of cylinder? */ + CURVE_KN_ENCLOSEFILTER = 2, /* don't consider strands surrounding start point? */ + CURVE_KN_CURVEDATA = 4, /* curve data available? */ + CURVE_KN_INTERPOLATE = 8, /* render as a curve? - not supported yet */ + CURVE_KN_ACCURATE = 16, /* use accurate intersections test? */ + CURVE_KN_INTERSECTCORRECTION = 32, /* correct for width after determing closest midpoint? */ + CURVE_KN_POSTINTERSECTCORRECTION = 64, /* correct for width after intersect? */ + CURVE_KN_NORMALCORRECTION = 128, /* correct tangent normal for slope? */ + CURVE_KN_TRUETANGENTGNORMAL = 256, /* use tangent normal for geometry? */ + CURVE_KN_TANGENTGNORMAL = 512, /* use tangent normal for shader? */ +} CurveFlag; + +typedef struct KernelCurves { + /* strand intersect and normal parameters - many can be changed to flags*/ + float normalmix; + float encasing_ratio; + int curveflags; + int pad; + +} KernelCurves; + typedef struct KernelData { KernelCamera cam; KernelFilm film; @@ -657,6 +712,7 @@ typedef struct KernelData { KernelSunSky sunsky; KernelIntegrator integrator; KernelBVH bvh; + KernelCurves curve_kernel_data; } KernelData; CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index 498d10f385b..28742d56e3b 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -37,9 +37,10 @@ #include "kernel_differential.h" #include "kernel_object.h" #include "kernel_bvh.h" -#include "kernel_attribute.h" -#include "kernel_projection.h" #include "kernel_triangle.h" +#include "kernel_curve.h" +#include "kernel_primitive.h" +#include "kernel_projection.h" #include "kernel_accumulate.h" #include "kernel_shader.h" @@ -74,6 +75,11 @@ ustring OSLRenderServices::u_geom_numpolyvertices("geom:numpolyvertices"); ustring OSLRenderServices::u_geom_trianglevertices("geom:trianglevertices"); ustring OSLRenderServices::u_geom_polyvertices("geom:polyvertices"); ustring OSLRenderServices::u_geom_name("geom:name"); +#ifdef __HAIR__ +ustring OSLRenderServices::u_is_curve("geom:is_curve"); +ustring OSLRenderServices::u_curve_thickness("geom:curve_thickness"); +ustring OSLRenderServices::u_curve_tangent_normal("geom:curve_tangent_normal"); +#endif ustring OSLRenderServices::u_path_ray_length("path:ray_length"); ustring OSLRenderServices::u_trace("trace"); ustring OSLRenderServices::u_hit("hit"); @@ -495,14 +501,14 @@ static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd, const OS attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor) { float3 fval[3]; - fval[0] = triangle_attribute_float3(kg, sd, attr.elem, attr.offset, - (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL); + fval[0] = primitive_attribute_float3(kg, sd, attr.elem, attr.offset, + (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL); return set_attribute_float3(fval, type, derivatives, val); } else if (attr.type == TypeDesc::TypeFloat) { float fval[3]; - fval[0] = triangle_attribute_float(kg, sd, attr.elem, attr.offset, - (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL); + fval[0] = primitive_attribute_float(kg, sd, attr.elem, attr.offset, + (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL); return set_attribute_float(fval, type, derivatives, val); } else { @@ -593,10 +599,13 @@ bool OSLRenderServices::get_object_standard_attribute(KernelGlobals *kg, ShaderD float3 f = particle_angular_velocity(kg, particle_id); return set_attribute_float3(f, type, derivatives, val); } + + /* Geometry Attributes */ else if (name == u_geom_numpolyvertices) { return set_attribute_int(3, type, derivatives, val); } - else if (name == u_geom_trianglevertices || name == u_geom_polyvertices) { + else if ((name == u_geom_trianglevertices || name == u_geom_polyvertices) + && sd->segment == ~0) { float3 P[3]; triangle_vertices(kg, sd->prim, P); @@ -612,6 +621,22 @@ bool OSLRenderServices::get_object_standard_attribute(KernelGlobals *kg, ShaderD ustring object_name = kg->osl->object_names[sd->object]; return set_attribute_string(object_name, type, derivatives, val); } + +#ifdef __HAIR__ + /* Hair Attributes */ + else if (name == u_is_curve) { + float f = (sd->segment != ~0); + return set_attribute_float(f, type, derivatives, val); + } + else if (name == u_curve_thickness) { + float f = curve_thickness(kg, sd); + return set_attribute_float(f, type, derivatives, val); + } + else if (name == u_curve_tangent_normal) { + float3 f = curve_tangent_normal(kg, sd); + return set_attribute_float3(f, type, derivatives, val); + } +#endif else return false; } @@ -634,7 +659,7 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri { KernelGlobals *kg = kernel_globals; ShaderData *sd = (ShaderData *)renderstate; - int object, tri; + int object, prim, segment; /* lookup of attribute on another object */ if (object_name != u_empty || sd == NULL) { @@ -644,17 +669,20 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri return false; object = it->second; - tri = ~0; + prim = ~0; + segment = ~0; } else { object = sd->object; - tri = sd->prim; + prim = sd->prim; + segment = sd->segment; if (object == ~0) return get_background_attribute(kg, sd, name, type, derivatives, val); } /* find attribute on object */ + object = object*ATTR_PRIM_TYPES + (segment != ~0); OSLGlobals::AttributeMap& attribute_map = kg->osl->attribute_map[object]; OSLGlobals::AttributeMap::iterator it = attribute_map.find(name); @@ -663,7 +691,7 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri if (attr.elem != ATTR_ELEMENT_VALUE) { /* triangle and vertex attributes */ - if (tri != ~0) + if (prim != ~0) return get_mesh_attribute(kg, sd, attr, type, derivatives, val); } else { diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h index cd4a4163209..50c50b9952c 100644 --- a/intern/cycles/kernel/osl/osl_services.h +++ b/intern/cycles/kernel/osl/osl_services.h @@ -130,6 +130,9 @@ public: static ustring u_geom_trianglevertices; static ustring u_geom_polyvertices; static ustring u_geom_name; + static ustring u_is_curve; + static ustring u_curve_thickness; + static ustring u_curve_tangent_normal; static ustring u_path_ray_length; static ustring u_trace; static ustring u_hit; diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp index 3ff032374fc..59e307bb408 100644 --- a/intern/cycles/kernel/osl/osl_shader.cpp +++ b/intern/cycles/kernel/osl/osl_shader.cpp @@ -26,9 +26,10 @@ #include "osl_services.h" #include "osl_shader.h" -#include "util_attribute.h" #include "util_foreach.h" +#include "attribute.h" + #include <OSL/oslexec.h> CCL_NAMESPACE_BEGIN @@ -453,15 +454,17 @@ float3 OSLShader::volume_eval_phase(const ShaderClosure *sc, const float3 omega_ /* Attributes */ -int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id) +int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem) { /* for OSL, a hash map is used to lookup the attribute by name. */ - OSLGlobals::AttributeMap &attr_map = kg->osl->attribute_map[sd->object]; - ustring stdname(std::string("std::") + std::string(attribute_standard_name((AttributeStandard)id))); + int object = sd->object*ATTR_PRIM_TYPES + (sd->segment != ~0); + OSLGlobals::AttributeMap &attr_map = kg->osl->attribute_map[object]; + ustring stdname(std::string("geom:") + std::string(Attribute::standard_name((AttributeStandard)id))); OSLGlobals::AttributeMap::const_iterator it = attr_map.find(stdname); if (it != attr_map.end()) { const OSLGlobals::Attribute &osl_attr = it->second; + *elem = osl_attr.elem; /* return result */ return (osl_attr.elem == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : osl_attr.offset; } diff --git a/intern/cycles/kernel/osl/osl_shader.h b/intern/cycles/kernel/osl/osl_shader.h index 2e46a2de42c..2062c651162 100644 --- a/intern/cycles/kernel/osl/osl_shader.h +++ b/intern/cycles/kernel/osl/osl_shader.h @@ -74,7 +74,7 @@ public: const float3 omega_in, const float3 omega_out); /* attributes */ - static int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id); + static int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem); }; CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt index 70fc8610c98..acae46f1615 100644 --- a/intern/cycles/kernel/shaders/CMakeLists.txt +++ b/intern/cycles/kernel/shaders/CMakeLists.txt @@ -27,6 +27,7 @@ set(SRC_OSL node_glass_bsdf.osl node_glossy_bsdf.osl node_gradient_texture.osl + node_hair_info.osl node_holdout.osl node_hsv.osl node_image_texture.osl diff --git a/intern/cycles/util/util_attribute.h b/intern/cycles/kernel/shaders/node_hair_info.osl index 334864c7f44..cbb3b98383f 100644 --- a/intern/cycles/util/util_attribute.h +++ b/intern/cycles/kernel/shaders/node_hair_info.osl @@ -1,5 +1,5 @@ /* - * Copyright 2011, Blender Foundation. + * Copyright 2012, Blender Foundation. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -16,16 +16,17 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __UTIL_ATTRIBUTE_H__ -#define __UTIL_ATTRIBUTE_H__ +#include "stdosl.h" -#include "util_types.h" - -CCL_NAMESPACE_BEGIN - -const char *attribute_standard_name(AttributeStandard std); - -CCL_NAMESPACE_END - -#endif /* __UTIL_ATTRIBUTE_H__ */ +shader node_hair_info( + output float IsStrand = 0.0, + output float Intercept = 0.0, + output float Thickness = 0.0, + output normal TangentNormal = N) +{ + getattribute("geom:is_curve", IsStrand); + getattribute("geom:curve_intercept", Intercept); + getattribute("geom:curve_thickness", Thickness); + getattribute("geom:curve_tangent_normal", TangentNormal); +} diff --git a/intern/cycles/kernel/shaders/stdosl.h b/intern/cycles/kernel/shaders/stdosl.h index 69ca6b32c36..f340eaff95f 100644 --- a/intern/cycles/kernel/shaders/stdosl.h +++ b/intern/cycles/kernel/shaders/stdosl.h @@ -161,6 +161,15 @@ vector cross (vector a, vector b) BUILTIN; float dot (vector a, vector b) BUILTIN; float length (vector v) BUILTIN; float distance (point a, point b) BUILTIN; +float distance (point a, point b, point q) +{ + vector d = b - a; + float dd = dot(d, d); + if(dd == 0.0) + return distance(q, a); + float t = dot(q - a, d)/dd; + return distance(q, a + clamp(t, 0.0, 1.0)*d); +} normal normalize (normal v) BUILTIN; vector normalize (vector v) BUILTIN; vector faceforward (vector N, vector I, vector Nref) BUILTIN; @@ -304,7 +313,7 @@ color transformc (string to, color x) r = color (dot (vector(0.299, 0.587, 0.114), (vector)x), dot (vector(0.596, -0.275, -0.321), (vector)x), dot (vector(0.212, -0.523, 0.311), (vector)x)); - else if (to == "xyz") + else if (to == "XYZ") r = color (dot (vector(0.412453, 0.357580, 0.180423), (vector)x), dot (vector(0.212671, 0.715160, 0.072169), (vector)x), dot (vector(0.019334, 0.119193, 0.950227), (vector)x)); @@ -366,7 +375,7 @@ color transformc (string from, string to, color x) r = color (dot (vector(1, 0.9557, 0.6199), (vector)x), dot (vector(1, -0.2716, -0.6469), (vector)x), dot (vector(1, -1.1082, 1.7051), (vector)x)); - else if (from == "xyz") + else if (from == "XYZ") r = color (dot (vector( 3.240479, -1.537150, -0.498535), (vector)x), dot (vector(-0.969256, 1.875991, 0.041556), (vector)x), dot (vector( 0.055648, -0.204043, 1.057311), (vector)x)); @@ -409,6 +418,8 @@ int startswith (string s, string prefix) BUILTIN; int endswith (string s, string suffix) BUILTIN; string substr (string s, int start, int len) BUILTIN; string substr (string s, int start) { return substr (s, start, strlen(s)); } +float strtof (string str) BUILTIN; +int strtoi (string str) BUILTIN; // Define concat in terms of shorter concat string concat (string a, string b, string c) { diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index ec7978066c2..1f4857c0924 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -301,6 +301,12 @@ __device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderT case NODE_PARTICLE_INFO: svm_node_particle_info(kg, sd, stack, node.y, node.z); break; +#ifdef __HAIR__ + case NODE_HAIR_INFO: + svm_node_hair_info(kg, sd, stack, node.y, node.z); + break; +#endif + #endif case NODE_CONVERT: svm_node_convert(sd, stack, node.y, node.z, node.w); diff --git a/intern/cycles/kernel/svm/svm_attribute.h b/intern/cycles/kernel/svm/svm_attribute.h index ed70a6dc423..2beec995151 100644 --- a/intern/cycles/kernel/svm/svm_attribute.h +++ b/intern/cycles/kernel/svm/svm_attribute.h @@ -28,10 +28,15 @@ __device void svm_node_attr_init(KernelGlobals *kg, ShaderData *sd, /* find attribute by unique id */ uint id = node.y; uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride; +#ifdef __HAIR__ + attr_offset = (sd->segment == ~0)? attr_offset: attr_offset + ATTR_PRIM_CURVE; +#endif uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset); - - while(attr_map.x != id) - attr_map = kernel_tex_fetch(__attributes_map, ++attr_offset); + + while(attr_map.x != id) { + attr_offset += ATTR_PRIM_TYPES; + attr_map = kernel_tex_fetch(__attributes_map, attr_offset); + } /* return result */ *elem = (AttributeElement)attr_map.y; @@ -61,21 +66,21 @@ __device void svm_node_attr(KernelGlobals *kg, ShaderData *sd, float *stack, uin /* fetch and store attribute */ if(type == NODE_ATTR_FLOAT) { if(mesh_type == NODE_ATTR_FLOAT) { - float f = triangle_attribute_float(kg, sd, elem, offset, NULL, NULL); + float f = primitive_attribute_float(kg, sd, elem, offset, NULL, NULL); stack_store_float(stack, out_offset, f); } else { - float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL); + float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, NULL); stack_store_float(stack, out_offset, average(f)); } } else { if(mesh_type == NODE_ATTR_FLOAT3) { - float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL); + float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, NULL); stack_store_float3(stack, out_offset, f); } else { - float f = triangle_attribute_float(kg, sd, elem, offset, NULL, NULL); + float f = primitive_attribute_float(kg, sd, elem, offset, NULL, NULL); stack_store_float3(stack, out_offset, make_float3(f, f, f)); } } @@ -94,24 +99,24 @@ __device void svm_node_attr_bump_dx(KernelGlobals *kg, ShaderData *sd, float *st if(type == NODE_ATTR_FLOAT) { if(mesh_type == NODE_ATTR_FLOAT) { float dx; - float f = triangle_attribute_float(kg, sd, elem, offset, &dx, NULL); + float f = primitive_attribute_float(kg, sd, elem, offset, &dx, NULL); stack_store_float(stack, out_offset, f+dx); } else { float3 dx; - float3 f = triangle_attribute_float3(kg, sd, elem, offset, &dx, NULL); + float3 f = primitive_attribute_float3(kg, sd, elem, offset, &dx, NULL); stack_store_float(stack, out_offset, average(f+dx)); } } else { if(mesh_type == NODE_ATTR_FLOAT3) { float3 dx; - float3 f = triangle_attribute_float3(kg, sd, elem, offset, &dx, NULL); + float3 f = primitive_attribute_float3(kg, sd, elem, offset, &dx, NULL); stack_store_float3(stack, out_offset, f+dx); } else { float dx; - float f = triangle_attribute_float(kg, sd, elem, offset, &dx, NULL); + float f = primitive_attribute_float(kg, sd, elem, offset, &dx, NULL); stack_store_float3(stack, out_offset, make_float3(f+dx, f+dx, f+dx)); } } @@ -130,24 +135,24 @@ __device void svm_node_attr_bump_dy(KernelGlobals *kg, ShaderData *sd, float *st if(type == NODE_ATTR_FLOAT) { if(mesh_type == NODE_ATTR_FLOAT) { float dy; - float f = triangle_attribute_float(kg, sd, elem, offset, NULL, &dy); + float f = primitive_attribute_float(kg, sd, elem, offset, NULL, &dy); stack_store_float(stack, out_offset, f+dy); } else { float3 dy; - float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, &dy); + float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, &dy); stack_store_float(stack, out_offset, average(f+dy)); } } else { if(mesh_type == NODE_ATTR_FLOAT3) { float3 dy; - float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, &dy); + float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, &dy); stack_store_float3(stack, out_offset, f+dy); } else { float dy; - float f = triangle_attribute_float(kg, sd, elem, offset, NULL, &dy); + float f = primitive_attribute_float(kg, sd, elem, offset, NULL, &dy); stack_store_float3(stack, out_offset, make_float3(f+dy, f+dy, f+dy)); } } diff --git a/intern/cycles/kernel/svm/svm_geometry.h b/intern/cycles/kernel/svm/svm_geometry.h index c4d03c1f948..a04f4ea0fa7 100644 --- a/intern/cycles/kernel/svm/svm_geometry.h +++ b/intern/cycles/kernel/svm/svm_geometry.h @@ -28,23 +28,7 @@ __device void svm_node_geometry(KernelGlobals *kg, ShaderData *sd, float *stack, case NODE_GEOM_P: data = sd->P; break; case NODE_GEOM_N: data = sd->N; break; #ifdef __DPDU__ - case NODE_GEOM_T: { - /* try to create spherical tangent from generated coordinates */ - int attr_offset = (sd->object != ~0)? find_attribute(kg, sd, ATTR_STD_GENERATED): ATTR_STD_NOT_FOUND; - - if(attr_offset != ATTR_STD_NOT_FOUND) { - data = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, attr_offset, NULL, NULL); - data = make_float3(-(data.y - 0.5f), (data.x - 0.5f), 0.0f); - object_normal_transform(kg, sd, &data); - data = cross(sd->N, normalize(cross(data, sd->N)));; - } - else { - /* otherwise use surface derivatives */ - data = normalize(sd->dPdu); - } - - break; - } + case NODE_GEOM_T: data = primitive_tangent(kg, sd); break; #endif case NODE_GEOM_I: data = sd->I; break; case NODE_GEOM_Ng: data = sd->Ng; break; @@ -160,5 +144,36 @@ __device void svm_node_particle_info(KernelGlobals *kg, ShaderData *sd, float *s } } +#ifdef __HAIR__ + +/* Hair Info */ + +__device void svm_node_hair_info(KernelGlobals *kg, ShaderData *sd, float *stack, uint type, uint out_offset) +{ + float data; + float3 data3; + + switch(type) { + case NODE_INFO_CURVE_IS_STRAND: { + data = (sd->segment != ~0); + stack_store_float(stack, out_offset, data); + break; + } + case NODE_INFO_CURVE_INTERCEPT: + break; /* handled as attribute */ + case NODE_INFO_CURVE_THICKNESS: { + data = curve_thickness(kg, sd); + stack_store_float(stack, out_offset, data); + break; + } + case NODE_INFO_CURVE_TANGENT_NORMAL: { + data3 = curve_tangent_normal(kg, sd); + stack_store_float3(stack, out_offset, data3); + break; + } + } +} +#endif + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h index 9f2d3367420..7a1af43b625 100644 --- a/intern/cycles/kernel/svm/svm_tex_coord.h +++ b/intern/cycles/kernel/svm/svm_tex_coord.h @@ -248,8 +248,9 @@ __device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *stac } /* first try to get tangent attribute */ - int attr_offset = find_attribute(kg, sd, node.z); - int attr_sign_offset = find_attribute(kg, sd, node.w); + AttributeElement attr_elem, attr_sign_elem; + int attr_offset = find_attribute(kg, sd, node.z, &attr_elem); + int attr_sign_offset = find_attribute(kg, sd, node.w, &attr_sign_elem); if(attr_offset == ATTR_STD_NOT_FOUND || attr_sign_offset == ATTR_STD_NOT_FOUND) { stack_store_float3(stack, normal_offset, make_float3(0.0f, 0.0f, 0.0f)); @@ -257,8 +258,8 @@ __device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *stac } /* ensure orthogonal and normalized (interpolation breaks it) */ - float3 tangent = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, attr_offset, NULL, NULL); - float sign = triangle_attribute_float(kg, sd, ATTR_ELEMENT_CORNER, attr_sign_offset, NULL, NULL); + float3 tangent = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL); + float sign = primitive_attribute_float(kg, sd, attr_sign_elem, attr_sign_offset, NULL, NULL); object_normal_transform(kg, sd, &tangent); tangent = cross(sd->N, normalize(cross(tangent, sd->N)));; @@ -295,22 +296,24 @@ __device void svm_node_tangent(KernelGlobals *kg, ShaderData *sd, float *stack, if(direction_type == NODE_TANGENT_UVMAP) { /* UV map */ - int attr_offset = find_attribute(kg, sd, node.z); + AttributeElement attr_elem; + int attr_offset = find_attribute(kg, sd, node.z, &attr_elem); if(attr_offset == ATTR_STD_NOT_FOUND) tangent = make_float3(0.0f, 0.0f, 0.0f); else - tangent = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, attr_offset, NULL, NULL); + tangent = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL); } else { /* radial */ - int attr_offset = find_attribute(kg, sd, node.z); + AttributeElement attr_elem; + int attr_offset = find_attribute(kg, sd, node.z, &attr_elem); float3 generated; if(attr_offset == ATTR_STD_NOT_FOUND) generated = sd->P; else - generated = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, attr_offset, NULL, NULL); + generated = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL); if(axis == NODE_TANGENT_AXIS_X) tangent = make_float3(0.0f, -(generated.z - 0.5f), (generated.y - 0.5f)); diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index e1a583625fc..57177eec48f 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -97,7 +97,8 @@ typedef enum NodeType { NODE_CLOSURE_SET_NORMAL, NODE_CLOSURE_AMBIENT_OCCLUSION, NODE_TANGENT, - NODE_NORMAL_MAP + NODE_NORMAL_MAP, + NODE_HAIR_INFO } NodeType; typedef enum NodeAttributeType { @@ -132,6 +133,13 @@ typedef enum NodeParticleInfo { NODE_INFO_PAR_ANGULAR_VELOCITY } NodeParticleInfo; +typedef enum NodeHairInfo { + NODE_INFO_CURVE_IS_STRAND, + NODE_INFO_CURVE_INTERCEPT, + NODE_INFO_CURVE_THICKNESS, + NODE_INFO_CURVE_TANGENT_NORMAL +} NodeHairInfo; + typedef enum NodeLightPath { NODE_LP_camera = 0, NODE_LP_shadow, diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt index 7907061c19c..d67a686d1e8 100644 --- a/intern/cycles/render/CMakeLists.txt +++ b/intern/cycles/render/CMakeLists.txt @@ -31,6 +31,7 @@ set(SRC object.cpp osl.cpp particles.cpp + curves.cpp scene.cpp session.cpp shader.cpp @@ -56,6 +57,7 @@ set(SRC_HEADERS object.h osl.h particles.h + curves.h scene.h session.h shader.h diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp index 95941c14b6c..b6f6ba47fe8 100644 --- a/intern/cycles/render/attribute.cpp +++ b/intern/cycles/render/attribute.cpp @@ -26,7 +26,7 @@ CCL_NAMESPACE_BEGIN /* Attribute */ -void Attribute::set(ustring name_, TypeDesc type_, Element element_) +void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_) { name = name_; type = type_; @@ -39,12 +39,30 @@ void Attribute::set(ustring name_, TypeDesc type_, Element element_) type == TypeDesc::TypeNormal); } -void Attribute::reserve(int numverts, int numtris) +void Attribute::reserve(int numverts, int numtris, int numcurves, int numkeys) { - buffer.resize(buffer_size(numverts, numtris), 0); + buffer.resize(buffer_size(numverts, numtris, numcurves, numkeys), 0); } -size_t Attribute::data_sizeof() +void Attribute::add(const float& f) +{ + char *data = (char*)&f; + size_t size = sizeof(f); + + for(size_t i = 0; i < size; i++) + buffer.push_back(data[i]); +} + +void Attribute::add(const float3& f) +{ + char *data = (char*)&f; + size_t size = sizeof(f); + + for(size_t i = 0; i < size; i++) + buffer.push_back(data[i]); +} + +size_t Attribute::data_sizeof() const { if(type == TypeDesc::TypeFloat) return sizeof(float); @@ -52,19 +70,27 @@ size_t Attribute::data_sizeof() return sizeof(float3); } -size_t Attribute::element_size(int numverts, int numtris) +size_t Attribute::element_size(int numverts, int numtris, int numcurves, int numkeys) const { - if(element == VERTEX) + if(element == ATTR_ELEMENT_VALUE) + return 1; + if(element == ATTR_ELEMENT_VERTEX) return numverts; - else if(element == FACE) + else if(element == ATTR_ELEMENT_FACE) return numtris; - else + else if(element == ATTR_ELEMENT_CORNER) return numtris*3; + else if(element == ATTR_ELEMENT_CURVE) + return numcurves; + else if(element == ATTR_ELEMENT_CURVE_KEY) + return numkeys; + + return 0; } -size_t Attribute::buffer_size(int numverts, int numtris) +size_t Attribute::buffer_size(int numverts, int numtris, int numcurves, int numkeys) const { - return element_size(numverts, numtris)*data_sizeof(); + return element_size(numverts, numtris, numcurves, numkeys)*data_sizeof(); } bool Attribute::same_storage(TypeDesc a, TypeDesc b) @@ -84,18 +110,51 @@ bool Attribute::same_storage(TypeDesc a, TypeDesc b) return false; } +const char *Attribute::standard_name(AttributeStandard std) +{ + if(std == ATTR_STD_VERTEX_NORMAL) + return "N"; + else if(std == ATTR_STD_FACE_NORMAL) + return "Ng"; + else if(std == ATTR_STD_UV) + return "uv"; + else if(std == ATTR_STD_GENERATED) + return "generated"; + else if(std == ATTR_STD_UV_TANGENT) + return "tangent"; + else if(std == ATTR_STD_UV_TANGENT_SIGN) + return "tangent_sign"; + else if(std == ATTR_STD_POSITION_UNDEFORMED) + return "undeformed"; + else if(std == ATTR_STD_POSITION_UNDISPLACED) + return "undisplaced"; + else if(std == ATTR_STD_MOTION_PRE) + return "motion_pre"; + else if(std == ATTR_STD_MOTION_POST) + return "motion_post"; + else if(std == ATTR_STD_PARTICLE) + return "particle"; + else if(std == ATTR_STD_CURVE_TANGENT) + return "curve_tangent"; + else if(std == ATTR_STD_CURVE_INTERCEPT) + return "curve_intercept"; + + return ""; +} + /* Attribute Set */ AttributeSet::AttributeSet() { - mesh = NULL; + triangle_mesh = NULL; + curve_mesh = NULL; } AttributeSet::~AttributeSet() { } -Attribute *AttributeSet::add(ustring name, TypeDesc type, Attribute::Element element) +Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement element) { Attribute *attr = find(name); @@ -111,24 +170,22 @@ Attribute *AttributeSet::add(ustring name, TypeDesc type, Attribute::Element ele attributes.push_back(Attribute()); attr = &attributes.back(); - if(element == Attribute::VERTEX) - attr->set(name, type, element); - else if(element == Attribute::FACE) - attr->set(name, type, element); - else if(element == Attribute::CORNER) - attr->set(name, type, element); + attr->set(name, type, element); - if(mesh) - attr->reserve(mesh->verts.size(), mesh->triangles.size()); + /* this is weak .. */ + if(triangle_mesh) + attr->reserve(triangle_mesh->verts.size(), triangle_mesh->triangles.size(), 0, 0); + if(curve_mesh) + attr->reserve(0, 0, curve_mesh->curves.size(), curve_mesh->curve_keys.size()); return attr; } -Attribute *AttributeSet::find(ustring name) +Attribute *AttributeSet::find(ustring name) const { - foreach(Attribute& attr, attributes) + foreach(const Attribute& attr, attributes) if(attr.name == name) - return &attr; + return (Attribute*)&attr; return NULL; } @@ -154,41 +211,59 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name) Attribute *attr = NULL; if(name == ustring()) - name = attribute_standard_name(std); - - if(std == ATTR_STD_VERTEX_NORMAL) - attr = add(name, TypeDesc::TypeNormal, Attribute::VERTEX); - else if(std == ATTR_STD_FACE_NORMAL) - attr = add(name, TypeDesc::TypeNormal, Attribute::FACE); - else if(std == ATTR_STD_UV) - attr = add(name, TypeDesc::TypePoint, Attribute::CORNER); - else if(std == ATTR_STD_UV_TANGENT) - attr = add(name, TypeDesc::TypeVector, Attribute::CORNER); - else if(std == ATTR_STD_UV_TANGENT_SIGN) - attr = add(name, TypeDesc::TypeFloat, Attribute::CORNER); - else if(std == ATTR_STD_GENERATED) - attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX); - else if(std == ATTR_STD_POSITION_UNDEFORMED) - attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX); - 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); + name = Attribute::standard_name(std); + + if(triangle_mesh) { + if(std == ATTR_STD_VERTEX_NORMAL) + attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX); + else if(std == ATTR_STD_FACE_NORMAL) + attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_FACE); + else if(std == ATTR_STD_UV) + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER); + else if(std == ATTR_STD_UV_TANGENT) + attr = add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER); + else if(std == ATTR_STD_UV_TANGENT_SIGN) + attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CORNER); + else if(std == ATTR_STD_GENERATED) + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX); + else if(std == ATTR_STD_POSITION_UNDEFORMED) + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX); + else if(std == ATTR_STD_POSITION_UNDISPLACED) + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX); + else if(std == ATTR_STD_MOTION_PRE) + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX); + else if(std == ATTR_STD_MOTION_POST) + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX); + else + assert(0); + } + else if(curve_mesh) { + if(std == ATTR_STD_UV) + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE); + else if(std == ATTR_STD_GENERATED) + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE); + else if(std == ATTR_STD_MOTION_PRE) + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE_KEY); + else if(std == ATTR_STD_MOTION_POST) + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE_KEY); + else if(std == ATTR_STD_CURVE_TANGENT) + attr = add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CURVE_KEY); + else if(std == ATTR_STD_CURVE_INTERCEPT) + attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE_KEY); + else + assert(0); + } attr->std = std; return attr; } -Attribute *AttributeSet::find(AttributeStandard std) +Attribute *AttributeSet::find(AttributeStandard std) const { - foreach(Attribute& attr, attributes) + foreach(const Attribute& attr, attributes) if(attr.std == std) - return &attr; + return (Attribute*)&attr; return NULL; } @@ -217,10 +292,14 @@ Attribute *AttributeSet::find(AttributeRequest& req) return find(req.std); } -void AttributeSet::reserve(int numverts, int numtris) +void AttributeSet::reserve() { - foreach(Attribute& attr, attributes) - attr.reserve(numverts, numtris); + foreach(Attribute& attr, attributes) { + if(triangle_mesh) + attr.reserve(triangle_mesh->verts.size(), triangle_mesh->triangles.size(), 0, 0); + if(curve_mesh) + attr.reserve(0, 0, curve_mesh->curves.size(), curve_mesh->curve_keys.size()); + } } void AttributeSet::clear() @@ -235,9 +314,13 @@ AttributeRequest::AttributeRequest(ustring name_) name = name_; std = ATTR_STD_NONE; - type = TypeDesc::TypeFloat; - element = ATTR_ELEMENT_NONE; - offset = 0; + triangle_type = TypeDesc::TypeFloat; + triangle_element = ATTR_ELEMENT_NONE; + triangle_offset = 0; + + curve_type = TypeDesc::TypeFloat; + curve_element = ATTR_ELEMENT_NONE; + curve_offset = 0; } AttributeRequest::AttributeRequest(AttributeStandard std_) @@ -245,9 +328,13 @@ AttributeRequest::AttributeRequest(AttributeStandard std_) name = ustring(); std = std_; - type = TypeDesc::TypeFloat; - element = ATTR_ELEMENT_NONE; - offset = 0; + triangle_type = TypeDesc::TypeFloat; + triangle_element = ATTR_ELEMENT_NONE; + triangle_offset = 0; + + curve_type = TypeDesc::TypeFloat; + curve_element = ATTR_ELEMENT_NONE; + curve_offset = 0; } /* AttributeRequestSet */ diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h index d05952edfd7..6c0c06d0425 100644 --- a/intern/cycles/render/attribute.h +++ b/intern/cycles/render/attribute.h @@ -21,7 +21,6 @@ #include "kernel_types.h" -#include "util_attribute.h" #include "util_list.h" #include "util_param.h" #include "util_types.h" @@ -42,36 +41,34 @@ class Mesh; class Attribute { public: - enum Element { - VERTEX, - FACE, - CORNER - }; - ustring name; AttributeStandard std; TypeDesc type; vector<char> buffer; - Element element; + AttributeElement element; Attribute() {} - void set(ustring name, TypeDesc type, Element element); - void reserve(int numverts, int numfaces); + void set(ustring name, TypeDesc type, AttributeElement element); + void reserve(int numverts, int numfaces, int numcurves, int numkeys); - size_t data_sizeof(); - size_t element_size(int numverts, int numfaces); - size_t buffer_size(int numverts, int numfaces); + size_t data_sizeof() const; + size_t element_size(int numverts, int numfaces, int numcurves, int numkeys) const; + size_t buffer_size(int numverts, int numfaces, int numcurves, int numkeys) const; char *data() { return (buffer.size())? &buffer[0]: NULL; }; float3 *data_float3() { return (float3*)data(); } float *data_float() { return (float*)data(); } const char *data() const { return (buffer.size())? &buffer[0]: NULL; } - const float3 *data_float3() const { return (float3*)data(); } - const float *data_float() const { return (float*)data(); } + const float3 *data_float3() const { return (const float3*)data(); } + const float *data_float() const { return (const float*)data(); } + + void add(const float& f); + void add(const float3& f); static bool same_storage(TypeDesc a, TypeDesc b); + static const char *standard_name(AttributeStandard std); }; /* Attribute Set @@ -80,23 +77,24 @@ public: class AttributeSet { public: - Mesh *mesh; + Mesh *triangle_mesh; + Mesh *curve_mesh; list<Attribute> attributes; AttributeSet(); ~AttributeSet(); - Attribute *add(ustring name, TypeDesc type, Attribute::Element element); - Attribute *find(ustring name); + Attribute *add(ustring name, TypeDesc type, AttributeElement element); + Attribute *find(ustring name) const; void remove(ustring name); Attribute *add(AttributeStandard std, ustring name = ustring()); - Attribute *find(AttributeStandard std); + Attribute *find(AttributeStandard std) const; void remove(AttributeStandard std); Attribute *find(AttributeRequest& req); - void reserve(int numverts, int numfaces); + void reserve(); void clear(); }; @@ -104,7 +102,7 @@ public: * * Request from a shader to use a certain attribute, so we can figure out * which ones we need to export from the host app end store for the kernel. - * The attribute is found either by name or by standard. */ + * The attribute is found either by name or by standard attribute type. */ class AttributeRequest { public: @@ -112,9 +110,9 @@ public: AttributeStandard std; /* temporary variables used by MeshManager */ - TypeDesc type; - AttributeElement element; - int offset; + TypeDesc triangle_type, curve_type; + AttributeElement triangle_element, curve_element; + int triangle_offset, curve_offset; AttributeRequest(ustring name_); AttributeRequest(AttributeStandard std); diff --git a/intern/cycles/render/curves.cpp b/intern/cycles/render/curves.cpp new file mode 100644 index 00000000000..3299503b4ab --- /dev/null +++ b/intern/cycles/render/curves.cpp @@ -0,0 +1,160 @@ +/* + * Copyright 2011, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "device.h" +#include "curves.h" +#include "mesh.h" +#include "object.h" +#include "scene.h" + +#include "util_foreach.h" +#include "util_map.h" +#include "util_progress.h" +#include "util_vector.h" + +CCL_NAMESPACE_BEGIN + +/* Hair System Manager */ + +CurveSystemManager::CurveSystemManager() +{ + primitive = CURVE_LINE_SEGMENTS; + line_method = CURVE_CORRECTED; + interpolation = CURVE_CARDINAL; + triangle_method = CURVE_CAMERA; + resolution = 3; + segments = 1; + + normalmix = 1.0f; + encasing_ratio = 1.01f; + + use_curves = true; + use_smooth = true; + use_cache = true; + use_parents = false; + use_encasing = true; + use_backfacing = false; + use_joined = false; + use_tangent_normal = false; + use_tangent_normal_geometry = false; + use_tangent_normal_correction = false; + + need_update = true; + need_mesh_update = false; +} + +CurveSystemManager::~CurveSystemManager() +{ +} + +void CurveSystemManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) +{ + if(!need_update) + return; + + device_free(device, dscene); + + progress.set_status("Updating Hair settings", "Copying Hair settings to device"); + + KernelCurves *kcurve= &dscene->data.curve_kernel_data; + + kcurve->curveflags = 0; + + if(primitive == CURVE_SEGMENTS) + kcurve->curveflags |= CURVE_KN_INTERPOLATE; + + if(line_method == CURVE_ACCURATE) + kcurve->curveflags |= CURVE_KN_ACCURATE; + if(line_method == CURVE_CORRECTED) + kcurve->curveflags |= CURVE_KN_INTERSECTCORRECTION; + if(line_method == CURVE_POSTCORRECTED) + kcurve->curveflags |= CURVE_KN_POSTINTERSECTCORRECTION; + + if(use_tangent_normal) + kcurve->curveflags |= CURVE_KN_TANGENTGNORMAL; + if(use_tangent_normal_correction) + kcurve->curveflags |= CURVE_KN_NORMALCORRECTION; + if(use_tangent_normal_geometry) + kcurve->curveflags |= CURVE_KN_TRUETANGENTGNORMAL; + if(use_joined) + kcurve->curveflags |= CURVE_KN_CURVEDATA; + if(use_backfacing) + kcurve->curveflags |= CURVE_KN_BACKFACING; + if(use_encasing) + kcurve->curveflags |= CURVE_KN_ENCLOSEFILTER; + + kcurve->normalmix = normalmix; + kcurve->encasing_ratio = encasing_ratio; + + if(progress.get_cancel()) return; + + need_update = false; +} + +void CurveSystemManager::device_free(Device *device, DeviceScene *dscene) +{ + +} + +bool CurveSystemManager::modified(const CurveSystemManager& CurveSystemManager) +{ + return !(line_method == CurveSystemManager.line_method && + interpolation == CurveSystemManager.interpolation && + primitive == CurveSystemManager.primitive && + use_encasing == CurveSystemManager.use_encasing && + use_tangent_normal == CurveSystemManager.use_tangent_normal && + use_tangent_normal_correction == CurveSystemManager.use_tangent_normal_correction && + use_tangent_normal_geometry == CurveSystemManager.use_tangent_normal_geometry && + encasing_ratio == CurveSystemManager.encasing_ratio && + use_backfacing == CurveSystemManager.use_backfacing && + normalmix == CurveSystemManager.normalmix && + use_cache == CurveSystemManager.use_cache && + use_smooth == CurveSystemManager.use_smooth && + triangle_method == CurveSystemManager.triangle_method && + resolution == CurveSystemManager.resolution && + use_curves == CurveSystemManager.use_curves && + use_joined == CurveSystemManager.use_joined && + segments == CurveSystemManager.segments && + use_parents == CurveSystemManager.use_parents); +} + +bool CurveSystemManager::modified_mesh(const CurveSystemManager& CurveSystemManager) +{ + return !(primitive == CurveSystemManager.primitive && + interpolation == CurveSystemManager.interpolation && + use_parents == CurveSystemManager.use_parents && + use_smooth == CurveSystemManager.use_smooth && + triangle_method == CurveSystemManager.triangle_method && + resolution == CurveSystemManager.resolution && + use_curves == CurveSystemManager.use_curves && + use_joined == CurveSystemManager.use_joined && + segments == CurveSystemManager.segments && + use_cache == CurveSystemManager.use_cache); +} + +void CurveSystemManager::tag_update(Scene *scene) +{ + need_update = true; +} + +void CurveSystemManager::tag_update_mesh() +{ + need_mesh_update = true; +} +CCL_NAMESPACE_END + diff --git a/intern/cycles/render/curves.h b/intern/cycles/render/curves.h new file mode 100644 index 00000000000..bb9ef6d99cf --- /dev/null +++ b/intern/cycles/render/curves.h @@ -0,0 +1,134 @@ +/* + * Copyright 2011, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __CURVES_H__ +#define __CURVES_H__ + +#include "util_types.h" +#include "util_vector.h" + +CCL_NAMESPACE_BEGIN + +class Device; +class DeviceScene; +class Progress; +class Scene; + +typedef enum curve_presets { + CURVE_CUSTOM, + CURVE_TANGENT_SHADING, + CURVE_TRUE_NORMAL, + CURVE_ACCURATE_PRESET +} curve_presets; + +typedef enum curve_primitives { + CURVE_TRIANGLES, + CURVE_LINE_SEGMENTS, + CURVE_SEGMENTS +} curve_primitives; + +typedef enum curve_triangles { + CURVE_CAMERA, + CURVE_RIBBONS, + CURVE_TESSELATED +} curve_triangles; + +typedef enum curve_lines { + CURVE_ACCURATE, + CURVE_CORRECTED, + CURVE_POSTCORRECTED, + CURVE_UNCORRECTED +} curve_lines; + +typedef enum curve_interpolation { + CURVE_LINEAR, + CURVE_CARDINAL, + CURVE_BSPLINE +} curve_interpolation; + +class ParticleCurveData { + +public: + + ParticleCurveData(); + ~ParticleCurveData(); + + vector<int> psys_firstcurve; + vector<int> psys_curvenum; + vector<int> psys_shader; + + vector<float> psys_rootradius; + vector<float> psys_tipradius; + vector<float> psys_shape; + vector<bool> psys_closetip; + + vector<int> curve_firstkey; + vector<int> curve_keynum; + vector<float> curve_length; + vector<float3> curve_uv; + vector<float3> curve_vcol; + + vector<float3> curvekey_co; + vector<float> curvekey_time; +}; + +/* HairSystem Manager */ + +class CurveSystemManager { +public: + + int primitive; + int line_method; + int interpolation; + int triangle_method; + int resolution; + int segments; + + float normalmix; + float encasing_ratio; + + bool use_curves; + bool use_smooth; + bool use_cache; + bool use_parents; + bool use_encasing; + bool use_backfacing; + bool use_tangent_normal; + bool use_tangent_normal_correction; + bool use_tangent_normal_geometry; + bool use_joined; + + bool need_update; + bool need_mesh_update; + + CurveSystemManager(); + ~CurveSystemManager(); + + void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); + void device_free(Device *device, DeviceScene *dscene); + bool modified(const CurveSystemManager& CurveSystemManager); + bool modified_mesh(const CurveSystemManager& CurveSystemManager); + + void tag_update(Scene *scene); + void tag_update_mesh(); +}; + +CCL_NAMESPACE_END + +#endif /* __CURVES_H__ */ + diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp index 4173da453fd..c8e3e94ec98 100644 --- a/intern/cycles/render/light.cpp +++ b/intern/cycles/render/light.cpp @@ -142,6 +142,7 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen /* count */ size_t num_lights = scene->lights.size(); size_t num_triangles = 0; + size_t num_curve_segments = 0; foreach(Object *object, scene->objects) { Mesh *mesh = object->mesh; @@ -169,10 +170,19 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen if(shader->sample_as_light && shader->has_surface_emission) num_triangles++; } + + /* disabled for curves */ +#if 0 + foreach(Mesh::Curve& curve, mesh->curves) { + Shader *shader = scene->shaders[curve.shader]; + + if(shader->sample_as_light && shader->has_surface_emission) + num_curve_segments += curve.num_segments(); +#endif } } - size_t num_distribution = num_triangles; + size_t num_distribution = num_triangles + num_curve_segments; num_distribution += num_lights; /* emission area */ @@ -216,7 +226,7 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen if(shader->sample_as_light && shader->has_surface_emission) { distribution[offset].x = totarea; distribution[offset].y = __int_as_float(i + mesh->tri_offset); - distribution[offset].z = 1.0f; + distribution[offset].z = __int_as_float(~0); distribution[offset].w = __int_as_float(object_id); offset++; @@ -234,6 +244,40 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen totarea += triangle_area(p1, p2, p3); } } + + /*sample as light disabled for strands*/ +#if 0 + size_t i = 0; + + foreach(Mesh::Curve& curve, mesh->curves) { + Shader *shader = scene->shaders[curve.shader]; + int first_key = curve.first_key; + + if(shader->sample_as_light && shader->has_surface_emission) { + for(int j = 0; j < curve.num_segments(); j++) { + distribution[offset].x = totarea; + distribution[offset].y = __int_as_float(i + mesh->curve_offset); // XXX fix kernel code + distribution[offset].z = __int_as_float(j); + distribution[offset].w = __int_as_float(object_id); + offset++; + + float3 p1 = mesh->curve_keys[first_key + j].loc; + float r1 = mesh->curve_keys[first_key + j].radius; + float3 p2 = mesh->curve_keys[first_key + j + 1].loc; + float r2 = mesh->curve_keys[first_key + j + 1].radius; + + if(!transform_applied) { + p1 = transform_point(&tfm, p1); + p2 = transform_point(&tfm, p2); + } + + totarea += M_PI_F * (r1 + r2) * len(p1 - p2); + } + } + + i++; + } +#endif } if(progress.get_cancel()) return; diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index bc782a78c60..d4619dcff55 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -51,7 +51,11 @@ Mesh::Mesh() tri_offset = 0; vert_offset = 0; - attributes.mesh = this; + curve_offset = 0; + curvekey_offset = 0; + + attributes.triangle_mesh = this; + curve_attributes.curve_mesh = this; } Mesh::~Mesh() @@ -59,14 +63,18 @@ Mesh::~Mesh() delete bvh; } -void Mesh::reserve(int numverts, int numtris) +void Mesh::reserve(int numverts, int numtris, int numcurves, int numcurvekeys) { /* reserve space to add verts and triangles later */ verts.resize(numverts); triangles.resize(numtris); shader.resize(numtris); smooth.resize(numtris); - attributes.reserve(numverts, numtris); + curve_keys.resize(numcurvekeys); + curves.resize(numcurves); + + attributes.reserve(); + curve_attributes.reserve(); } void Mesh::clear() @@ -77,7 +85,11 @@ void Mesh::clear() shader.clear(); smooth.clear(); + curve_keys.clear(); + curves.clear(); + attributes.clear(); + curve_attributes.clear(); used_shaders.clear(); transform_applied = false; @@ -86,24 +98,47 @@ void Mesh::clear() void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_) { - Triangle t; - t.v[0] = v0; - t.v[1] = v1; - t.v[2] = v2; + Triangle tri; + tri.v[0] = v0; + tri.v[1] = v1; + tri.v[2] = v2; - triangles.push_back(t); + triangles.push_back(tri); shader.push_back(shader_); smooth.push_back(smooth_); } +void Mesh::add_curve_key(float3 co, float radius) +{ + CurveKey key; + key.co = co; + key.radius = radius; + + curve_keys.push_back(key); +} + +void Mesh::add_curve(int first_key, int num_keys, int shader) +{ + Curve curve; + curve.first_key = first_key; + curve.num_keys = num_keys; + curve.shader = shader; + + curves.push_back(curve); +} + void Mesh::compute_bounds() { BoundBox bnds = BoundBox::empty; size_t verts_size = verts.size(); + size_t curve_keys_size = curve_keys.size(); for(size_t i = 0; i < verts_size; i++) bnds.grow(verts[i]); + for(size_t i = 0; i < curve_keys_size; i++) + bnds.grow(curve_keys[i].co, curve_keys[i].radius); + /* happens mostly on empty meshes */ if(!bnds.valid()) bnds.grow(make_float3(0.0f, 0.0f, 0.0f)); @@ -135,7 +170,12 @@ void Mesh::add_face_normals() float3 v1 = verts_ptr[t.v[1]]; float3 v2 = verts_ptr[t.v[2]]; - fN[i] = normalize(cross(v1 - v0, v2 - v0)); + float3 norm = cross(v1 - v0, v2 - v0); + float normlen = len(norm); + if(normlen == 0.0f) + fN[i] = make_float3(0.0f, 0.0f, 0.0f); + else + fN[i] = norm / normlen; if(flip) fN[i] = -fN[i]; @@ -243,6 +283,43 @@ void Mesh::pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset) } } +void Mesh::pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset) +{ + size_t curve_keys_size = curve_keys.size(); + CurveKey *keys_ptr = NULL; + + /* pack curve keys */ + if(curve_keys_size) { + keys_ptr = &curve_keys[0]; + + for(size_t i = 0; i < curve_keys_size; i++) { + float3 p = keys_ptr[i].co; + float radius = keys_ptr[i].radius; + + curve_key_co[i] = make_float4(p.x, p.y, p.z, radius); + } + } + + /* pack curve segments */ + size_t curve_num = curves.size(); + + if(curve_num) { + Curve *curve_ptr = &curves[0]; + int shader_id = 0; + + for(size_t i = 0; i < curve_num; i++) { + Curve curve = curve_ptr[i]; + shader_id = scene->shader_manager->get_shader_id(curve.shader, this, false); + + curve_data[i] = make_float4( + __int_as_float(curve.first_key + curvekey_offset), + __int_as_float(curve.num_keys), + __int_as_float(shader_id), + 0.0f); + } + } +} + void Mesh::compute_bvh(SceneParams *params, Progress *progress, int n, int total) { if(progress->get_cancel()) @@ -327,7 +404,7 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att og->attribute_map.clear(); og->object_names.clear(); - og->attribute_map.resize(scene->objects.size()); + og->attribute_map.resize(scene->objects.size()*ATTR_PRIM_TYPES); for(size_t i = 0; i < scene->objects.size(); i++) { /* set object name to object index map */ @@ -343,7 +420,8 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att osl_attr.elem = ATTR_ELEMENT_VALUE; osl_attr.value = attr; - og->attribute_map[i][attr.name()] = osl_attr; + og->attribute_map[i*ATTR_PRIM_TYPES][attr.name()] = osl_attr; + og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][attr.name()] = osl_attr; } /* find mesh attributes */ @@ -357,27 +435,46 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att /* set object attributes */ foreach(AttributeRequest& req, attributes.requests) { - if(req.element == ATTR_ELEMENT_NONE) - continue; - OSLGlobals::Attribute osl_attr; - osl_attr.elem = req.element; - osl_attr.offset = req.offset; - - if(req.type == TypeDesc::TypeFloat) - osl_attr.type = TypeDesc::TypeFloat; - else - osl_attr.type = TypeDesc::TypeColor; - - if(req.std != ATTR_STD_NONE) { - /* if standard attribute, add lookup by geom: name convention */ - ustring stdname(string("geom:") + string(attribute_standard_name(req.std))); - og->attribute_map[i][stdname] = osl_attr; + if(req.triangle_element != ATTR_ELEMENT_NONE) { + osl_attr.elem = req.triangle_element; + osl_attr.offset = req.triangle_offset; + + if(req.triangle_type == TypeDesc::TypeFloat) + osl_attr.type = TypeDesc::TypeFloat; + else + osl_attr.type = TypeDesc::TypeColor; + + if(req.std != ATTR_STD_NONE) { + /* if standard attribute, add lookup by geom: name convention */ + ustring stdname(string("geom:") + string(Attribute::standard_name(req.std))); + og->attribute_map[i*ATTR_PRIM_TYPES][stdname] = osl_attr; + } + else if(req.name != ustring()) { + /* add lookup by mesh attribute name */ + og->attribute_map[i*ATTR_PRIM_TYPES][req.name] = osl_attr; + } } - else if(req.name != ustring()) { - /* add lookup by mesh attribute name */ - og->attribute_map[i][req.name] = osl_attr; + + if(req.curve_element != ATTR_ELEMENT_NONE) { + osl_attr.elem = req.curve_element; + osl_attr.offset = req.curve_offset; + + if(req.curve_type == TypeDesc::TypeFloat) + osl_attr.type = TypeDesc::TypeFloat; + else + osl_attr.type = TypeDesc::TypeColor; + + if(req.std != ATTR_STD_NONE) { + /* if standard attribute, add lookup by geom: name convention */ + ustring stdname(string("geom:") + string(Attribute::standard_name(req.std))); + og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][stdname] = osl_attr; + } + else if(req.name != ustring()) { + /* add lookup by mesh attribute name */ + og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][req.name] = osl_attr; + } } } } @@ -393,7 +490,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()+1); + attr_map_stride = max(attr_map_stride, (mesh_attributes[i].size() + 1)*ATTR_PRIM_TYPES); if(attr_map_stride == 0) return; @@ -404,12 +501,13 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce for(size_t i = 0; i < scene->objects.size(); i++) { Object *object = scene->objects[i]; + Mesh *mesh = object->mesh; /* find mesh attributes */ size_t j; for(j = 0; j < scene->meshes.size(); j++) - if(scene->meshes[j] == object->mesh) + if(scene->meshes[j] == mesh) break; AttributeRequestSet& attributes = mesh_attributes[j]; @@ -425,14 +523,29 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce else id = scene->shader_manager->get_attribute_id(req.std); - attr_map[index].x = id; - attr_map[index].y = req.element; - attr_map[index].z = as_uint(req.offset); + if(mesh->triangles.size()) { + attr_map[index].x = id; + attr_map[index].y = req.triangle_element; + attr_map[index].z = as_uint(req.triangle_offset); - if(req.type == TypeDesc::TypeFloat) - attr_map[index].w = NODE_ATTR_FLOAT; - else - attr_map[index].w = NODE_ATTR_FLOAT3; + if(req.triangle_type == TypeDesc::TypeFloat) + attr_map[index].w = NODE_ATTR_FLOAT; + else + attr_map[index].w = NODE_ATTR_FLOAT3; + } + + index++; + + if(mesh->curves.size()) { + attr_map[index].x = id; + attr_map[index].y = req.curve_element; + attr_map[index].z = as_uint(req.curve_offset); + + if(req.curve_type == TypeDesc::TypeFloat) + attr_map[index].w = NODE_ATTR_FLOAT; + else + attr_map[index].w = NODE_ATTR_FLOAT3; + } index++; } @@ -442,6 +555,15 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce attr_map[index].y = 0; attr_map[index].z = 0; attr_map[index].w = 0; + + index++; + + attr_map[index].x = ATTR_STD_NONE; + attr_map[index].y = 0; + attr_map[index].z = 0; + attr_map[index].w = 0; + + index++; } /* copy to device */ @@ -449,6 +571,60 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce device->tex_alloc("__attributes_map", dscene->attributes_map); } +static void update_attribute_element_offset(Mesh *mesh, vector<float>& attr_float, vector<float4>& attr_float3, + Attribute *mattr, TypeDesc& type, int& offset, AttributeElement& element) +{ + if(mattr) { + /* store element and type */ + element = mattr->element; + type = mattr->type; + + /* store attribute data in arrays */ + size_t size = mattr->element_size( + mesh->verts.size(), + mesh->triangles.size(), + mesh->curves.size(), + mesh->curve_keys.size()); + + if(mattr->type == TypeDesc::TypeFloat) { + float *data = mattr->data_float(); + offset = attr_float.size(); + + attr_float.resize(attr_float.size() + size); + + for(size_t k = 0; k < size; k++) + attr_float[offset+k] = data[k]; + } + else { + float3 *data = mattr->data_float3(); + offset = attr_float3.size(); + + attr_float3.resize(attr_float3.size() + size); + + for(size_t k = 0; k < size; k++) + attr_float3[offset+k] = float3_to_float4(data[k]); + } + + /* mesh vertex/curve index is global, not per object, so we sneak + * a correction for that in here */ + if(element == ATTR_ELEMENT_VERTEX) + offset -= mesh->vert_offset; + else if(element == ATTR_ELEMENT_FACE) + offset -= mesh->tri_offset; + else if(element == ATTR_ELEMENT_CORNER) + offset -= 3*mesh->tri_offset; + else if(element == ATTR_ELEMENT_CURVE) + offset -= mesh->curve_offset; + else if(element == ATTR_ELEMENT_CURVE_KEY) + offset -= mesh->curvekey_offset; + } + else { + /* attribute not found */ + element = ATTR_ELEMENT_NONE; + offset = 0; + } +} + void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) { progress.set_status("Updating Mesh", "Computing attributes"); @@ -482,66 +658,24 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, /* todo: we now store std and name attributes from requests even if * they actually refer to the same mesh attributes, optimize */ foreach(AttributeRequest& req, attributes.requests) { - Attribute *mattr = mesh->attributes.find(req); - - /* todo: get rid of this exception */ - if(!mattr && req.std == ATTR_STD_GENERATED) { - mattr = mesh->attributes.add(ATTR_STD_GENERATED); + Attribute *triangle_mattr = mesh->attributes.find(req); + Attribute *curve_mattr = mesh->curve_attributes.find(req); + + /* todo: get rid of this exception, it's only here for giving some + * working texture coordinate for subdivision as we can't preserve + * any attributes yet */ + if(!triangle_mattr && req.std == ATTR_STD_GENERATED) { + triangle_mattr = mesh->attributes.add(ATTR_STD_GENERATED); if(mesh->verts.size()) - memcpy(mattr->data_float3(), &mesh->verts[0], sizeof(float3)*mesh->verts.size()); + memcpy(triangle_mattr->data_float3(), &mesh->verts[0], sizeof(float3)*mesh->verts.size()); } - /* attribute not found */ - if(!mattr) { - req.element = ATTR_ELEMENT_NONE; - req.offset = 0; - continue; - } - - /* we abuse AttributeRequest to pass on info like element and - * offset, it doesn't really make sense but is convenient */ - - /* store element and type */ - if(mattr->element == Attribute::VERTEX) - req.element = ATTR_ELEMENT_VERTEX; - else if(mattr->element == Attribute::FACE) - req.element = ATTR_ELEMENT_FACE; - else if(mattr->element == Attribute::CORNER) - req.element = ATTR_ELEMENT_CORNER; - - req.type = mattr->type; - - /* store attribute data in arrays */ - size_t size = mattr->element_size(mesh->verts.size(), mesh->triangles.size()); - - if(mattr->type == TypeDesc::TypeFloat) { - 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[req.offset+k] = data[k]; - } - else { - float3 *data = mattr->data_float3(); - req.offset = attr_float3.size(); - - attr_float3.resize(attr_float3.size() + size); - - 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 - * a correction for that in here */ - if(req.element == ATTR_ELEMENT_VERTEX) - req.offset -= mesh->vert_offset; - else if(mattr->element == Attribute::FACE) - req.offset -= mesh->tri_offset; - else if(mattr->element == Attribute::CORNER) - req.offset -= 3*mesh->tri_offset; + update_attribute_element_offset(mesh, attr_float, attr_float3, triangle_mattr, + req.triangle_type, req.triangle_offset, req.triangle_element); + update_attribute_element_offset(mesh, attr_float, attr_float3, curve_mattr, + req.curve_type, req.curve_offset, req.curve_element); + if(progress.get_cancel()) return; } } @@ -573,39 +707,62 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene size_t vert_size = 0; size_t tri_size = 0; + size_t curve_key_size = 0; + size_t curve_size = 0; + foreach(Mesh *mesh, scene->meshes) { mesh->vert_offset = vert_size; mesh->tri_offset = tri_size; + mesh->curvekey_offset = curve_key_size; + mesh->curve_offset = curve_size; + vert_size += mesh->verts.size(); tri_size += mesh->triangles.size(); + + curve_key_size += mesh->curve_keys.size(); + curve_size += mesh->curves.size(); } - if(tri_size == 0) - return; + if(tri_size != 0) { + /* normals */ + progress.set_status("Updating Mesh", "Computing normals"); - /* normals */ - progress.set_status("Updating Mesh", "Computing normals"); + float4 *normal = dscene->tri_normal.resize(tri_size); + float4 *vnormal = dscene->tri_vnormal.resize(vert_size); + float4 *tri_verts = dscene->tri_verts.resize(vert_size); + float4 *tri_vindex = dscene->tri_vindex.resize(tri_size); - float4 *normal = dscene->tri_normal.resize(tri_size); - float4 *vnormal = dscene->tri_vnormal.resize(vert_size); - float4 *tri_verts = dscene->tri_verts.resize(vert_size); - float4 *tri_vindex = dscene->tri_vindex.resize(tri_size); + foreach(Mesh *mesh, scene->meshes) { + mesh->pack_normals(scene, &normal[mesh->tri_offset], &vnormal[mesh->vert_offset]); + mesh->pack_verts(&tri_verts[mesh->vert_offset], &tri_vindex[mesh->tri_offset], mesh->vert_offset); - foreach(Mesh *mesh, scene->meshes) { - mesh->pack_normals(scene, &normal[mesh->tri_offset], &vnormal[mesh->vert_offset]); - mesh->pack_verts(&tri_verts[mesh->vert_offset], &tri_vindex[mesh->tri_offset], mesh->vert_offset); + if(progress.get_cancel()) return; + } - if(progress.get_cancel()) return; + /* vertex coordinates */ + progress.set_status("Updating Mesh", "Copying Mesh to device"); + + device->tex_alloc("__tri_normal", dscene->tri_normal); + device->tex_alloc("__tri_vnormal", dscene->tri_vnormal); + device->tex_alloc("__tri_verts", dscene->tri_verts); + device->tex_alloc("__tri_vindex", dscene->tri_vindex); } - /* vertex coordinates */ - progress.set_status("Updating Mesh", "Copying Mesh to device"); + if(curve_size != 0) { + progress.set_status("Updating Mesh", "Copying Strands to device"); + + float4 *curve_keys = dscene->curve_keys.resize(curve_key_size); + float4 *curves = dscene->curves.resize(curve_size); - device->tex_alloc("__tri_normal", dscene->tri_normal); - device->tex_alloc("__tri_vnormal", dscene->tri_vnormal); - device->tex_alloc("__tri_verts", dscene->tri_verts); - device->tex_alloc("__tri_vindex", dscene->tri_vindex); + foreach(Mesh *mesh, scene->meshes) { + mesh->pack_curves(scene, &curve_keys[mesh->curvekey_offset], &curves[mesh->curve_offset], mesh->curvekey_offset); + if(progress.get_cancel()) return; + } + + device->tex_alloc("__curve_keys", dscene->curve_keys); + device->tex_alloc("__curves", dscene->curves); + } } void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) @@ -642,6 +799,10 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene * dscene->tri_woop.reference(&pack.tri_woop[0], pack.tri_woop.size()); device->tex_alloc("__tri_woop", dscene->tri_woop); } + if(pack.prim_segment.size()) { + dscene->prim_segment.reference((uint*)&pack.prim_segment[0], pack.prim_segment.size()); + device->tex_alloc("__prim_segment", dscene->prim_segment); + } if(pack.prim_visibility.size()) { dscene->prim_visibility.reference((uint*)&pack.prim_visibility[0], pack.prim_visibility.size()); device->tex_alloc("__prim_visibility", dscene->prim_visibility); @@ -751,6 +912,7 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) device->tex_free(dscene->bvh_nodes); device->tex_free(dscene->object_node); device->tex_free(dscene->tri_woop); + device->tex_free(dscene->prim_segment); device->tex_free(dscene->prim_visibility); device->tex_free(dscene->prim_index); device->tex_free(dscene->prim_object); @@ -758,6 +920,8 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) device->tex_free(dscene->tri_vnormal); device->tex_free(dscene->tri_vindex); device->tex_free(dscene->tri_verts); + device->tex_free(dscene->curves); + device->tex_free(dscene->curve_keys); device->tex_free(dscene->attributes_map); device->tex_free(dscene->attributes_float); device->tex_free(dscene->attributes_float3); @@ -765,6 +929,7 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) dscene->bvh_nodes.clear(); dscene->object_node.clear(); dscene->tri_woop.clear(); + dscene->prim_segment.clear(); dscene->prim_visibility.clear(); dscene->prim_index.clear(); dscene->prim_object.clear(); @@ -772,6 +937,8 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) dscene->tri_vnormal.clear(); dscene->tri_vindex.clear(); dscene->tri_verts.clear(); + dscene->curves.clear(); + dscene->curve_keys.clear(); dscene->attributes_map.clear(); dscene->attributes_float.clear(); dscene->attributes_float3.clear(); diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h index 637143f5adf..b83752ad8df 100644 --- a/intern/cycles/render/mesh.h +++ b/intern/cycles/render/mesh.h @@ -50,6 +50,21 @@ public: int v[3]; }; + /* Mesh Curve */ + struct Curve { + int first_key; + int num_keys; + uint shader; + uint pad; + + int num_segments() { return num_keys - 1; } + }; + + struct CurveKey { + float3 co; + float radius; + }; + /* Displacement */ enum DisplacementMethod { DISPLACE_BUMP, @@ -65,8 +80,12 @@ public: vector<uint> shader; vector<bool> smooth; + vector<CurveKey> curve_keys; + vector<Curve> curves; + vector<uint> used_shaders; AttributeSet attributes; + AttributeSet curve_attributes; BoundBox bounds; bool transform_applied; @@ -82,13 +101,18 @@ public: size_t tri_offset; size_t vert_offset; + size_t curve_offset; + size_t curvekey_offset; + /* Functions */ Mesh(); ~Mesh(); - void reserve(int numverts, int numfaces); + void reserve(int numverts, int numfaces, int numcurves, int numcurvekeys); void clear(); void add_triangle(int v0, int v1, int v2, int shader, bool smooth); + void add_curve_key(float3 loc, float radius); + void add_curve(int first_key, int num_keys, int shader); void compute_bounds(); void add_face_normals(); @@ -96,6 +120,7 @@ public: void pack_normals(Scene *scene, float4 *normal, float4 *vnormal); void pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset); + void pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset); void compute_bvh(SceneParams *params, Progress *progress, int n, int total); bool need_attribute(Scene *scene, AttributeStandard std); diff --git a/intern/cycles/render/mesh_displace.cpp b/intern/cycles/render/mesh_displace.cpp index dea694a811e..04267697b29 100644 --- a/intern/cycles/render/mesh_displace.cpp +++ b/intern/cycles/render/mesh_displace.cpp @@ -19,6 +19,7 @@ #include "device.h" #include "mesh.h" +#include "object.h" #include "scene.h" #include "shader.h" @@ -41,11 +42,24 @@ bool MeshManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress& p if(!has_displacement) return false; + string msg = string_printf("Computing Displacement %s", mesh->name.c_str()); + progress.set_status("Updating Mesh", msg); + + /* find object index. todo: is arbitrary */ + size_t object_index = ~0; + + for(size_t i = 0; i < scene->objects.size(); i++) { + if(scene->objects[i]->mesh == mesh) { + object_index = i; + break; + } + } + /* setup input for device task */ vector<bool> done(mesh->verts.size(), false); device_vector<uint4> d_input; uint4 *d_input_data = d_input.resize(mesh->verts.size()); - size_t d_input_offset = 0; + size_t d_input_size = 0; for(size_t i = 0; i < mesh->triangles.size(); i++) { Mesh::Triangle t = mesh->triangles[i]; @@ -61,8 +75,8 @@ bool MeshManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress& p done[t.v[j]] = true; /* set up object, primitive and barycentric coordinates */ - /* when used, non-instanced convention: object = -object-1; */ - int object = ~0; /* todo */ + /* when used, non-instanced convention: object = ~object */ + int object = ~object_index; int prim = mesh->tri_offset + i; float u, v; @@ -81,16 +95,16 @@ bool MeshManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress& p /* back */ uint4 in = make_uint4(object, prim, __float_as_int(u), __float_as_int(v)); - d_input_data[d_input_offset++] = in; + d_input_data[d_input_size++] = in; } } - if(d_input_offset == 0) + if(d_input_size == 0) return false; /* run device task */ device_vector<float4> d_output; - d_output.resize(d_input.size()); + d_output.resize(d_input_size); device->mem_alloc(d_input, MEM_READ_ONLY); device->mem_copy_to(d_input); @@ -101,7 +115,7 @@ bool MeshManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress& p task.shader_output = d_output.device_pointer; task.shader_eval_type = SHADER_EVAL_DISPLACE; task.shader_x = 0; - task.shader_w = d_input.size(); + task.shader_w = d_output.size(); device->task_add(task); device->task_wait(); diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index aef28449e44..14ef3c68ad3 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -2240,6 +2240,63 @@ void ParticleInfoNode::compile(OSLCompiler& compiler) compiler.add(this, "node_particle_info"); } +/* Hair Info */ + +HairInfoNode::HairInfoNode() +: ShaderNode("hair_info") +{ + add_output("Is Strand", SHADER_SOCKET_FLOAT); + add_output("Intercept", SHADER_SOCKET_FLOAT); + add_output("Thickness", SHADER_SOCKET_FLOAT); + add_output("Tangent Normal", SHADER_SOCKET_NORMAL); +} + +void HairInfoNode::attributes(AttributeRequestSet *attributes) +{ + ShaderOutput *intercept_out = output("Intercept"); + + if(!intercept_out->links.empty()) + attributes->add(ATTR_STD_CURVE_INTERCEPT); + + ShaderNode::attributes(attributes); +} + +void HairInfoNode::compile(SVMCompiler& compiler) +{ + ShaderOutput *out; + + out = output("Is Strand"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_IS_STRAND, out->stack_offset); + } + + out = output("Intercept"); + if(!out->links.empty()) { + int attr = compiler.attribute(ATTR_STD_CURVE_INTERCEPT); + compiler.stack_assign(out); + compiler.add_node(NODE_ATTR, attr, out->stack_offset, NODE_ATTR_FLOAT); + } + + out = output("Thickness"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_THICKNESS, out->stack_offset); + } + + out = output("Tangent Normal"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_TANGENT_NORMAL, out->stack_offset); + } + +} + +void HairInfoNode::compile(OSLCompiler& compiler) +{ + compiler.add(this, "node_hair_info"); +} + /* Value */ ValueNode::ValueNode() diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 8012a99ff05..564ceee5a5b 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -331,6 +331,13 @@ public: void attributes(AttributeRequestSet *attributes); }; +class HairInfoNode : public ShaderNode { +public: + SHADER_NODE_CLASS(HairInfoNode) + + void attributes(AttributeRequestSet *attributes); +}; + class ValueNode : public ShaderNode { public: SHADER_NODE_CLASS(ValueNode) diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index 5df8e8c1368..a89f8afd251 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -19,6 +19,7 @@ #include "device.h" #include "light.h" #include "mesh.h" +#include "curves.h" #include "object.h" #include "scene.h" @@ -45,6 +46,7 @@ Object::Object() motion.post = transform_identity(); use_motion = false; use_holdout = false; + curverender = false; } Object::~Object() @@ -86,6 +88,10 @@ void Object::apply_transform() for(size_t i = 0; i < mesh->verts.size(); i++) mesh->verts[i] = transform_point(&tfm, mesh->verts[i]); + for(size_t i = 0; i < mesh->curve_keys.size(); i++) + mesh->curve_keys[i].co = transform_point(&tfm, mesh->curve_keys[i].co); + + Attribute *attr_tangent = mesh->curve_attributes.find(ATTR_STD_CURVE_TANGENT); Attribute *attr_fN = mesh->attributes.find(ATTR_STD_FACE_NORMAL); Attribute *attr_vN = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL); @@ -110,6 +116,13 @@ void Object::apply_transform() vN[i] = transform_direction(&ntfm, vN[i]); } + if(attr_tangent) { + float3 *tangent = attr_tangent->data_float3(); + + for(size_t i = 0; i < mesh->curve_keys.size(); i++) + tangent[i] = transform_direction(&tfm, tangent[i]); + } + if(bounds.valid()) { mesh->compute_bounds(); compute_bounds(false, 0.0f); @@ -133,6 +146,7 @@ void Object::tag_update(Scene *scene) } } + scene->curve_system_manager->need_update = true; scene->mesh_manager->need_update = true; scene->object_manager->need_update = true; } @@ -189,6 +203,20 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene surface_area += triangle_area(p1, p2, p3); } + foreach(Mesh::Curve& curve, mesh->curves) { + int first_key = curve.first_key; + + for(int i = 0; i < curve.num_segments(); i++) { + float3 p1 = mesh->curve_keys[first_key + i].co; + float r1 = mesh->curve_keys[first_key + i].radius; + float3 p2 = mesh->curve_keys[first_key + i + 1].co; + float r2 = mesh->curve_keys[first_key + i + 1].radius; + + /* currently ignores segment overlaps*/ + surface_area += M_PI_F *(r1 + r2) * len(p1 - p2); + } + } + surface_area_map[mesh] = surface_area; } else @@ -204,6 +232,23 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene surface_area += triangle_area(p1, p2, p3); } + + foreach(Mesh::Curve& curve, mesh->curves) { + int first_key = curve.first_key; + + for(int i = 0; i < curve.num_segments(); i++) { + float3 p1 = mesh->curve_keys[first_key + i].co; + float r1 = mesh->curve_keys[first_key + i].radius; + float3 p2 = mesh->curve_keys[first_key + i + 1].co; + float r2 = mesh->curve_keys[first_key + i + 1].radius; + + p1 = transform_point(&tfm, p1); + p2 = transform_point(&tfm, p2); + + /* currently ignores segment overlaps*/ + surface_area += M_PI_F *(r1 + r2) * len(p1 - p2); + } + } } /* pack in texture */ @@ -355,6 +400,7 @@ void ObjectManager::apply_static_transforms(Scene *scene, uint *object_flag, Pro void ObjectManager::tag_update(Scene *scene) { need_update = true; + scene->curve_system_manager->need_update = true; scene->mesh_manager->need_update = true; scene->light_manager->need_update = true; } diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h index 9c9b11bc29c..9ba500ca4d6 100644 --- a/intern/cycles/render/object.h +++ b/intern/cycles/render/object.h @@ -48,6 +48,7 @@ public: MotionTransform motion; bool use_motion; bool use_holdout; + bool curverender; float3 dupli_generated; float2 dupli_uv; diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 8085cfdd3e6..093bfecf88e 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -29,6 +29,7 @@ #include "mesh.h" #include "object.h" #include "particles.h" +#include "curves.h" #include "scene.h" #include "svm.h" #include "osl.h" @@ -54,6 +55,7 @@ Scene::Scene(const SceneParams& params_, const DeviceInfo& device_info_) integrator = new Integrator(); image_manager = new ImageManager(); particle_system_manager = new ParticleSystemManager(); + curve_system_manager = new CurveSystemManager(); /* OSL only works on the CPU */ if(device_info_.type == DEVICE_CPU) @@ -96,6 +98,7 @@ void Scene::free_memory(bool final) light_manager->device_free(device, &dscene); particle_system_manager->device_free(device, &dscene); + curve_system_manager->device_free(device, &dscene); if(!params.persistent_images || final) image_manager->device_free(device, &dscene); @@ -112,6 +115,7 @@ void Scene::free_memory(bool final) delete shader_manager; delete light_manager; delete particle_system_manager; + delete curve_system_manager; delete image_manager; } else { @@ -165,6 +169,11 @@ void Scene::device_update(Device *device_, Progress& progress) if(progress.get_cancel()) return; + progress.set_status("Updating Hair Systems"); + curve_system_manager->device_update(device, &dscene, this, progress); + + if(progress.get_cancel()) return; + progress.set_status("Updating Meshes"); mesh_manager->device_update(device, &dscene, this, progress); @@ -242,7 +251,8 @@ bool Scene::need_reset() || filter->need_update || integrator->need_update || shader_manager->need_update - || particle_system_manager->need_update); + || particle_system_manager->need_update + || curve_system_manager->need_update); } void Scene::reset() diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index ebe932e40e7..f6e1daea80d 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -25,7 +25,6 @@ #include "kernel_types.h" -#include "util_attribute.h" #include "util_param.h" #include "util_string.h" #include "util_thread.h" @@ -50,6 +49,7 @@ class Object; class ObjectManager; class ParticleSystemManager; class ParticleSystem; +class CurveSystemManager; class Shader; class ShaderManager; class Progress; @@ -62,6 +62,7 @@ public: device_vector<float4> bvh_nodes; device_vector<uint> object_node; device_vector<float4> tri_woop; + device_vector<uint> prim_segment; device_vector<uint> prim_visibility; device_vector<uint> prim_index; device_vector<uint> prim_object; @@ -72,6 +73,9 @@ public: device_vector<float4> tri_vindex; device_vector<float4> tri_verts; + device_vector<float4> curves; + device_vector<float4> curve_keys; + /* objects */ device_vector<float4> objects; device_vector<float4> objects_vector; @@ -170,6 +174,7 @@ public: MeshManager *mesh_manager; ObjectManager *object_manager; ParticleSystemManager *particle_system_manager; + CurveSystemManager *curve_system_manager; /* default shaders */ int default_surface; diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 1d1a3d54893..36948adce17 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -357,7 +357,7 @@ bool Session::acquire_tile(Device *tile_device, RenderTile& rtile) tile_lock.unlock(); - /* in case of a permant buffer, return it, otherwise we will allocate + /* in case of a permanent buffer, return it, otherwise we will allocate * a new temporary buffer */ if(!params.background) { tile_manager.state.buffer.get_offset_stride(rtile.offset, rtile.stride); @@ -411,6 +411,12 @@ bool Session::acquire_tile(Device *tile_device, RenderTile& rtile) rtile.rgba = 0; rtile.buffers = tilebuffers; + /* this will tag tile as IN PROGRESS in blender-side render pipeline, + * which is needed to highlight currently rendering tile before first + * sample was processed for it + */ + update_tile_sample(rtile); + return true; } diff --git a/intern/cycles/subd/subd_dice.cpp b/intern/cycles/subd/subd_dice.cpp index 6920df9954c..48e6808bc38 100644 --- a/intern/cycles/subd/subd_dice.cpp +++ b/intern/cycles/subd/subd_dice.cpp @@ -47,7 +47,7 @@ void EdgeDice::reserve(int num_verts, int num_tris) vert_offset = mesh->verts.size(); tri_offset = mesh->triangles.size(); - mesh->reserve(vert_offset + num_verts, tri_offset + num_tris); + mesh->reserve(vert_offset + num_verts, tri_offset + num_tris, 0, 0); Attribute *attr_vN = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL); diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt index dce417704cc..bcaaa9a71b9 100644 --- a/intern/cycles/util/CMakeLists.txt +++ b/intern/cycles/util/CMakeLists.txt @@ -9,7 +9,6 @@ set(INC_SYS ) set(SRC - util_attribute.cpp util_cache.cpp util_cuda.cpp util_dynlib.cpp @@ -33,7 +32,6 @@ endif() set(SRC_HEADERS util_algorithm.h util_args.h - util_attribute.h util_boundbox.h util_cache.h util_cuda.h diff --git a/intern/cycles/util/util_attribute.cpp b/intern/cycles/util/util_attribute.cpp deleted file mode 100644 index 057fb6213e9..00000000000 --- a/intern/cycles/util/util_attribute.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "util_attribute.h" - -CCL_NAMESPACE_BEGIN - -const char *attribute_standard_name(AttributeStandard std) -{ - if(std == ATTR_STD_VERTEX_NORMAL) - return "N"; - else if(std == ATTR_STD_FACE_NORMAL) - return "Ng"; - else if(std == ATTR_STD_UV) - return "uv"; - else if(std == ATTR_STD_GENERATED) - return "generated"; - else if(std == ATTR_STD_UV_TANGENT) - return "tangent"; - else if(std == ATTR_STD_UV_TANGENT_SIGN) - return "tangent_sign"; - else if(std == ATTR_STD_POSITION_UNDEFORMED) - return "undeformed"; - else if(std == ATTR_STD_POSITION_UNDISPLACED) - return "undisplaced"; - else if(std == ATTR_STD_MOTION_PRE) - return "motion_pre"; - else if(std == ATTR_STD_MOTION_POST) - return "motion_post"; - else if(std == ATTR_STD_PARTICLE) - return "particle"; - - return ""; -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_boundbox.h b/intern/cycles/util/util_boundbox.h index 6dd1c6c71e8..0c857f906ee 100644 --- a/intern/cycles/util/util_boundbox.h +++ b/intern/cycles/util/util_boundbox.h @@ -65,6 +65,13 @@ public: max = ccl::max(max, pt); } + __forceinline void grow(const float3& pt, float border) + { + float3 shift = {border, border, border, 0.0f}; + min = ccl::min(min, pt - shift); + max = ccl::max(max, pt + shift); + } + __forceinline void grow(const BoundBox& bbox) { grow(bbox.min); diff --git a/intern/cycles/util/util_types.h b/intern/cycles/util/util_types.h index 00b6cf5c56e..bb6de1197e7 100644 --- a/intern/cycles/util/util_types.h +++ b/intern/cycles/util/util_types.h @@ -448,24 +448,6 @@ __device_inline int4 make_int4(const float3& f) #endif -typedef enum AttributeStandard { - ATTR_STD_NONE = 0, - ATTR_STD_VERTEX_NORMAL, - ATTR_STD_FACE_NORMAL, - ATTR_STD_UV, - ATTR_STD_UV_TANGENT, - ATTR_STD_UV_TANGENT_SIGN, - ATTR_STD_GENERATED, - ATTR_STD_POSITION_UNDEFORMED, - ATTR_STD_POSITION_UNDISPLACED, - ATTR_STD_MOTION_PRE, - ATTR_STD_MOTION_POST, - ATTR_STD_PARTICLE, - ATTR_STD_NUM, - - ATTR_STD_NOT_FOUND = ~0 -} AttributeStandard; - CCL_NAMESPACE_END #endif /* __UTIL_TYPES_H__ */ diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index 39fd038d568..2d9d89d9ad0 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -1579,7 +1579,13 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) case NSScrollWheel: { - if (!m_hasMultiTouchTrackpad) { + int momentum = 0; +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 + m_hasMultiTouchTrackpad = 0; + momentum = [event momentumPhase] || [event phase]; +#endif + /* standard scrollwheel case */ + if (!m_hasMultiTouchTrackpad && momentum == 0) { GHOST_TInt32 delta; double deltaF = [event deltaY]; @@ -1593,9 +1599,18 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) else { NSPoint mousePos = [cocoawindow mouseLocationOutsideOfEventStream]; GHOST_TInt32 x, y; - double dx = [event deltaX]; - double dy = -[event deltaY]; + double dx; + double dy; +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 + /* with 10.7 nice scrolling deltas are supported */ + dx = [event scrollingDeltaX]; + dy = [event scrollingDeltaY]; + +#else + /* trying to pretend you have nice scrolls... */ + dx = [event deltaX]; + dy = -[event deltaY]; const double deltaMax = 50.0; if ((dx == 0) && (dy == 0)) break; @@ -1612,9 +1627,10 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) else dy += 0.5; if (dy < -deltaMax) dy= -deltaMax; else if (dy > deltaMax) dy= deltaMax; - - window->clientToScreenIntern(mousePos.x, mousePos.y, x, y); + dy = -dy; +#endif + window->clientToScreenIntern(mousePos.x, mousePos.y, x, y); pushEvent(new GHOST_EventTrackpad([event timestamp] * 1000, window, GHOST_kTrackpadEventScroll, x, y, dx, dy)); } diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm index 471505538ba..2d58f0612ce 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.mm +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -595,6 +595,11 @@ GHOST_WindowCocoa::GHOST_WindowCocoa( [m_window setAcceptsMouseMovedEvents:YES]; +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 + NSView *view = [m_window contentView]; + [view setAcceptsTouchEvents:YES]; +#endif + [m_window registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, NSStringPboardType, NSTIFFPboardType, nil]]; diff --git a/intern/locale/boost_locale_wrapper.cpp b/intern/locale/boost_locale_wrapper.cpp index 939c66bad13..80e75298d70 100644 --- a/intern/locale/boost_locale_wrapper.cpp +++ b/intern/locale/boost_locale_wrapper.cpp @@ -55,44 +55,49 @@ void bl_locale_set(const char *locale) // Specify location of dictionaries. gen.add_messages_path(messages_path); gen.add_messages_domain(default_domain); - //gen.set_default_messages_domain(default_domain); + //gen.set_default_messages_domain(default_domain); - if (locale && locale[0]) { - std::locale::global(gen(locale)); - } - else { -#if defined (__APPLE__) - // workaround to get osx system locale from user defaults - FILE* fp; - std::string locale_osx = ""; - char result[16]; - int result_len = 0; + try { + if (locale && locale[0]) { + std::locale::global(gen(locale)); + } + else { +#ifdef __APPLE__ + // workaround to get osx system locale from user defaults + FILE *fp; + std::string locale_osx = ""; + char result[16]; + int result_len = 0; - fp = popen("defaults read .GlobalPreferences AppleLocale", "r"); + fp = popen("defaults read .GlobalPreferences AppleLocale", "r"); - if(fp) { - result_len = fread(result, 1, sizeof(result) - 1, fp); + if (fp) { + result_len = fread(result, 1, sizeof(result) - 1, fp); - if(result_len > 0) { - result[result_len-1] = '\0'; // \0 terminate and remove \n - locale_osx = std::string(result) + std::string(".UTF-8"); - } + if (result_len > 0) { + result[result_len - 1] = '\0'; // \0 terminate and remove \n + locale_osx = std::string(result) + std::string(".UTF-8"); + } - pclose(fp); - } + pclose(fp); + } - if(locale_osx == "") - fprintf(stderr, "Locale set: failed to read AppleLocale read from defaults\n"); + if (locale_osx == "") + fprintf(stderr, "Locale set: failed to read AppleLocale read from defaults\n"); - std::locale::global(gen(locale_osx.c_str())); + std::locale::global(gen(locale_osx.c_str())); #else - std::locale::global(gen("")); + std::locale::global(gen("")); #endif + } + // Note: boost always uses "C" LC_NUMERIC by default! + } + catch(std::exception const &e) { + std::cout << "bl_locale_set(" << locale << "): " << e.what() << " \n"; } - // Note: boost always uses "C" LC_NUMERIC by default! } -const char* bl_locale_pgettext(const char *msgctxt, const char *msgid) +const char *bl_locale_pgettext(const char *msgctxt, const char *msgid) { // Note: We cannot use short stuff like boost::locale::gettext, because those return // std::basic_string objects, which c_ptr()-returned char* is no more valid @@ -107,7 +112,7 @@ const char* bl_locale_pgettext(const char *msgctxt, const char *msgid) return msgid; } catch(std::exception const &e) { -// std::cout << "boost_locale_pgettext: " << e.what() << " \n"; +// std::cout << "bl_locale_pgettext(" << msgctxt << ", " << msgid << "): " << e.what() << " \n"; return msgid; } } diff --git a/intern/smoke/CMakeLists.txt b/intern/smoke/CMakeLists.txt index 3b8a4c06e69..b6338f90ebc 100644 --- a/intern/smoke/CMakeLists.txt +++ b/intern/smoke/CMakeLists.txt @@ -29,7 +29,7 @@ set(INC ) set(INC_SYS - ../../extern/bullet2/src + ${BULLET_INCLUDE_DIRS} ${PNG_INCLUDE_DIR} ${ZLIB_INCLUDE_DIRS} ) |