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.
This commit is contained in:
Stuart Broadfoot 2012-12-28 14:21:30 +00:00
parent 857df8065f
commit e9ba345c46
50 changed files with 3126 additions and 245 deletions

@ -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

@ -64,6 +64,38 @@ enum_panorama_types = (
"Similar to most fisheye modern lens, takes sensor dimensions into consideration"),
)
enum_curve_presets = (
('CUSTOM', "Custom", "Set general parameters"),
('TANGENT_SHADING', "Tangent Normal", "Use planar geometry and tangent normals"),
('TRUE_NORMAL', "True Normal", "Use true normals (good for thin strands)"),
('ACCURATE_PRESET', "Accurate", "Use best settings (suitable for glass materials)"),
)
enum_curve_primitives = (
('TRIANGLES', "Triangles", "create triangle geometry around strands"),
('LINE_SEGMENTS', "Line Segments", "use line segment primitives"),
('CURVE_SEGMENTS', "?Curve Segments?", "use curve segment primitives (not implemented)"),
)
enum_triangle_curves = (
('CAMERA', "Planes", "create individual triangles forming planes that face camera"),
('RIBBONS', "Ribbons", "create individual triangles forming ribbon"),
('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
def register(cls):
@ -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)

@ -945,6 +945,94 @@ class CyclesParticle_PT_textures(CyclesButtonsPanel, Panel):
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"

@ -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

@ -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();
@ -436,15 +436,23 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated)
vector<Mesh::Triangle> oldtriangle = mesh->triangles;
/* compares curve_keys rather than strands in order to handle quick hair adjustsments in dynamic BVH - other methods could probably do this better*/
vector<Mesh::CurveKey> oldcurve_keys = mesh->curve_keys;
mesh->clear();
mesh->used_shaders = used_shaders;
mesh->name = ustring(b_ob_data.name().c_str());
if(b_mesh) {
if(!(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);
@ -472,6 +480,13 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated)
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);
return mesh;

@ -196,7 +196,7 @@ void BlenderSync::sync_background_light()
/* Object */
Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_ob, Transform& tfm, uint layer_flag, int motion)
Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_ob, Transform& tfm, uint layer_flag, int motion, bool hide_tris)
{
BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent);
@ -247,7 +247,7 @@ Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_P
bool use_holdout = (layer_flag & render_layer.holdout_layer) != 0;
/* mesh sync */
object->mesh = sync_mesh(b_ob, object_updated);
object->mesh = sync_mesh(b_ob, object_updated, hide_tris);
/* sspecial case not tracked by object update flags */
if(use_holdout != object->use_holdout) {
@ -390,7 +390,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion)
BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_dup->persistent_id();
/* sync object and mesh or light data */
Object *object = sync_object(*b_ob, persistent_id.data, *b_dup, tfm, ob_layer, motion);
Object *object = sync_object(*b_ob, persistent_id.data, *b_dup, tfm, ob_layer, motion, false);
/* sync possible particle data, note particle_id
* starts counting at 1, first is dummy particle */
@ -412,9 +412,23 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion)
/* check if we should render or hide particle emitter */
BL::Object::particle_systems_iterator b_psys;
for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys)
if(b_psys->settings().use_render_emitter())
bool hair_present = false;
bool show_emitter = false;
bool hide_tris = false;
for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) {
if((b_psys->settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys->settings().type()==BL::ParticleSettings::type_HAIR))
hair_present = true;
if(b_psys->settings().use_render_emitter()) {
hide = false;
show_emitter = true;
}
}
if(hair_present && !show_emitter)
hide_tris = true;
/* hide original object for duplis */
BL::Object parent = b_ob->parent();
@ -424,7 +438,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion)
if(!hide) {
/* object itself */
Transform tfm = get_transform(b_ob->matrix_world());
sync_object(*b_ob, NULL, PointerRNA_NULL, tfm, ob_layer, motion);
sync_object(*b_ob, NULL, PointerRNA_NULL, tfm, ob_layer, motion, hide_tris);
}
}

@ -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);

@ -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;

@ -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);
}

@ -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()

@ -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<int> prim_type;
vector<int> prim_index;
vector<int> 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];
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)
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++) {
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++;
@ -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,26 +612,38 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility
if(leaf) {
/* refit leaf node */
for(int tri = c0; tri < c1; tri++) {
int tidx = pack.prim_index[tri];
int tob = pack.prim_object[tri];
for(int prim = c0; prim < c1; prim++) {
int pidx = pack.prim_index[prim];
int tob = pack.prim_object[prim];
Object *ob = objects[tob];
if(tidx == -1) {
if(pidx == -1) {
/* object instance */
bbox.grow(ob->bounds);
}
else {
/* triangles */
/* primitives */
const Mesh *mesh = ob->mesh;
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[tidx - tri_offset].v;
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;
}

@ -52,6 +52,8 @@ struct PackedBVH {
array<int> object_node;
/* precomputed triangle intersection data, one triangle is 4x float4 */
array<float4> tri_woop;
/* primitive type - triangle or strand (should be moved to flag?) */
array<int> prim_type;
/* visibility visibilitys for primitives */
array<uint> prim_visibility;
/* mapping from BVH primitive index to true primitive index, as primitives
@ -101,9 +103,10 @@ protected:
bool cache_read(CacheData& key);
void cache_write(CacheData& key);
/* triangles */
void pack_triangles();
/* triangles and strands*/
void pack_primitives();
void pack_triangle(int idx, float4 woop[3]);
void pack_curve_seg(int idx, float4 woop[3]);
/* merge instance BVH's */
void pack_instances(size_t nodes_size);

@ -48,9 +48,10 @@ public:
/* Constructor / Destructor */
BVHBuild::BVHBuild(const vector<Object*>& objects_,
vector<int>& prim_index_, vector<int>& prim_object_,
vector<int>& prim_type_, vector<int>& prim_index_, vector<int>& 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<int>& p_type = prim_type;
vector<int>& p_index = prim_index;
vector<int>& 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();
}

@ -44,6 +44,7 @@ public:
/* Constructor/Destructor */
BVHBuild(
const vector<Object*>& objects,
vector<int>& prim_type,
vector<int>& prim_index,
vector<int>& prim_object,
const BVHParams& params,
@ -87,6 +88,7 @@ protected:
int num_original_references;
/* output primitive indexes and objects */
vector<int>& prim_type;
vector<int>& prim_index;
vector<int>& prim_object;

@ -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

@ -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;
}

@ -252,6 +252,8 @@ 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;
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]];
@ -277,6 +279,37 @@ void BVHSpatialSplit::split_reference(BVHBuild *builder, BVHReference& left, BVH
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];
/* insert vertex to the boxes it belongs to. */
if(v0p <= pos)
left_bounds.grow(*v0);
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));
left_bounds.grow(t);
right_bounds.grow(t);
}
}
/* intersect with original bounds. */
left_bounds.max[dim] = pos;
@ -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

@ -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,9 +426,14 @@ __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 */
/* 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 */
@ -401,9 +551,14 @@ __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 */
/* 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 */
@ -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

@ -47,7 +47,13 @@ __device float3 direct_emissive_eval(KernelGlobals *kg, float rando,
else
#endif
{
#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);

@ -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,9 +418,18 @@ __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);
#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 {

@ -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

@ -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,13 +66,45 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
sd->time = ray->time;
#endif
sd->prim = kernel_tex_fetch(__prim_index, isect->prim);
#ifdef __HAIR__
sd->curve_seg = ~0;
#endif
sd->ray_length = isect->t;
#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;
sd->I = -ray->D;
sd->shader = shader;
sd->ray_length = isect->t;
/* smooth normal */
if(sd->shader & SHADER_SMOOTH_NORMAL)
@ -98,6 +115,15 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
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);
int shader = 0;
#ifdef __HAIR__
if(!kernel_tex_fetch(__prim_type, isect->prim)) {
#endif
float4 Ns = kernel_tex_fetch(__tri_normal, prim);
int shader = __float_as_int(Ns.w);
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;

@ -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)

@ -106,6 +106,9 @@ __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)
{
#ifdef __HAIR__
if(sd->curve_seg == ~0) {
#endif
if(elem == ATTR_ELEMENT_FACE) {
if(dx) *dx = 0.0f;
if(dy) *dy = 0.0f;
@ -145,10 +148,19 @@ __device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *sd,
return 0.0f;
}
#ifdef __HAIR__
}
else {
return 0.0f;
}
#endif
}
__device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy)
{
#ifdef __HAIR__
if(sd->curve_seg == ~0) {
#endif
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);
@ -188,6 +200,13 @@ __device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData *s
return make_float3(0.0f, 0.0f, 0.0f);
}
#ifdef __HAIR__
}
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);
#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;

@ -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

@ -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);

@ -58,6 +58,21 @@ __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);
#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 {
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
{
#endif
/* fetch and store attribute */
if(type == NODE_ATTR_FLOAT) {
if(mesh_type == NODE_ATTR_FLOAT) {
@ -79,6 +94,9 @@ __device void svm_node_attr(KernelGlobals *kg, ShaderData *sd, float *stack, uin
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,6 +109,16 @@ __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 */
#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 {
#endif
if(type == NODE_ATTR_FLOAT) {
if(mesh_type == NODE_ATTR_FLOAT) {
float dx;
@ -115,6 +143,9 @@ __device void svm_node_attr_bump_dx(KernelGlobals *kg, ShaderData *sd, float *st
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,6 +158,16 @@ __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 */
#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 {
#endif
if(type == NODE_ATTR_FLOAT) {
if(mesh_type == NODE_ATTR_FLOAT) {
float dy;
@ -151,6 +192,9 @@ __device void svm_node_attr_bump_dy(KernelGlobals *kg, ShaderData *sd, float *st
stack_store_float3(stack, out_offset, make_float3(f+dy, f+dy, f+dy));
}
}
#ifdef __HAIR__
}
#endif
}
CCL_NAMESPACE_END

@ -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

@ -242,7 +242,11 @@ __device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *stac
if(space == NODE_NORMAL_MAP_TANGENT) {
/* tangent space */
#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);

@ -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,

@ -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

@ -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

@ -0,0 +1,134 @@
/*
* Copyright 2011, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __CURVES_H__
#define __CURVES_H__
#include "util_types.h"
#include "util_vector.h"
CCL_NAMESPACE_BEGIN
class Device;
class DeviceScene;
class Progress;
class Scene;
typedef enum curve_presets {
CURVE_CUSTOM,
CURVE_TANGENT_SHADING,
CURVE_TRUE_NORMAL,
CURVE_ACCURATE_PRESET
} curve_presets;
typedef enum curve_primitives {
CURVE_TRIANGLES,
CURVE_LINE_SEGMENTS,
CURVE_SEGMENTS
} curve_primitives;
typedef enum curve_triangles {
CURVE_CAMERA,
CURVE_RIBBONS,
CURVE_TESSELATED
} curve_triangles;
typedef enum curve_lines {
CURVE_ACCURATE,
CURVE_CORRECTED,
CURVE_POSTCORRECTED,
CURVE_UNCORRECTED
} curve_lines;
typedef enum curve_interpolation {
CURVE_LINEAR,
CURVE_CARDINAL,
CURVE_BSPLINE
} curve_interpolation;
class ParticleCurveData {
public:
ParticleCurveData();
~ParticleCurveData();
vector<int> psys_firstcurve;
vector<int> psys_curvenum;
vector<int> psys_shader;
vector<float> psys_rootradius;
vector<float> psys_tipradius;
vector<float> psys_shape;
vector<bool> psys_closetip;
vector<int> curve_firstkey;
vector<int> curve_keynum;
vector<float> curve_length;
vector<float> curve_u;
vector<float> curve_v;
vector<float3> curvekey_co;
vector<float> curvekey_time;
};
/* HairSystem Manager */
class CurveSystemManager {
public:
int primitive;
int line_method;
int interpolation;
int triangle_method;
int resolution;
int segments;
float normalmix;
float encasing_ratio;
bool use_curves;
bool use_smooth;
bool use_cache;
bool use_parents;
bool use_encasing;
bool use_backfacing;
bool use_tangent_normal;
bool use_tangent_normal_correction;
bool use_tangent_normal_geometry;
bool use_joined;
bool need_update;
bool need_mesh_update;
CurveSystemManager();
~CurveSystemManager();
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_free(Device *device, DeviceScene *dscene);
bool modified(const CurveSystemManager& CurveSystemManager);
bool modified_mesh(const CurveSystemManager& CurveSystemManager);
void tag_update(Scene *scene);
void tag_update_mesh();
};
CCL_NAMESPACE_END
#endif /* __CURVES_H__ */

@ -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;

@ -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,17 +655,24 @@ 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");
@ -608,6 +697,22 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene
device->tex_alloc("__tri_vindex", dscene->tri_vindex);
}
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);
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)
{
/* bvh build */
@ -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();

@ -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<uint> shader;
vector<bool> smooth;
vector<CurveKey> curve_keys;
vector<CurveData> curve_keysCD;
vector<CurveSeg> curve_segs;
vector<Curve_Attribute> curve_attrib;
vector<uint> 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);

@ -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()

@ -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)

@ -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;
}

@ -48,6 +48,7 @@ public:
MotionTransform motion;
bool use_motion;
bool use_holdout;
bool curverender;
float3 dupli_generated;
float2 dupli_uv;

@ -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()

@ -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<float4> bvh_nodes;
device_vector<uint> object_node;
device_vector<float4> tri_woop;
device_vector<uint> prim_type;
device_vector<uint> prim_visibility;
device_vector<uint> prim_index;
device_vector<uint> prim_object;
@ -72,6 +74,9 @@ public:
device_vector<float4> tri_vindex;
device_vector<float4> tri_verts;
device_vector<float4> cur_segs;
device_vector<float4> cur_keys;
/* objects */
device_vector<float4> objects;
device_vector<float4> 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;

@ -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);

@ -557,6 +557,7 @@ struct ShadeResult;
#define SH_NODE_BSDF_REFRACTION 173
#define SH_NODE_TANGENT 174
#define SH_NODE_NORMAL_MAP 175
#define SH_NODE_HAIR_INFO 176
/* custom defines options for Material node */
#define SH_NODE_MAT_DIFF 1

@ -2323,6 +2323,7 @@ static void registerShaderNodes(bNodeTreeType *ttype)
register_node_type_sh_layer_weight(ttype);
register_node_type_sh_tex_coord(ttype);
register_node_type_sh_particle_info(ttype);
register_node_type_sh_hair_info(ttype);
register_node_type_sh_bump(ttype);
register_node_type_sh_script(ttype);
register_node_type_sh_tangent(ttype);

@ -84,6 +84,7 @@ DefNode( ShaderNode, SH_NODE_LIGHT_PATH, 0, "LI
DefNode( ShaderNode, SH_NODE_LIGHT_FALLOFF, 0, "LIGHT_FALLOFF", LightFalloff, "Light Falloff", "" )
DefNode( ShaderNode, SH_NODE_OBJECT_INFO, 0, "OBJECT_INFO", ObjectInfo, "Object Info", "" )
DefNode( ShaderNode, SH_NODE_PARTICLE_INFO, 0, "PARTICLE_INFO", ParticleInfo, "Particle Info", "" )
DefNode( ShaderNode, SH_NODE_HAIR_INFO, 0, "HAIR_INFO", HairInfo, "Hair Info", "" )
DefNode( ShaderNode, SH_NODE_BUMP, 0, "BUMP", Bump, "Bump", "" )
DefNode( ShaderNode, SH_NODE_NORMAL_MAP, def_sh_normal_map, "NORMAL_MAP", NormalMap, "Normal Map", "" )
DefNode( ShaderNode, SH_NODE_TANGENT, def_sh_tangent, "TANGENT", Tangent, "Tangent", "" )

@ -238,7 +238,220 @@ static void rna_ParticleHairKey_location_object_set(PointerRNA *ptr, const float
}
}
/* property update functions */
static void rna_ParticleHairKey_co_object(HairKey *hairkey, Object *object, ParticleSystemModifierData *modifier, ParticleData *particle,
float n_co[3])
{
DerivedMesh *hairdm = (modifier->psys->flag & PSYS_HAIR_DYNAMICS) ? modifier->psys->hair_out_dm : NULL;
if (particle) {
if (hairdm) {
MVert *mvert = CDDM_get_vert(hairdm, particle->hair_index + (hairkey - particle->hair));
copy_v3_v3(n_co, mvert->co);
}
else {
float hairmat[4][4];
psys_mat_hair_to_object(object, modifier->dm, modifier->psys->part->from, particle, hairmat);
copy_v3_v3(n_co, hairkey->co);
mul_m4_v3(hairmat, n_co);
}
}
else {
zero_v3(n_co);
}
}
static void rna_Particle_uv_on_emitter(ParticleData *particle, ParticleSystemModifierData *modifier, float n_uv[2])
{
/*psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, nor, 0, 0, sd.orco, 0);*/
/* get uvco & mcol */
int num = particle->num_dmcache;
int from = modifier->psys->part->from;
if (num == DMCACHE_NOTFOUND)
if (particle->num < modifier->dm->getNumTessFaces(modifier->dm))
num = particle->num;
/* get uvco */
if (n_uv && ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) {
if (num != DMCACHE_NOTFOUND) {
MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE);
MTFace *mtface = (MTFace*)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, 0);
mtface += num;
psys_interpolate_uvs(mtface, mface->v4, particle->fuv, n_uv);
}
else {
n_uv[0] = 0.0f;
n_uv[1] = 0.0f;
}
}
}
static void rna_ParticleSystem_co_hair(ParticleSystem *particlesystem, Object *object, ParticleSystemModifierData *modifier, int particle_no, int step,
float n_co[3])
{
ParticleSettings *part = 0;
ParticleData *pars = 0;
ParticleCacheKey *cache = 0;
int totchild=0;
int path_nbr=0;
int totpart;
int max_k = 0;
if (particlesystem == NULL)
return;
part = particlesystem->part;
pars = particlesystem->particles;
if (part == NULL || pars == NULL || !psys_check_enabled(object, particlesystem))
return;
if (part->ren_as==PART_DRAW_OB || part->ren_as==PART_DRAW_GR || part->ren_as==PART_DRAW_NOT)
return;
totchild = particlesystem->totchild * part->disp / 100;
/* can happen for disconnected/global hair */
if (part->type == PART_HAIR && !particlesystem->childcache)
totchild = 0;
totpart = particlesystem->totpart;
if (particle_no >= totpart + totchild)
return;
if (part->ren_as == PART_DRAW_PATH && particlesystem->pathcache)
path_nbr=(int)pow(2.0, part->draw_step);
if (particle_no<totpart) {
if (path_nbr) {
cache = particlesystem->pathcache[particle_no];
max_k = (int)cache->steps;
}
}
else {
if (path_nbr) {
cache = particlesystem->childcache[particle_no-totpart];
if (cache->steps < 0)
max_k = 0;
else
max_k = (int)cache->steps;
}
}
/*strands key loop data stored in cache + step->co*/
if (path_nbr) {
if (step>=0 && step<=path_nbr) {
if (step<=max_k)
copy_v3_v3(n_co, (cache+step)->co);
}
}
}
static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem, ParticleSystemModifierData *modifier, ParticleData *particle, int particle_no,
float n_uv[2])
{
ParticleSettings *part = 0;
int totpart;
int totchild = 0;
int num;
/* 1. check that everything is ok & updated */
if (particlesystem == NULL)
return;
part=particlesystem->part;
totchild = particlesystem->totchild;
/* can happen for disconnected/global hair */
if (part->type == PART_HAIR && !particlesystem->childcache)
totchild = 0;
totpart = particlesystem->totpart;
if (particle_no >= totpart + totchild)
return;
/* 3. start creating renderable things */
/* setup per particle individual stuff */
if (particle_no<totpart) {
/* get uvco & mcol */
num = particle->num_dmcache;
if (num == DMCACHE_NOTFOUND)
if (particle->num < modifier->dm->getNumTessFaces(modifier->dm))
num = particle->num;
if (n_uv && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) {
if (num != DMCACHE_NOTFOUND) {
MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE);
MTFace *mtface = (MTFace*)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, 0);
mtface += num;
psys_interpolate_uvs(mtface, mface->v4, particle->fuv, n_uv);
}
else {
n_uv[0] = 0.0f;
n_uv[1] = 0.0f;
}
}
}
else {
ChildParticle *cpa = particlesystem->child + particle_no-totpart;
num = cpa->num;
/* get uvco & mcol */
if (part->childtype == PART_CHILD_FACES) {
if (n_uv && ELEM(PART_FROM_FACE, PART_FROM_FACE, PART_FROM_VOLUME)) {
if (cpa->num != DMCACHE_NOTFOUND) {
MFace *mface = modifier->dm->getTessFaceData(modifier->dm, cpa->num, CD_MFACE);
MTFace *mtface = (MTFace*)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, 0);
mtface += cpa->num;
psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, n_uv);
}
else {
n_uv[0] = 0.0f;
n_uv[1] = 0.0f;
}
}
}
else {
ParticleData *parent = particlesystem->particles + cpa->parent;
num = parent->num_dmcache;
if (num == DMCACHE_NOTFOUND)
if (parent->num < modifier->dm->getNumTessFaces(modifier->dm))
num = parent->num;
if (n_uv && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) {
if (num != DMCACHE_NOTFOUND) {
MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE);
MTFace *mtface = (MTFace*)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, 0);
mtface += num;
psys_interpolate_uvs(mtface, mface->v4, parent->fuv, n_uv);
}
else {
n_uv[0] = 0.0f;
n_uv[1] = 0.0f;
}
}
}
}
}
static void particle_recalc(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr, short flag)
{
if (ptr->type == &RNA_ParticleSystem) {
@ -905,6 +1118,7 @@ static void rna_def_particle_hair_key(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
FunctionRNA *func;
srna = RNA_def_struct(brna, "ParticleHairKey", NULL);
RNA_def_struct_sdna(srna, "HairKey");
@ -928,6 +1142,19 @@ static void rna_def_particle_hair_key(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Location",
"Location of the hair key in its internal coordinate system, "
"relative to the emitting face");
/* Aided co func */
func = RNA_def_function(srna, "co_object", "rna_ParticleHairKey_co_object");
RNA_def_function_ui_description(func, "Obtain hairkey location with particle and modifier data");
prop = RNA_def_pointer(func, "object", "Object", "", "Object");
prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
prop = RNA_def_pointer(func, "particle", "Particle", "", "hair particle");
prop = RNA_def_float_vector(func, "co", 3, NULL, -FLT_MAX, FLT_MAX, "Co",
"Exported hairkey location", -1e4, 1e4);
RNA_def_property_flag(prop, PROP_THICK_WRAP);
RNA_def_function_output(func, prop);
}
static void rna_def_particle_key(BlenderRNA *brna)
@ -979,6 +1206,7 @@ static void rna_def_particle(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
FunctionRNA *func;
static EnumPropertyItem alive_items[] = {
/*{PARS_KILLED, "KILLED", 0, "Killed", ""}, */
@ -1083,6 +1311,15 @@ static void rna_def_particle(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Alive State", "");
/* short rt2; */
/* UVs */
func = RNA_def_function(srna, "uv_on_emitter", "rna_Particle_uv_on_emitter");
RNA_def_function_ui_description(func, "Obtain uv for particle on derived mesh");
prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
prop = RNA_def_property(func, "uv", PROP_FLOAT, PROP_COORDS);
RNA_def_property_array(prop, 2);
RNA_def_property_flag(prop, PROP_THICK_WRAP);
RNA_def_function_output(func, prop);
}
static void rna_def_particle_dupliweight(BlenderRNA *brna)
@ -2696,6 +2933,7 @@ static void rna_def_particle_system(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
FunctionRNA *func;
srna = RNA_def_struct(brna, "ParticleSystem", NULL);
RNA_def_struct_ui_text(srna, "Particle System", "Particle system in an object");
@ -2793,7 +3031,6 @@ static void rna_def_particle_system(BlenderRNA *brna)
"rna_ParticleSystem_active_particle_target_index_range");
RNA_def_property_ui_text(prop, "Active Particle Target Index", "");
/* billboard */
prop = RNA_def_property(srna, "billboard_normal_uv", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "bb_uvname[0]");
@ -2995,6 +3232,32 @@ static void rna_def_particle_system(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_struct_path_func(srna, "rna_ParticleSystem_path");
/* extract cached hair location data */
func = RNA_def_function(srna, "co_hair", "rna_ParticleSystem_co_hair");
RNA_def_function_ui_description(func, "Obtain cache hair data");
prop = RNA_def_pointer(func, "object", "Object", "", "Object");
prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
prop = RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX);
prop = RNA_def_int(func, "step", 0, INT_MIN, INT_MAX, "step no", "", INT_MIN, INT_MAX);
prop = RNA_def_float_vector(func, "co", 3, NULL, -FLT_MAX, FLT_MAX, "Co",
"Exported hairkey location", -1e4, 1e4);
RNA_def_property_flag(prop, PROP_THICK_WRAP);
RNA_def_function_output(func, prop);
/* extract hair UVs */
func = RNA_def_function(srna, "uv_on_emitter", "rna_ParticleSystem_uv_on_emitter");
RNA_def_function_ui_description(func, "Obtain uv for all particles");
prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
prop = RNA_def_pointer(func, "particle", "Particle", "", "Particle");
prop = RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX);
prop = RNA_def_property(func, "uv", PROP_FLOAT, PROP_COORDS);
RNA_def_property_array(prop, 2);
RNA_def_property_flag(prop, PROP_THICK_WRAP);
RNA_def_function_output(func, prop);
}
void RNA_def_particle(BlenderRNA *brna)

@ -168,6 +168,7 @@ set(SRC
shader/nodes/node_shader_mix_shader.c
shader/nodes/node_shader_normal_map.c
shader/nodes/node_shader_object_info.c
shader/nodes/node_shader_hair_info.c
shader/nodes/node_shader_output_lamp.c
shader/nodes/node_shader_output_material.c
shader/nodes/node_shader_output_world.c

@ -78,6 +78,7 @@ void register_node_type_sh_fresnel(struct bNodeTreeType *ttype);
void register_node_type_sh_layer_weight(struct bNodeTreeType *ttype);
void register_node_type_sh_tex_coord(struct bNodeTreeType *ttype);
void register_node_type_sh_particle_info(struct bNodeTreeType *ttype);
void register_node_type_sh_hair_info(struct bNodeTreeType *ttype);
void register_node_type_sh_script(struct bNodeTreeType *ttype);
void register_node_type_sh_normal_map(struct bNodeTreeType *ttype);
void register_node_type_sh_tangent(struct bNodeTreeType *ttype);

@ -0,0 +1,58 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* 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.
*
* The Original Code is Copyright (C) 2005 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "../node_shader_util.h"
static bNodeSocketTemplate outputs[] = {
{ SOCK_FLOAT, 0, N_("Is Strand"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 0, N_("Intercept"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 0, N_("Thickness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_VECTOR, 0, N_("Tangent Normal"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ -1, 0, "" }
};
static int node_shader_gpu_curve_attrib(GPUMaterial *mat, bNode *UNUSED(node), GPUNodeStack *in, GPUNodeStack *out)
{
return GPU_stack_link(mat, "NODE_HAIR_INFO", in, out);
}
/* node type definition */
void register_node_type_sh_hair_info(bNodeTreeType *ttype)
{
static bNodeType ntype;
node_type_base(ttype, &ntype, SH_NODE_HAIR_INFO, "Hair Info", NODE_CLASS_INPUT, 0);
node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, NULL, outputs);
node_type_size(&ntype, 150, 60, 200);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
node_type_exec(&ntype, NULL);
node_type_gpu(&ntype, node_shader_gpu_curve_attrib);
nodeRegisterType(ttype, &ntype);
}