From e9ba345c46c93a193193f01d4bfac714a666d384 Mon Sep 17 00:00:00 2001 From: Stuart Broadfoot Date: Fri, 28 Dec 2012 14:21:30 +0000 Subject: New feature Patch [#33445] - Experimental Cycles Hair Rendering (CPU only) This patch allows hair data to be exported to cycles and introduces a new line segment primitive to render with. The UI appears under the particle tab and there is a new hair info node available. It is only available under the experimental feature set and for cpu rendering. --- intern/cycles/blender/CMakeLists.txt | 1 + intern/cycles/blender/addon/properties.py | 188 +++++++ intern/cycles/blender/addon/ui.py | 88 +++ intern/cycles/blender/blender_curves.cpp | 898 ++++++++++++++++++++++++++++++ intern/cycles/blender/blender_mesh.cpp | 25 +- intern/cycles/blender/blender_object.cpp | 26 +- intern/cycles/blender/blender_session.cpp | 4 +- intern/cycles/blender/blender_shader.cpp | 4 + intern/cycles/blender/blender_sync.cpp | 5 +- intern/cycles/blender/blender_sync.h | 9 +- intern/cycles/bvh/bvh.cpp | 132 ++++- intern/cycles/bvh/bvh.h | 9 +- intern/cycles/bvh/bvh_build.cpp | 37 +- intern/cycles/bvh/bvh_build.h | 2 + intern/cycles/bvh/bvh_params.h | 5 +- intern/cycles/bvh/bvh_sort.cpp | 2 + intern/cycles/bvh/bvh_split.cpp | 55 +- intern/cycles/kernel/kernel_bvh.h | 267 ++++++++- intern/cycles/kernel/kernel_emission.h | 12 +- intern/cycles/kernel/kernel_light.h | 64 ++- intern/cycles/kernel/kernel_object.h | 50 ++ intern/cycles/kernel/kernel_shader.h | 115 +++- intern/cycles/kernel/kernel_textures.h | 5 + intern/cycles/kernel/kernel_triangle.h | 176 +++--- intern/cycles/kernel/kernel_types.h | 34 +- intern/cycles/kernel/svm/svm.h | 6 + intern/cycles/kernel/svm/svm_attribute.h | 144 +++-- intern/cycles/kernel/svm/svm_geometry.h | 38 +- intern/cycles/kernel/svm/svm_tex_coord.h | 14 +- intern/cycles/kernel/svm/svm_types.h | 10 +- intern/cycles/render/CMakeLists.txt | 2 + intern/cycles/render/curves.cpp | 160 ++++++ intern/cycles/render/curves.h | 134 +++++ intern/cycles/render/light.cpp | 37 +- intern/cycles/render/mesh.cpp | 151 ++++- intern/cycles/render/mesh.h | 34 ++ intern/cycles/render/nodes.cpp | 46 ++ intern/cycles/render/nodes.h | 5 + intern/cycles/render/object.cpp | 31 ++ intern/cycles/render/object.h | 1 + intern/cycles/render/scene.cpp | 12 +- intern/cycles/render/scene.h | 6 + intern/cycles/util/util_boundbox.h | 7 + 43 files changed, 2803 insertions(+), 248 deletions(-) create mode 100644 intern/cycles/blender/blender_curves.cpp create mode 100644 intern/cycles/render/curves.cpp create mode 100644 intern/cycles/render/curves.h (limited to 'intern/cycles') 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/properties.py b/intern/cycles/blender/addon/properties.py index 26fc7a81936..35ea8501eb7 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -63,6 +63,38 @@ enum_panorama_types = ( ('FISHEYE_EQUISOLID', "Fisheye Equisolid", "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"), + ('TESSELATED', "Tesselated", "create mesh surrounding each strand"), + ) + +enum_line_curves = ( + ('ACCURATE', "Accurate", "always take into consideration strand width for intersections"), + ('QT_CORRECTED', "corrected", "ignores width for initial intersection and corrects later"), + ('ENDCORRECTED', "correct found", "ignores width for all intersections and only corrects closest"), + ('QT_UNCORRECTED', "uncorrected", "calculates intersection without considering width"), + ) + +enum_curves_interpolation = ( + ('LINEAR', "Linear interpolation", "uses Linear interpolation between segments"), + ('CARDINAL', "Cardinal interpolation", "uses CARDINAL interpolation between segments"), + ('BSPLINE', "b-spline interpolation", "uses b-spline interpolation between segments"), + ) class CyclesRenderSettings(bpy.types.PropertyGroup): @classmethod @@ -573,6 +605,158 @@ 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="Tests back-faces of strands", + default=False, + ) + cls.use_encasing = BoolProperty( + name="Exclude encasing", + description="Ignores strands encasing a ray's initial location", + default=True, + ) + cls.use_tangent_normal_geometry = BoolProperty( + name="Tangent normal geometry", + description="Uses the tangent normal for actual normal", + default=False, + ) + cls.use_tangent_normal = BoolProperty( + name="Tangent normal default", + description="Uses the tangent normal for all normals", + default=False, + ) + cls.use_tangent_normal_correction = BoolProperty( + name="strand slope correction", + description="Corrects the tangent normal for the strands slope", + default=False, + ) + cls.use_cache = BoolProperty( + name="Export Cached data", + description="Export cached data with child strands (uses 'draw step' for subdivisions)", + 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="Fills 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="Sets tip radius to zero", + default=True, + ) + + @classmethod + def unregister(cls): + del bpy.types.ParticleSettings.cycles def register(): bpy.utils.register_class(CyclesRenderSettings) @@ -582,6 +766,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 +778,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 86a1ab3c3e0..5253f5789ec 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -944,7 +944,95 @@ class CyclesParticle_PT_textures(CyclesButtonsPanel, Panel): else: slot = part.texture_slots[part.active_texture_index] layout.template_ID(slot, "texture", new="texture.new") + +class CyclesParticle_PT_CurveSettings(CyclesButtonsPanel, Panel): + bl_label = "Cycles Hair Settings" + bl_context = "particle" + + @classmethod + def poll(cls, context): + psys = context.particle_system + device_type = context.user_preferences.system.compute_device_type + if context.scene.cycles.feature_set == 'EXPERIMENTAL' and (context.scene.cycles.device == 'CPU' or device_type == 'NONE'): + if CyclesButtonsPanel.poll(context) and psys: + return True + + return False + + 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") + row = layout.row() + row.prop(cpsys, "root_width", text="Root Width multiplier") + row = layout.row() + row.prop(cpsys, "tip_width", text="Tip Width multiplier") + +class CyclesRender_PT_CurveRendering(CyclesButtonsPanel, Panel): + bl_label = "Cycles Hair Rendering" + bl_context = "particle" + + @classmethod + def poll(cls, context): + device_type = context.user_preferences.system.compute_device_type + if CyclesButtonsPanel.poll(context): + if context.scene.cycles.feature_set == 'EXPERIMENTAL' and (context.scene.cycles.device == 'CPU' or device_type == 'NONE'): + return True + return False + + def draw(self, context): + layout = self.layout + scene = context.scene + csscene = scene.cycles_curves + + row = layout.row() + row.prop(csscene, "use_curves", text="Enable Cycles Hair") + row = layout.row() + row.prop(csscene, "preset", text="Mode") + + if csscene.preset == 'CUSTOM': + row = layout.row() + row.prop(csscene, "primitive", text="Primitive") + row = layout.row() + + if csscene.primitive == 'TRIANGLES': + row.prop(csscene, "triangle_method", text="Method") + if csscene.triangle_method == 'TESSELATED': + row = layout.row() + row.prop(csscene, "resolution", text="Resolution") + row = layout.row() + row.prop(csscene, "use_smooth", text="Smooth") + elif csscene.primitive == 'LINE_SEGMENTS': + row.prop(csscene, "use_backfacing", text="Check back-faces") + row = layout.row() + row.prop(csscene, "use_encasing", text="Exclude encasing") + if csscene.use_encasing: + row.prop(csscene, "encasing_ratio", text="Ratio for encasing") + row = layout.row() + row.prop(csscene, "line_method", text="Method") + row = layout.row() + row.prop(csscene, "use_tangent_normal", text="Use tangent normal as default") + row = layout.row() + row.prop(csscene, "use_tangent_normal_geometry", text="Use tangent normal geometry") + row = layout.row() + row.prop(csscene, "use_tangent_normal_correction", text="Correct tangent normal for slope") + row = layout.row() + row.prop(csscene, "interpolation", text="Interpolation") + row = layout.row() + row.prop(csscene, "segments", text="Segments") + row = layout.row() + row.prop(csscene, "normalmix", text="Ray Mix") + row = layout.row() + row.prop(csscene, "use_cache", text="Export cache with children") + if csscene.use_cache: + row.prop(csscene, "use_parents", text="Include parents") 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..81358e51eb2 --- /dev/null +++ b/intern/cycles/blender/blender_curves.cpp @@ -0,0 +1,898 @@ +/* + * 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 "mesh.h" +#include "object.h" +#include "scene.h" +#include "curves.h" + +#include "blender_sync.h" +#include "blender_util.h" + +#include "subd_mesh.h" +#include "subd_patch.h" +#include "subd_split.h" + +#include "util_foreach.h" + +#include "DNA_modifier_types.h" +#include "DNA_particle_types.h" +#include "DNA_meshdata_types.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 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); + +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_u.clear(); + curve_v.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); + + float uvs[3] = {0,0}; + if(b_mesh->tessface_uv_textures.length()) + b_pa->uv_on_emitter(psmd,uvs); + CData->curve_u.push_back(uvs[0]); + CData->curve_v.push_back(uvs[1]); + + 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; + + BL::ParticleSystem::particles_iterator b_pa; + b_psys.particles.begin(b_pa); + 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); + + /*add uvs*/ + BL::Mesh::tessface_uv_textures_iterator l; + b_mesh->tessface_uv_textures.begin(l); + + float uvs[2] = {0,0}; + if(b_mesh->tessface_uv_textures.length()) + b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uvs); + + + if(pa_no < totparts && b_pa != b_psys.particles.end()) + ++b_pa; + + CData->curve_u.push_back(uvs[0]); + CData->curve_v.push_back(uvs[1]); + + curvenum++; + + } + } + + } + } + + 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[curvekey+2] - CData->curvekey_co[curvekey]; + } + else if (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) + v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey - 2]; + 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 == 2) && (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 = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f); + + if ((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) && (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()); + mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); + mesh->attributes.remove(ATTR_STD_FACE_NORMAL); + mesh->add_face_normals(); + mesh->add_vertex_normals(); + + /* 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[curvekey+2] - 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] - 2) { + v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; + v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[curvekey-2]; + } + 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[curvekey+2] - 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] - 2) { + v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; + v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[curvekey-2]; + } + 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 == 2) && (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 = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f); + + if ((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) && (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()); + mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); + mesh->attributes.remove(ATTR_STD_FACE_NORMAL); + mesh->add_face_normals(); + mesh->add_vertex_normals(); + + /* 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[curvekey+2] - 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] - 2) { + v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; + v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[curvekey-2]; + } + 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[curvekey+2] - 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] - 2) { + v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; + v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[curvekey-2]; + } + 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 == 2) && (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 = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f); + + if ((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) && (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()); + mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); + mesh->attributes.remove(ATTR_STD_FACE_NORMAL); + mesh->add_face_normals(); + mesh->add_vertex_normals(); + + /* texture coords still needed */ +} + +void ExportCurveSegments(Mesh *mesh, ParticleCurveData *CData, int interpolation, int segments) +{ + int cks = 0; + int curs = 0; + int segs = 0; + + if(!(mesh->curve_segs.empty() && mesh->curve_keys.empty() && mesh->curve_attrib.empty())) + return; + + 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; + + 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_curvekey(ickey_loc, radius, time); + + if(subv != 0) { + mesh->add_curve(cks - 1, cks, CData->psys_shader[sys], curs); + segs++; + } + + cks++; + } + } + + mesh->add_curveattrib(CData->curve_u[curve], CData->curve_v[curve]); + curs++; + + } + } + + /* check allocation*/ + if((mesh->curve_keys.size() != cks) || (mesh->curve_segs.size() != segs) || (mesh->curve_attrib.size() != curs)) { + /* allocation failed -> clear data */ + mesh->curve_keys.clear(); + mesh->curve_segs.clear(); + mesh->curve_attrib.clear(); + } +} + +/* 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_attrib.clear(); + mesh->curve_keys.clear(); + mesh->curve_keysCD.clear(); + mesh->curve_segs.clear(); + + /* obtain general settings */ + bool use_curves = scene->curve_system_manager->use_curves; + + if(use_curves && b_ob.mode() == b_ob.mode_OBJECT) { + 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 = new ParticleCurveData(); + + if (use_cache) + ObtainCacheParticleData(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){ + if (triangle_method == CURVE_CAMERA) + ExportCurveTrianglePlanes(mesh, CData, interpolation, use_smooth, segments, RotCam); + else if (triangle_method == CURVE_RIBBONS) + ExportCurveTriangleRibbons(mesh, CData, interpolation, use_smooth, segments); + else + ExportCurveTriangleGeometry(mesh, CData, interpolation, use_smooth, resolution, segments); + } + else { + ExportCurveSegments(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) { + + for(int ck = 0; ck < ckey_num; ck++) { + Mesh::CurveData SCD; + SCD.tg = normalize(normalize(mesh->curve_keys[min(ck + 1, ckey_num - 1)].loc - mesh->curve_keys[ck].loc) - + normalize(mesh->curve_keys[max(ck - 1, 0)].loc - mesh->curve_keys[ck].loc)); + mesh->curve_keysCD.push_back(SCD); + } + } + } + + + delete CData; + + } + + mesh->compute_bounds(); + +} + + +CCL_NAMESPACE_END + diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index c9748756d43..e9250ec3eff 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -376,7 +376,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 +435,24 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated) PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles"); vector 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 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 +479,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 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..cd31a5b5bb6 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) @@ -143,7 +143,7 @@ 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); 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/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp index b58a34f9942..102414e4a3d 100644 --- a/intern/cycles/bvh/bvh.cpp +++ b/intern/cycles/bvh/bvh.cpp @@ -75,6 +75,10 @@ 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->curve_keysCD); + key.add(ob->mesh->curve_segs); + key.add(ob->mesh->curve_attrib); key.add(&ob->bounds, sizeof(ob->bounds)); key.add(&ob->visibility, sizeof(ob->visibility)); key.add(&ob->mesh->transform_applied, sizeof(bool)); @@ -91,6 +95,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_type); value.read(pack.prim_visibility); value.read(pack.prim_index); value.read(pack.prim_object); @@ -112,6 +117,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_type); value.add(pack.prim_visibility); value.add(pack.prim_index); value.add(pack.prim_object); @@ -157,10 +163,11 @@ void BVH::build(Progress& progress) } /* build nodes */ + vector prim_type; vector prim_index; vector prim_object; - BVHBuild bvh_build(objects, prim_index, prim_object, params, progress); + BVHBuild bvh_build(objects, prim_type, prim_index, prim_object, params, progress); BVHNode *root = bvh_build.run(); if(progress.get_cancel()) { @@ -169,6 +176,7 @@ void BVH::build(Progress& progress) } /* todo: get rid of this copy */ + pack.prim_type = prim_type; pack.prim_index = prim_index; pack.prim_object = prim_object; @@ -182,8 +190,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 +223,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 +271,50 @@ void BVH::pack_triangle(int idx, float4 woop[3]) } } -void BVH::pack_triangles() +/* Curves*/ + +void BVH::pack_curve_seg(int idx, float4 woop[3]) +{ + int tob = pack.prim_object[idx]; + const Mesh *mesh = objects[tob]->mesh; + int tidx = pack.prim_index[idx]; + float3 v0 = mesh->curve_keys[mesh->curve_segs[tidx].v[0]].loc; + float3 v1 = mesh->curve_keys[mesh->curve_segs[tidx].v[1]].loc; + float t0 = mesh->curve_keys[mesh->curve_segs[tidx].v[0]].time; + float t1 = mesh->curve_keys[mesh->curve_segs[tidx].v[1]].time; + + float3 d0 = v1 - v0; + float l = len(d0); + + float u = mesh->curve_attrib[mesh->curve_segs[tidx].curve].uv[0]; + float v = mesh->curve_attrib[mesh->curve_segs[tidx].curve].uv[1]; + + /*Plan + *Transform tfm = make_transform( + * location <3> , l, + * extra curve data <3> , StrID, + * nextkey, flags/tip?, r, t); + */ + float3 tg1 = make_float3(1.0f,0.0f,0.0f); + float3 tg2 = make_float3(1.0f,0.0f,0.0f); + if(mesh->curve_keysCD.size()) { + tg1 = mesh->curve_keysCD[mesh->curve_segs[tidx].v[0]].tg; + tg2 = mesh->curve_keysCD[mesh->curve_segs[tidx].v[1]].tg; + } + + Transform tfm = make_transform( + tg1.x, tg1.y, tg1.z, l, + tg2.x, tg2.y, tg2.z, 0, + t0, t1, u, v, + 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_type[i]) + pack_curve_seg(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_type[i]) + pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->curveseg_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_type.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_type = (pack.prim_type.size())? &pack.prim_type[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->curveseg_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_type = &bvh->pack.prim_type[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_type[i]) + 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_type[pack_prim_index_offset] = bvh_prim_type[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,37 @@ 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_type[prim]) { + /* strands */ + int str_offset = (params.top_level)? mesh->curveseg_offset: 0; + const int *hidx = mesh->curve_segs[pidx - str_offset].v; + + bbox.grow(mesh->curve_keys[hidx[0]].loc, mesh->curve_keys[hidx[0]].radius); + bbox.grow(mesh->curve_keys[hidx[1]].loc, mesh->curve_keys[hidx[1]].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..d81bb312148 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 object_node; /* precomputed triangle intersection data, one triangle is 4x float4 */ - array tri_woop; + array tri_woop; + /* primitive type - triangle or strand (should be moved to flag?) */ + array prim_type; /* visibility visibilitys for primitives */ array 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_seg(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..cdd94324f53 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& objects_, - vector& prim_index_, vector& prim_object_, + vector& prim_type_, vector& prim_index_, vector& prim_object_, const BVHParams& params_, Progress& progress_) : objects(objects_), + prim_type(prim_type_), prim_index(prim_index_), prim_object(prim_object_), params(params_), @@ -78,7 +79,23 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, } if(bounds.valid()) { - references.push_back(BVHReference(bounds, j, i)); + references.push_back(BVHReference(bounds, j, i, false)); + root.grow(bounds); + center.grow(bounds.center2()); + } + } + + for(uint j = 0; j < mesh->curve_segs.size(); j++) { + Mesh::CurveSeg s = mesh->curve_segs[j]; + BoundBox bounds = BoundBox::empty; + + for(int k = 0; k < 2; k++) { + float3 pt = mesh->curve_keys[s.v[k]].loc; + bounds.grow(pt, mesh->curve_keys[s.v[k]].radius); + } + + if(bounds.valid()) { + references.push_back(BVHReference(bounds, j, i, true)); root.grow(bounds); center.grow(bounds.center2()); } @@ -87,7 +104,7 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, 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()); } @@ -99,13 +116,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 += ob->mesh->curve_segs.size(); + } else num_alloc_references++; } - else + else { num_alloc_references += ob->mesh->triangles.size(); + num_alloc_references += ob->mesh->curve_segs.size(); + } } references.reserve(num_alloc_references); @@ -162,6 +183,7 @@ BVHNode* BVHBuild::run() progress_total = references.size(); progress_original_total = progress_total; + prim_type.resize(references.size()); prim_index.resize(references.size()); prim_object.resize(references.size()); @@ -319,10 +341,12 @@ BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start, if(start == prim_index.size()) { assert(params.use_spatial_split); + prim_type.push_back(ref->prim_type()); prim_index.push_back(ref->prim_index()); prim_object.push_back(ref->prim_object()); } else { + prim_type[start] = ref->prim_type(); prim_index[start] = ref->prim_index(); prim_object[start] = ref->prim_object(); } @@ -345,6 +369,7 @@ BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start, BVHNode* BVHBuild::create_leaf_node(const BVHRange& range) { + vector& p_type = prim_type; vector& p_index = prim_index; vector& p_object = prim_object; BoundBox bounds = BoundBox::empty; @@ -358,10 +383,12 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range) if(range.start() + num == prim_index.size()) { assert(params.use_spatial_split); + p_type.push_back(ref.prim_type()); p_index.push_back(ref.prim_index()); p_object.push_back(ref.prim_object()); } else { + p_type[range.start() + num] = ref.prim_type(); 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..ba10eb49412 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& objects, + vector& prim_type, vector& prim_index, vector& prim_object, const BVHParams& params, @@ -87,6 +88,7 @@ protected: int num_original_references; /* output primitive indexes and objects */ + vector& prim_type; vector& prim_index; vector& prim_object; diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h index a78496d841d..7a1555ae548 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_type) : rbounds(bounds_) { rbounds.min.w = __int_as_float(prim_index_); rbounds.max.w = __int_as_float(prim_object_); + type = prim_type; } __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_type() const { return type; } protected: BoundBox rbounds; + uint type; }; /* BVH Range diff --git a/intern/cycles/bvh/bvh_sort.cpp b/intern/cycles/bvh/bvh_sort.cpp index bef384be592..9a8961c8b15 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_type() < rb.prim_type()) return true; + else if(ra.prim_type() > rb.prim_type()) return false; return false; } diff --git a/intern/cycles/bvh/bvh_split.cpp b/intern/cycles/bvh/bvh_split.cpp index 263c5834428..860e2c8d7df 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_type()) { + 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 { + /* Strand split: NOTE - Currently ignores strand width and needs to be fixed.*/ + + const int *inds = mesh->curve_segs[ref.prim_index()].v; + const float3* v0 = &mesh->curve_keys[inds[0]].loc; + const float3* v1 = &mesh->curve_keys[inds[1]].loc; + 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_type()); + right = BVHReference(right_bounds, ref.prim_index(), ref.prim_object(), ref.prim_type()); } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_bvh.h b/intern/cycles/kernel/kernel_bvh.h index 73e7fb0e5d6..15af35a05f8 100644 --- a/intern/cycles/kernel/kernel_bvh.h +++ b/intern/cycles/kernel/kernel_bvh.h @@ -205,6 +205,151 @@ __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 triAddr) +{ + /* curve Intersection check */ + + int flags = kernel_data.curve_kernel_data.curveflags; + + int prim = kernel_tex_fetch(__prim_index, triAddr); + float4 v00 = kernel_tex_fetch(__cur_segs, prim); + + int v1 = __float_as_int(v00.x); + int v2 = __float_as_int(v00.y); + + float4 P1 = kernel_tex_fetch(__cur_keys, v1); + float4 P2 = kernel_tex_fetch(__cur_keys, v2); + + float l = v00.w; + 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; + + /* test bounding sphere intersection (introduce circular artifacts)*/ + /*float3 bvector = 0.5f * (p1 + p2) - P; + float bvectorl_sq = len_squared(bvector); + float dot_bv_dir = dot(bvector,dir); + float maxdist = l * 0.5f + mr; + if(bvectorl_sq - dot_bv_dir * dot_bv_dir > maxdist * maxdist) + 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) + 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; + } + } + + /*remove overlap - not functional yet*/ + /*if (flags & CURVE_KN_CURVEDATA) { + float3 tg1 = float4_to_float3(kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0)); + float3 tg2 = float4_to_float3(kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1)); + if((dot(P + t * dir - p1, tg1) < 0.0f) || (dot(P + t * dir - p2, tg2) > 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, triAddr) & visibility) + #endif + { + /* record intersection */ + isect->prim = triAddr; + 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 +426,15 @@ __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__ + if(kernel_tex_fetch(__prim_type, primAddr)) + bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr); + 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 +551,15 @@ __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__ + if(kernel_tex_fetch(__prim_type, primAddr)) + bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr); + 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) @@ -545,5 +700,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(__cur_segs, prim); + + int v1 = __float_as_int(v00.x); + int v2 = __float_as_int(v00.y); + + float4 P1 = kernel_tex_fetch(__cur_keys, v1); + float4 P2 = kernel_tex_fetch(__cur_keys, v2); + float l = v00.w; + 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_emission.h b/intern/cycles/kernel/kernel_emission.h index e56633c9358..adf7e8eca82 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->curve_seg == ~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..0f74ab75dd4 100644 --- a/intern/cycles/kernel/kernel_light.h +++ b/intern/cycles/kernel/kernel_light.h @@ -326,6 +326,59 @@ __device float triangle_light_pdf(KernelGlobals *kg, return (t*t*kernel_data.integrator.pdf_triangles)/cos_pi; } +#ifdef __HAIR__ +/* Strand Light */ + +__device void curve_seg_light_sample(KernelGlobals *kg, int prim, int object, + float randu, float randv, float time, LightSample *ls) +{ + /* this strand code needs completion */ + float4 v00 = kernel_tex_fetch(__cur_segs, prim); + + int v1 = __float_as_int(v00.x); + int v2 = __float_as_int(v00.y); + float l = v00.w; + + float4 P1 = kernel_tex_fetch(__cur_keys, v1); + float4 P2 = kernel_tex_fetch(__cur_keys, v2); + 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 +418,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__ +/* currently use l.z to indicate is strand sample which isn't ideal */ + bool is_curve = __float_as_int(l.z) == 0.0f; +#endif if(prim >= 0) { int object = __float_as_int(l.w); - triangle_light_sample(kg, prim, object, randu, randv, time, ls); +#ifdef __HAIR__ + if (is_curve) + curve_seg_light_sample(kg, prim, object, 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_object.h b/intern/cycles/kernel/kernel_object.h index 40aa4753daa..2260094aa70 100644 --- a/intern/cycles/kernel/kernel_object.h +++ b/intern/cycles/kernel/kernel_object.h @@ -288,5 +288,55 @@ __device float3 particle_angular_velocity(KernelGlobals *kg, int particle) return make_float3(f3.z, f3.w, f4.x); } +#ifdef __HAIR__ +/* Hair Info Node fns */ + +__device float hair_radius(KernelGlobals *kg, int prim, float u) +{ + float r = 0.0f; + + if (prim != -1) { + float4 v00 = kernel_tex_fetch(__cur_segs, prim); + + int v1 = __float_as_int(v00.x); + int v2 = __float_as_int(v00.y); + + float4 P1 = kernel_tex_fetch(__cur_keys, v1); + float4 P2 = kernel_tex_fetch(__cur_keys, v2); + r = (P2.w - P1.w) * u + P1.w; + } + + return r; +} + +__device float3 hair_tangent_normal(KernelGlobals *kg, ShaderData *sd) +{ + float3 tgN = make_float3(0.0f,0.0f,0.0f); + + if (sd->curve_seg != ~0) { + tgN = -(-sd->I - sd->dPdu * (dot(sd->dPdu,-sd->I) * kernel_data.curve_kernel_data.normalmix / len_squared(sd->dPdu))); + tgN = normalize(tgN); + /*if (kernel_data.curve_kernel_data.use_tangent_normal_correction) need to find suitable scaled gd for corrected normal + { + tgN = normalize(tgN - gd * sd->dPdu); + }*/ + } + + return tgN; +} + +__device float intercept(KernelGlobals *kg, int prim, int triAddr, float u) +{ + float t = 0.0f; + + if (prim != -1) { + float4 sd2 = kernel_tex_fetch(__tri_woop, triAddr*3+2); + t = (sd2.y - sd2.x) * u + sd2.x; + } + + return t; +} +#endif + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index 47b4d02e5bf..36cd21c1b48 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -56,24 +56,9 @@ __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); /* matrices and time */ #ifdef __OBJECT_MOTION__ @@ -81,23 +66,64 @@ __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); +#ifdef __HAIR__ + sd->curve_seg = ~0; +#endif 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_type, isect->prim)) { + /* Strand Shader setting*/ + float4 CurSeg = kernel_tex_fetch(__cur_segs, sd->prim); + sd->shader = __float_as_int(CurSeg.z); + + sd->curve_seg = sd->prim; + sd->prim = isect->prim; + + 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 __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); + sd->flag |= kernel_tex_fetch(__object_flag, sd->object); + #ifdef __INSTANCING__ if(isect->object != ~0) { /* instance transform */ @@ -135,7 +161,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 curve = ~0) { /* vectors */ sd->P = P; @@ -143,11 +169,15 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd, sd->Ng = Ng; sd->I = I; sd->shader = shader; +#ifdef __HAIR__ + sd->curve_seg = curve; +#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 +213,13 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd, #endif /* smooth normal */ +#ifdef __HAIR__ + if(sd->shader & SHADER_SMOOTH_NORMAL && sd->curve_seg == ~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 +229,17 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd, #ifdef __DPDU__ /* dPdu/dPdv */ +#ifdef __HAIR__ + if(sd->prim == ~0 || sd->curve_seg != ~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 +321,9 @@ __device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData sd->object = ~0; #endif sd->prim = ~0; +#ifdef __HAIR__ + sd->curve_seg = ~0; +#endif #ifdef __UV__ sd->u = 0.0f; sd->v = 0.0f; @@ -732,8 +777,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_type, isect->prim)) { +#endif + float4 Ns = kernel_tex_fetch(__tri_normal, prim); + shader = __float_as_int(Ns.w); +#ifdef __HAIR__ + } + else { + float4 str = kernel_tex_fetch(__cur_segs, 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..0b6107b398e 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_type) 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, __cur_segs) +KERNEL_TEX(float4, texture_float4, __cur_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..1f2618d3507 100644 --- a/intern/cycles/kernel/kernel_triangle.h +++ b/intern/cycles/kernel/kernel_triangle.h @@ -106,88 +106,107 @@ __device_inline void triangle_dPdudv(KernelGlobals *kg, float3 *dPdu, float3 *dP __device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy) { - if(elem == ATTR_ELEMENT_FACE) { - if(dx) *dx = 0.0f; - if(dy) *dy = 0.0f; - - return kernel_tex_fetch(__attributes_float, offset + sd->prim); - } - else if(elem == ATTR_ELEMENT_VERTEX) { - float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, sd->prim)); - - float f0 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.x)); - float f1 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.y)); - float f2 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.z)); - -#ifdef __RAY_DIFFERENTIALS__ - if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2; - if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2; -#endif - - return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2; - } - else if(elem == ATTR_ELEMENT_CORNER) { - int tri = offset + sd->prim*3; - float f0 = kernel_tex_fetch(__attributes_float, tri + 0); - float f1 = kernel_tex_fetch(__attributes_float, tri + 1); - float f2 = kernel_tex_fetch(__attributes_float, tri + 2); - -#ifdef __RAY_DIFFERENTIALS__ - if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2; - if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2; +#ifdef __HAIR__ + if(sd->curve_seg == ~0) { #endif - - return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2; + if(elem == ATTR_ELEMENT_FACE) { + if(dx) *dx = 0.0f; + if(dy) *dy = 0.0f; + + return kernel_tex_fetch(__attributes_float, offset + sd->prim); + } + else if(elem == ATTR_ELEMENT_VERTEX) { + float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, sd->prim)); + + float f0 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.x)); + float f1 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.y)); + float f2 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.z)); + + #ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2; + if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2; + #endif + + return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2; + } + else if(elem == ATTR_ELEMENT_CORNER) { + int tri = offset + sd->prim*3; + float f0 = kernel_tex_fetch(__attributes_float, tri + 0); + float f1 = kernel_tex_fetch(__attributes_float, tri + 1); + float f2 = kernel_tex_fetch(__attributes_float, tri + 2); + + #ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2; + if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2; + #endif + + return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2; + } + else { + if(dx) *dx = 0.0f; + if(dy) *dy = 0.0f; + + return 0.0f; + } +#ifdef __HAIR__ } else { - if(dx) *dx = 0.0f; - if(dy) *dy = 0.0f; - return 0.0f; } +#endif } __device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy) { - if(elem == ATTR_ELEMENT_FACE) { - if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f); - if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f); - - return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + sd->prim)); - } - else if(elem == ATTR_ELEMENT_VERTEX) { - float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, sd->prim)); - - float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x))); - float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y))); - float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z))); - -#ifdef __RAY_DIFFERENTIALS__ - if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2; - if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2; +#ifdef __HAIR__ + if(sd->curve_seg == ~0) { #endif - - return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2; - } - else if(elem == ATTR_ELEMENT_CORNER) { - int tri = offset + sd->prim*3; - float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 0)); - float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 1)); - float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 2)); - -#ifdef __RAY_DIFFERENTIALS__ - if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2; - if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2; -#endif - - return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2; + if(elem == ATTR_ELEMENT_FACE) { + if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f); + if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f); + + return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + sd->prim)); + } + else if(elem == ATTR_ELEMENT_VERTEX) { + float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, sd->prim)); + + float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x))); + float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y))); + float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z))); + + #ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2; + if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2; + #endif + + return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2; + } + else if(elem == ATTR_ELEMENT_CORNER) { + int tri = offset + sd->prim*3; + float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 0)); + float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 1)); + float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 2)); + + #ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2; + if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2; + #endif + + return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2; + } + else { + if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f); + if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f); + + return make_float3(0.0f, 0.0f, 0.0f); + } +#ifdef __HAIR__ } - else { - if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f); - if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f); - + else + { return make_float3(0.0f, 0.0f, 0.0f); } +#endif } /* motion */ @@ -200,10 +219,16 @@ __device float4 triangle_motion_vector(KernelGlobals *kg, ShaderData *sd) 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); +#ifdef __HAIR__ + if(sd->curve_seg == ~0) { +#endif + 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); +#ifdef __HAIR__ + } +#endif /* object motion. note that depending on the mesh having motion vectors, this * transformation was set match the world/object space of motion_pre/post */ @@ -259,8 +284,13 @@ __device float3 triangle_uv(KernelGlobals *kg, ShaderData *sd) { int offset_uv = find_attribute(kg, sd, ATTR_STD_UV); +#ifdef __HAIR__ + if(offset_uv == ATTR_STD_NOT_FOUND || sd->curve_seg != ~0) + return make_float3(0.0f, 0.0f, 0.0f); +#else if(offset_uv == ATTR_STD_NOT_FOUND) return make_float3(0.0f, 0.0f, 0.0f); +#endif float3 uv = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, offset_uv, NULL, NULL); uv.z = 1.0f; diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index d11b96503d9..d051006f165 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 */ @@ -436,6 +437,11 @@ typedef struct ShaderData { /* primitive id if there is one, ~0 otherwise */ int prim; + +#ifdef __HAIR__ + /* strand id if there is one, -1 otherwise */ + int curve_seg; +#endif /* parametric coordinates * - barycentric weights for triangles */ float u, v; @@ -650,6 +656,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 +686,7 @@ typedef struct KernelData { KernelSunSky sunsky; KernelIntegrator integrator; KernelBVH bvh; + KernelCurves curve_kernel_data; } KernelData; CCL_NAMESPACE_END 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..4f9dc4af007 100644 --- a/intern/cycles/kernel/svm/svm_attribute.h +++ b/intern/cycles/kernel/svm/svm_attribute.h @@ -58,27 +58,45 @@ __device void svm_node_attr(KernelGlobals *kg, ShaderData *sd, float *stack, uin svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset); - /* 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); - stack_store_float(stack, out_offset, f); - } +#ifdef __HAIR__ + if (sd->curve_seg != ~0) { + /*currently strand attributes aren't enabled - only exports stored uvs*/ + if(type == NODE_ATTR_FLOAT) + stack_store_float(stack, out_offset, 0.0f); else { - float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL); - stack_store_float(stack, out_offset, average(f)); + float4 sd2 = kernel_tex_fetch(__tri_woop, sd->prim*3+2); + float3 uv = make_float3(sd2.z,sd2.w,0.0f); + stack_store_float3(stack, out_offset, uv); } } - else { - if(mesh_type == NODE_ATTR_FLOAT3) { - float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL); - stack_store_float3(stack, out_offset, f); + else + { +#endif + + /* 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); + stack_store_float(stack, out_offset, f); + } + else { + float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL); + stack_store_float(stack, out_offset, average(f)); + } } else { - float f = triangle_attribute_float(kg, sd, elem, offset, NULL, NULL); - stack_store_float3(stack, out_offset, make_float3(f, f, f)); + if(mesh_type == NODE_ATTR_FLOAT3) { + float3 f = triangle_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); + stack_store_float3(stack, out_offset, make_float3(f, f, f)); + } } +#ifdef __HAIR__ } +#endif } __device void svm_node_attr_bump_dx(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node) @@ -91,30 +109,43 @@ __device void svm_node_attr_bump_dx(KernelGlobals *kg, ShaderData *sd, float *st svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset); /* fetch and store attribute */ - if(type == NODE_ATTR_FLOAT) { - if(mesh_type == NODE_ATTR_FLOAT) { - float dx; - float f = triangle_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); - stack_store_float(stack, out_offset, average(f+dx)); - } +#ifdef __HAIR__ + if (sd->curve_seg != ~0) { + /*currently strand attributes aren't enabled*/ + if(type == NODE_ATTR_FLOAT) + stack_store_float(stack, out_offset, 0.0f); + else + stack_store_float3(stack, out_offset, make_float3(0.0f, 0.0f, 0.0f)); } else { - if(mesh_type == NODE_ATTR_FLOAT3) { - float3 dx; - float3 f = triangle_attribute_float3(kg, sd, elem, offset, &dx, NULL); - stack_store_float3(stack, out_offset, f+dx); +#endif + if(type == NODE_ATTR_FLOAT) { + if(mesh_type == NODE_ATTR_FLOAT) { + float dx; + float f = triangle_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); + stack_store_float(stack, out_offset, average(f+dx)); + } } else { - float dx; - float f = triangle_attribute_float(kg, sd, elem, offset, &dx, NULL); - stack_store_float3(stack, out_offset, make_float3(f+dx, f+dx, f+dx)); + if(mesh_type == NODE_ATTR_FLOAT3) { + float3 dx; + float3 f = triangle_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); + stack_store_float3(stack, out_offset, make_float3(f+dx, f+dx, f+dx)); + } } +#ifdef __HAIR__ } +#endif } __device void svm_node_attr_bump_dy(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node) @@ -127,30 +158,43 @@ __device void svm_node_attr_bump_dy(KernelGlobals *kg, ShaderData *sd, float *st svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset); /* fetch and store attribute */ - if(type == NODE_ATTR_FLOAT) { - if(mesh_type == NODE_ATTR_FLOAT) { - float dy; - float f = triangle_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); - stack_store_float(stack, out_offset, average(f+dy)); - } +#ifdef __HAIR__ + if (sd->curve_seg != ~0) { + /*currently strand attributes aren't enabled*/ + if(type == NODE_ATTR_FLOAT) + stack_store_float(stack, out_offset, 0.0f); + else + stack_store_float3(stack, out_offset, make_float3(0.0f, 0.0f, 0.0f)); } else { - if(mesh_type == NODE_ATTR_FLOAT3) { - float3 dy; - float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, &dy); - stack_store_float3(stack, out_offset, f+dy); +#endif + if(type == NODE_ATTR_FLOAT) { + if(mesh_type == NODE_ATTR_FLOAT) { + float dy; + float f = triangle_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); + stack_store_float(stack, out_offset, average(f+dy)); + } } else { - float dy; - float f = triangle_attribute_float(kg, sd, elem, offset, NULL, &dy); - stack_store_float3(stack, out_offset, make_float3(f+dy, f+dy, f+dy)); + if(mesh_type == NODE_ATTR_FLOAT3) { + float3 dy; + float3 f = triangle_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); + stack_store_float3(stack, out_offset, make_float3(f+dy, f+dy, f+dy)); + } } +#ifdef __HAIR__ } +#endif } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/svm/svm_geometry.h b/intern/cycles/kernel/svm/svm_geometry.h index c4d03c1f948..e1b898e9b14 100644 --- a/intern/cycles/kernel/svm/svm_geometry.h +++ b/intern/cycles/kernel/svm/svm_geometry.h @@ -31,8 +31,11 @@ __device void svm_node_geometry(KernelGlobals *kg, ShaderData *sd, float *stack, 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; - +#ifdef __HAIR__ + if(attr_offset != ATTR_STD_NOT_FOUND && sd->curve_seg == ~0) { +#else if(attr_offset != ATTR_STD_NOT_FOUND) { +#endif 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); @@ -160,5 +163,38 @@ __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->curve_seg == ~0); + stack_store_float(stack, out_offset, data); + break; + } + case NODE_INFO_CURVE_INTERCEPT: { + data = intercept(kg, sd->curve_seg, sd->prim, sd->u); + stack_store_float(stack, out_offset, data); + break; + } + case NODE_INFO_CURVE_THICKNESS: { + data = 2 * hair_radius(kg, sd->curve_seg, sd->u); + stack_store_float(stack, out_offset, data); + break; + } + case NODE_INFO_CURVE_TANGENT_NORMAL: { + data3 = hair_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..5e7c92ba93c 100644 --- a/intern/cycles/kernel/svm/svm_tex_coord.h +++ b/intern/cycles/kernel/svm/svm_tex_coord.h @@ -242,7 +242,11 @@ __device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *stac if(space == NODE_NORMAL_MAP_TANGENT) { /* tangent space */ - if(sd->object == ~0) { +#ifdef __HAIR__ + if(sd->object == ~0 || sd->curve_seg != ~0) { +#else + if(sd->object == ~0) { +#endif stack_store_float3(stack, normal_offset, make_float3(0.0f, 0.0f, 0.0f)); return; } @@ -297,7 +301,11 @@ __device void svm_node_tangent(KernelGlobals *kg, ShaderData *sd, float *stack, /* UV map */ int attr_offset = find_attribute(kg, sd, node.z); +#ifdef __HAIR__ + if(attr_offset == ATTR_STD_NOT_FOUND || sd->curve_seg != ~0) +#else if(attr_offset == ATTR_STD_NOT_FOUND) +#endif tangent = make_float3(0.0f, 0.0f, 0.0f); else tangent = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, attr_offset, NULL, NULL); @@ -307,7 +315,11 @@ __device void svm_node_tangent(KernelGlobals *kg, ShaderData *sd, float *stack, int attr_offset = find_attribute(kg, sd, node.z); float3 generated; +#ifdef __HAIR__ + if(attr_offset == ATTR_STD_NOT_FOUND || sd->curve_seg != ~0) +#else if(attr_offset == ATTR_STD_NOT_FOUND) +#endif generated = sd->P; else generated = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, attr_offset, NULL, NULL); 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/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..581b3010d77 --- /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 psys_firstcurve; + vector psys_curvenum; + vector psys_shader; + + vector psys_rootradius; + vector psys_tipradius; + vector psys_shape; + vector psys_closetip; + + vector curve_firstkey; + vector curve_keynum; + vector curve_length; + vector curve_u; + vector curve_v; + + vector curvekey_co; + vector 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..66e528c7230 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_segs = 0; foreach(Object *object, scene->objects) { Mesh *mesh = object->mesh; @@ -169,10 +170,18 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen if(shader->sample_as_light && shader->has_surface_emission) num_triangles++; } + + /* disabled for strands*/ + /*for(size_t i = 0; i < mesh->curve_segs.size(); i++) { + * Shader *shader = scene->shaders[mesh->curve_segs[i].curveshader]; + * + * if(shader->sample_as_light && shader->has_surface_emission) + * num_curve_segs++; + }*/ } } - size_t num_distribution = num_triangles; + size_t num_distribution = num_triangles + num_curve_segs; num_distribution += num_lights; /* emission area */ @@ -234,6 +243,32 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen totarea += triangle_area(p1, p2, p3); } } + + /*sample as light disabled for strands*/ + /*for(size_t i = 0; i < mesh->curve_segs.size(); i++) { + * Shader *shader = scene->shaders[mesh->curve_segs[i].curveshader]; + * + * if(shader->sample_as_light && shader->has_surface_emission) { + * distribution[offset].x = totarea; + * distribution[offset].y = __int_as_float(i + mesh->curveseg_offset); + * distribution[offset].z = 0.0f; + * distribution[offset].w = __int_as_float(object_id); + * offset++; + * + * Mesh::CurveSeg s = mesh->curve_segs[i]; + * float3 p1 = mesh->curve_keys[s.v[0]].loc; + * float r1 = mesh->curve_keys[s.v[0]].radius; + * float3 p2 = mesh->curve_keys[s.v[1]].loc; + * float r2 = mesh->curve_keys[s.v[1]].radius; + * + * if(!transform_applied) { + * p1 = transform_point(&tfm, p1); + * p2 = transform_point(&tfm, p2); + * } + * + * totarea += M_PI_F * (r1 + r2) * len(p1 - p2); + * } + }*/ } if(progress.get_cancel()) return; diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index bc782a78c60..a2d545d51c0 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -51,6 +51,9 @@ Mesh::Mesh() tri_offset = 0; vert_offset = 0; + curveseg_offset = 0; + curvekey_offset = 0; + attributes.mesh = this; } @@ -66,6 +69,7 @@ void Mesh::reserve(int numverts, int numtris) triangles.resize(numtris); shader.resize(numtris); smooth.resize(numtris); + /*currently no need in hair segment resize and curve data needs including*/ attributes.reserve(numverts, numtris); } @@ -77,6 +81,11 @@ void Mesh::clear() shader.clear(); smooth.clear(); + curve_keys.clear(); + curve_keysCD.clear(); + curve_segs.clear(); + curve_attrib.clear(); + attributes.clear(); used_shaders.clear(); @@ -96,14 +105,48 @@ void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_) smooth.push_back(smooth_); } +void Mesh::add_curvekey(float3 loc, float radius, float time) +{ + CurveKey ck; + ck.loc = loc; + ck.radius = radius; + ck.time = time; + + curve_keys.push_back(ck); +} + +void Mesh::add_curve(int v0, int v1, int shader, int curveid) +{ + CurveSeg s; + s.v[0] = v0; + s.v[1] = v1; + s.curveshader = shader; + s.curve = curveid; + + curve_segs.push_back(s); +} + +void Mesh::add_curveattrib(float u, float v) +{ + Curve_Attribute s; + s.uv[0] = u; + s.uv[1] = v; + + curve_attrib.push_back(s); +} + 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].loc, curve_keys[i].radius); + /* happens mostly on empty meshes */ if(!bnds.valid()) bnds.grow(make_float3(0.0f, 0.0f, 0.0f)); @@ -243,6 +286,45 @@ 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_seg_keys, size_t curvekey_offset) +{ + size_t curve_keys_size = curve_keys.size(); + CurveKey *keys_ptr = NULL; + + if(curve_keys_size) { + + keys_ptr = &curve_keys[0]; + + for(size_t i = 0; i < curve_keys_size; i++) { + float3 p = keys_ptr[i].loc; + curve_key_co[i] = make_float4(p.x, p.y, p.z, keys_ptr[i].radius); + } + } + + size_t curve_seg_num = curve_segs.size(); + + if(curve_seg_num) { + CurveSeg *curve_ptr = &curve_segs[0]; + + int shader_id = 0; + + for(size_t i = 0; i < curve_seg_num; i++) { + CurveSeg s = curve_ptr[i]; + shader_id = scene->shader_manager->get_shader_id(s.curveshader, this, false); + + float3 p1 = keys_ptr[s.v[0]].loc; + float3 p2 = keys_ptr[s.v[1]].loc; + float length = len(p2 - p1); + + curve_seg_keys[i] = make_float4( + __int_as_float(s.v[0] + curvekey_offset), + __int_as_float(s.v[1] + curvekey_offset), + __int_as_float(shader_id), + length); + } + } +} + void Mesh::compute_bvh(SceneParams *params, Progress *progress, int n, int total) { if(progress->get_cancel()) @@ -573,39 +655,62 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene size_t vert_size = 0; size_t tri_size = 0; + size_t CurveKey_size = 0; + size_t curve_seg_keys = 0; + foreach(Mesh *mesh, scene->meshes) { mesh->vert_offset = vert_size; mesh->tri_offset = tri_size; + mesh->curvekey_offset = CurveKey_size; + mesh->curveseg_offset = curve_seg_keys; + vert_size += mesh->verts.size(); tri_size += mesh->triangles.size(); + + CurveKey_size += mesh->curve_keys.size(); + curve_seg_keys += mesh->curve_segs.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_seg_keys != 0) { + progress.set_status("Updating Mesh", "Copying Strands to device"); + + float4 *cur_keys = dscene->cur_keys.resize(CurveKey_size); + float4 *cur_segs = dscene->cur_segs.resize(curve_seg_keys); - 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, &cur_keys[mesh->curvekey_offset], &cur_segs[mesh->curveseg_offset], mesh->curvekey_offset); + if(progress.get_cancel()) return; + } + + device->tex_alloc("__cur_keys", dscene->cur_keys); + device->tex_alloc("__cur_segs", dscene->cur_segs); + } } void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) @@ -642,6 +747,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_type.size()) { + dscene->prim_type.reference((uint*)&pack.prim_type[0], pack.prim_type.size()); + device->tex_alloc("__prim_type", dscene->prim_type); + } 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 +860,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_type); device->tex_free(dscene->prim_visibility); device->tex_free(dscene->prim_index); device->tex_free(dscene->prim_object); @@ -758,6 +868,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->cur_segs); + device->tex_free(dscene->cur_keys); device->tex_free(dscene->attributes_map); device->tex_free(dscene->attributes_float); device->tex_free(dscene->attributes_float3); @@ -765,6 +877,7 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) dscene->bvh_nodes.clear(); dscene->object_node.clear(); dscene->tri_woop.clear(); + dscene->prim_type.clear(); dscene->prim_visibility.clear(); dscene->prim_index.clear(); dscene->prim_object.clear(); @@ -772,6 +885,8 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) dscene->tri_vnormal.clear(); dscene->tri_vindex.clear(); dscene->tri_verts.clear(); + dscene->cur_segs.clear(); + dscene->cur_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..24d3f02e082 100644 --- a/intern/cycles/render/mesh.h +++ b/intern/cycles/render/mesh.h @@ -50,6 +50,28 @@ public: int v[3]; }; + /* Mesh Strand Data*/ + struct CurveSeg { + int v[2]; + uint curveshader; + int curve; + }; + + struct Curve_Attribute { + float uv[2]; + }; + + struct CurveKey { + float3 loc; + float radius; + float time; + }; + + /*curve data for hair - currently only contains key tangent instead*/ + struct CurveData { + float3 tg; + }; + /* Displacement */ enum DisplacementMethod { DISPLACE_BUMP, @@ -65,6 +87,11 @@ public: vector shader; vector smooth; + vector curve_keys; + vector curve_keysCD; + vector curve_segs; + vector curve_attrib; + vector used_shaders; AttributeSet attributes; @@ -82,6 +109,9 @@ public: size_t tri_offset; size_t vert_offset; + size_t curveseg_offset; + size_t curvekey_offset; + /* Functions */ Mesh(); ~Mesh(); @@ -89,6 +119,9 @@ public: void reserve(int numverts, int numfaces); void clear(); void add_triangle(int v0, int v1, int v2, int shader, bool smooth); + void add_curvekey(float3 loc, float radius, float time); + void add_curve(int v0, int v1, int shader, int curveid); + void add_curveattrib(float u, float v); void compute_bounds(); void add_face_normals(); @@ -96,6 +129,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_seg_keys, 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/nodes.cpp b/intern/cycles/render/nodes.cpp index aef28449e44..23d6432616c 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -2240,6 +2240,52 @@ 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::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()) { + compiler.stack_assign(out); + compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_INTERCEPT, out->stack_offset); + } + + 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..ee7afccb0e1 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -331,6 +331,11 @@ public: void attributes(AttributeRequestSet *attributes); }; +class HairInfoNode : public ShaderNode { +public: + SHADER_NODE_CLASS(HairInfoNode) +}; + 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..588b4d50e1b 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,13 @@ 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].loc = transform_point(&tfm, mesh->curve_keys[i].loc); + + for(size_t i = 0; i < mesh->curve_keysCD.size(); i++) + mesh->curve_keysCD[i].tg = transform_direction(&tfm, mesh->curve_keysCD[i].tg); + + Attribute *attr_fN = mesh->attributes.find(ATTR_STD_FACE_NORMAL); Attribute *attr_vN = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL); @@ -133,6 +142,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 +199,16 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene surface_area += triangle_area(p1, p2, p3); } + foreach(Mesh::CurveSeg& t, mesh->curve_segs) { + float3 p1 = mesh->curve_keys[t.v[0]].loc; + float r1 = mesh->curve_keys[t.v[0]].radius; + float3 p2 = mesh->curve_keys[t.v[1]].loc; + float r2 = mesh->curve_keys[t.v[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 +224,16 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene surface_area += triangle_area(p1, p2, p3); } + + foreach(Mesh::CurveSeg& t, mesh->curve_segs) { + float3 p1 = mesh->curve_keys[t.v[0]].loc; + float r1 = mesh->curve_keys[t.v[0]].radius; + float3 p2 = mesh->curve_keys[t.v[1]].loc; + float r2 = mesh->curve_keys[t.v[1]].radius; + + /* currently ignores segment overlaps*/ + surface_area += M_PI_F *(r1 + r2) * len(p1 - p2); + } } /* pack in texture */ @@ -355,6 +385,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..8b121d3b2fb 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -50,6 +50,7 @@ class Object; class ObjectManager; class ParticleSystemManager; class ParticleSystem; +class CurveSystemManager; class Shader; class ShaderManager; class Progress; @@ -62,6 +63,7 @@ public: device_vector bvh_nodes; device_vector object_node; device_vector tri_woop; + device_vector prim_type; device_vector prim_visibility; device_vector prim_index; device_vector prim_object; @@ -72,6 +74,9 @@ public: device_vector tri_vindex; device_vector tri_verts; + device_vector cur_segs; + device_vector cur_keys; + /* objects */ device_vector objects; device_vector objects_vector; @@ -170,6 +175,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/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); -- cgit v1.2.3