forked from bartvdbraak/blender
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:
parent
857df8065f
commit
e9ba345c46
@ -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
|
||||
|
@ -63,6 +63,38 @@ enum_panorama_types = (
|
||||
('FISHEYE_EQUISOLID', "Fisheye Equisolid",
|
||||
"Similar to most fisheye modern lens, takes sensor dimensions into consideration"),
|
||||
)
|
||||
|
||||
enum_curve_presets = (
|
||||
('CUSTOM', "Custom", "Set general parameters"),
|
||||
('TANGENT_SHADING', "Tangent Normal", "Use planar geometry and tangent normals"),
|
||||
('TRUE_NORMAL', "True Normal", "Use true normals (good for thin strands)"),
|
||||
('ACCURATE_PRESET', "Accurate", "Use best settings (suitable for glass materials)"),
|
||||
)
|
||||
|
||||
enum_curve_primitives = (
|
||||
('TRIANGLES', "Triangles", "create triangle geometry around strands"),
|
||||
('LINE_SEGMENTS', "Line Segments", "use line segment primitives"),
|
||||
('CURVE_SEGMENTS', "?Curve Segments?", "use curve segment primitives (not implemented)"),
|
||||
)
|
||||
|
||||
enum_triangle_curves = (
|
||||
('CAMERA', "Planes", "create individual triangles forming planes that face camera"),
|
||||
('RIBBONS', "Ribbons", "create individual triangles forming ribbon"),
|
||||
('TESSELATED', "Tesselated", "create mesh surrounding each strand"),
|
||||
)
|
||||
|
||||
enum_line_curves = (
|
||||
('ACCURATE', "Accurate", "always take into consideration strand width for intersections"),
|
||||
('QT_CORRECTED', "corrected", "ignores width for initial intersection and corrects later"),
|
||||
('ENDCORRECTED', "correct found", "ignores width for all intersections and only corrects closest"),
|
||||
('QT_UNCORRECTED', "uncorrected", "calculates intersection without considering width"),
|
||||
)
|
||||
|
||||
enum_curves_interpolation = (
|
||||
('LINEAR', "Linear interpolation", "uses Linear interpolation between segments"),
|
||||
('CARDINAL', "Cardinal interpolation", "uses CARDINAL interpolation between segments"),
|
||||
('BSPLINE', "b-spline interpolation", "uses b-spline interpolation between segments"),
|
||||
)
|
||||
|
||||
class CyclesRenderSettings(bpy.types.PropertyGroup):
|
||||
@classmethod
|
||||
@ -573,6 +605,158 @@ class CyclesMeshSettings(bpy.types.PropertyGroup):
|
||||
del bpy.types.Curve.cycles
|
||||
del bpy.types.MetaBall.cycles
|
||||
|
||||
class CyclesCurveRenderSettings(bpy.types.PropertyGroup):
|
||||
@classmethod
|
||||
def register(cls):
|
||||
bpy.types.Scene.cycles_curves = PointerProperty(
|
||||
name="Cycles Hair Rendering Settings",
|
||||
description="Cycles hair rendering settings",
|
||||
type=cls,
|
||||
)
|
||||
cls.preset = EnumProperty(
|
||||
name="Mode",
|
||||
description="Hair rendering mode",
|
||||
items=enum_curve_presets,
|
||||
default='TRUE_NORMAL',
|
||||
)
|
||||
cls.primitive = EnumProperty(
|
||||
name="Primitive",
|
||||
description="Type of primitive used for hair rendering",
|
||||
items=enum_curve_primitives,
|
||||
default='LINE_SEGMENTS',
|
||||
)
|
||||
cls.triangle_method = EnumProperty(
|
||||
name="Mesh Geometry",
|
||||
description="Method for creating triangle geometry",
|
||||
items=enum_triangle_curves,
|
||||
default='CAMERA',
|
||||
)
|
||||
cls.line_method = EnumProperty(
|
||||
name="Intersection Method",
|
||||
description="Method for line segment intersection",
|
||||
items=enum_line_curves,
|
||||
default='ACCURATE',
|
||||
)
|
||||
cls.interpolation = EnumProperty(
|
||||
name="Interpolation",
|
||||
description="Interpolation method",
|
||||
items=enum_curves_interpolation,
|
||||
default='BSPLINE',
|
||||
)
|
||||
cls.use_backfacing = BoolProperty(
|
||||
name="Check back-faces",
|
||||
description="Tests back-faces of strands",
|
||||
default=False,
|
||||
)
|
||||
cls.use_encasing = BoolProperty(
|
||||
name="Exclude encasing",
|
||||
description="Ignores strands encasing a ray's initial location",
|
||||
default=True,
|
||||
)
|
||||
cls.use_tangent_normal_geometry = BoolProperty(
|
||||
name="Tangent normal geometry",
|
||||
description="Uses the tangent normal for actual normal",
|
||||
default=False,
|
||||
)
|
||||
cls.use_tangent_normal = BoolProperty(
|
||||
name="Tangent normal default",
|
||||
description="Uses the tangent normal for all normals",
|
||||
default=False,
|
||||
)
|
||||
cls.use_tangent_normal_correction = BoolProperty(
|
||||
name="strand slope correction",
|
||||
description="Corrects the tangent normal for the strands slope",
|
||||
default=False,
|
||||
)
|
||||
cls.use_cache = BoolProperty(
|
||||
name="Export Cached data",
|
||||
description="Export cached data with child strands (uses 'draw step' for subdivisions)",
|
||||
default=True,
|
||||
)
|
||||
cls.use_parents = BoolProperty(
|
||||
name="Use parent strands",
|
||||
description="Use parents with children",
|
||||
default=False,
|
||||
)
|
||||
cls.use_smooth = BoolProperty(
|
||||
name="Smooth Strands",
|
||||
description="Use vertex normals",
|
||||
default=True,
|
||||
)
|
||||
cls.use_joined = BoolProperty(
|
||||
name="Join",
|
||||
description="Fills gaps between segments (requires more memory)",
|
||||
default=False,
|
||||
)
|
||||
cls.use_curves = BoolProperty(
|
||||
name="Use Cycles Hair Rendering",
|
||||
description="Activate cycles hair rendering for particle system",
|
||||
default=True,
|
||||
)
|
||||
cls.segments = IntProperty(
|
||||
name="Segments",
|
||||
description="Number of segments between path keys (Note that this combines with the `draw step' value)",
|
||||
min=1, max=64,
|
||||
default=1,
|
||||
)
|
||||
cls.resolution = IntProperty(
|
||||
name="Resolution",
|
||||
description="Resolution of generated mesh",
|
||||
min=3, max=64,
|
||||
default=3,
|
||||
)
|
||||
cls.normalmix = FloatProperty(
|
||||
name="Normal mix",
|
||||
description="Scale factor for tangent normal removal (zero gives ray normal)",
|
||||
min=0, max=2.0,
|
||||
default=1,
|
||||
)
|
||||
cls.encasing_ratio = FloatProperty(
|
||||
name="Encasing ratio",
|
||||
description="Scale factor for encasing strand width",
|
||||
min=0, max=100.0,
|
||||
default=1.01,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def unregister(cls):
|
||||
del bpy.types.Scene.cycles_curves
|
||||
|
||||
class CyclesCurveSettings(bpy.types.PropertyGroup):
|
||||
@classmethod
|
||||
def register(cls):
|
||||
bpy.types.ParticleSettings.cycles = PointerProperty(
|
||||
name="Cycles Hair Settings",
|
||||
description="Cycles hair settings",
|
||||
type=cls,
|
||||
)
|
||||
cls.root_width = FloatProperty(
|
||||
name="Root Size Multiplier",
|
||||
description="Multiplier of particle size for the strand's width at root",
|
||||
min=0.0, max=1000.0,
|
||||
default=1.0,
|
||||
)
|
||||
cls.tip_width = FloatProperty(
|
||||
name="Tip Size Multiplier",
|
||||
description="Multiplier of particle size for the strand's width at tip",
|
||||
min=0.0, max=1000.0,
|
||||
default=0.0,
|
||||
)
|
||||
cls.shape = FloatProperty(
|
||||
name="Strand Shape",
|
||||
description="Strand shape parameter",
|
||||
min=-1.0, max=1.0,
|
||||
default=0.0,
|
||||
)
|
||||
cls.use_closetip = BoolProperty(
|
||||
name="Close tip",
|
||||
description="Sets tip radius to zero",
|
||||
default=True,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def unregister(cls):
|
||||
del bpy.types.ParticleSettings.cycles
|
||||
|
||||
def register():
|
||||
bpy.utils.register_class(CyclesRenderSettings)
|
||||
@ -582,6 +766,8 @@ def register():
|
||||
bpy.utils.register_class(CyclesWorldSettings)
|
||||
bpy.utils.register_class(CyclesVisibilitySettings)
|
||||
bpy.utils.register_class(CyclesMeshSettings)
|
||||
bpy.utils.register_class(CyclesCurveRenderSettings)
|
||||
bpy.utils.register_class(CyclesCurveSettings)
|
||||
|
||||
|
||||
def unregister():
|
||||
@ -592,3 +778,5 @@ def unregister():
|
||||
bpy.utils.unregister_class(CyclesWorldSettings)
|
||||
bpy.utils.unregister_class(CyclesMeshSettings)
|
||||
bpy.utils.unregister_class(CyclesVisibilitySettings)
|
||||
bpy.utils.unregister_class(CyclesCurveRenderSettings)
|
||||
bpy.utils.unregister_class(CyclesCurveSettings)
|
||||
|
@ -944,7 +944,95 @@ class CyclesParticle_PT_textures(CyclesButtonsPanel, Panel):
|
||||
else:
|
||||
slot = part.texture_slots[part.active_texture_index]
|
||||
layout.template_ID(slot, "texture", new="texture.new")
|
||||
|
||||
class CyclesParticle_PT_CurveSettings(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Cycles Hair Settings"
|
||||
bl_context = "particle"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
psys = context.particle_system
|
||||
device_type = context.user_preferences.system.compute_device_type
|
||||
if context.scene.cycles.feature_set == 'EXPERIMENTAL' and (context.scene.cycles.device == 'CPU' or device_type == 'NONE'):
|
||||
if CyclesButtonsPanel.poll(context) and psys:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
psys = context.particle_settings
|
||||
|
||||
cpsys = psys.cycles
|
||||
|
||||
row = layout.row()
|
||||
row.prop(cpsys, "shape", text="Shape")
|
||||
row.prop(cpsys, "use_closetip", text="Close tip")
|
||||
row = layout.row()
|
||||
row.prop(cpsys, "root_width", text="Root Width multiplier")
|
||||
row = layout.row()
|
||||
row.prop(cpsys, "tip_width", text="Tip Width multiplier")
|
||||
|
||||
class CyclesRender_PT_CurveRendering(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Cycles Hair Rendering"
|
||||
bl_context = "particle"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
device_type = context.user_preferences.system.compute_device_type
|
||||
if CyclesButtonsPanel.poll(context):
|
||||
if context.scene.cycles.feature_set == 'EXPERIMENTAL' and (context.scene.cycles.device == 'CPU' or device_type == 'NONE'):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
scene = context.scene
|
||||
csscene = scene.cycles_curves
|
||||
|
||||
row = layout.row()
|
||||
row.prop(csscene, "use_curves", text="Enable Cycles Hair")
|
||||
row = layout.row()
|
||||
row.prop(csscene, "preset", text="Mode")
|
||||
|
||||
if csscene.preset == 'CUSTOM':
|
||||
row = layout.row()
|
||||
row.prop(csscene, "primitive", text="Primitive")
|
||||
row = layout.row()
|
||||
|
||||
if csscene.primitive == 'TRIANGLES':
|
||||
row.prop(csscene, "triangle_method", text="Method")
|
||||
if csscene.triangle_method == 'TESSELATED':
|
||||
row = layout.row()
|
||||
row.prop(csscene, "resolution", text="Resolution")
|
||||
row = layout.row()
|
||||
row.prop(csscene, "use_smooth", text="Smooth")
|
||||
elif csscene.primitive == 'LINE_SEGMENTS':
|
||||
row.prop(csscene, "use_backfacing", text="Check back-faces")
|
||||
row = layout.row()
|
||||
row.prop(csscene, "use_encasing", text="Exclude encasing")
|
||||
if csscene.use_encasing:
|
||||
row.prop(csscene, "encasing_ratio", text="Ratio for encasing")
|
||||
row = layout.row()
|
||||
row.prop(csscene, "line_method", text="Method")
|
||||
row = layout.row()
|
||||
row.prop(csscene, "use_tangent_normal", text="Use tangent normal as default")
|
||||
row = layout.row()
|
||||
row.prop(csscene, "use_tangent_normal_geometry", text="Use tangent normal geometry")
|
||||
row = layout.row()
|
||||
row.prop(csscene, "use_tangent_normal_correction", text="Correct tangent normal for slope")
|
||||
row = layout.row()
|
||||
row.prop(csscene, "interpolation", text="Interpolation")
|
||||
row = layout.row()
|
||||
row.prop(csscene, "segments", text="Segments")
|
||||
row = layout.row()
|
||||
row.prop(csscene, "normalmix", text="Ray Mix")
|
||||
row = layout.row()
|
||||
row.prop(csscene, "use_cache", text="Export cache with children")
|
||||
if csscene.use_cache:
|
||||
row.prop(csscene, "use_parents", text="Include parents")
|
||||
|
||||
class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Simplify"
|
||||
|
898
intern/cycles/blender/blender_curves.cpp
Normal file
898
intern/cycles/blender/blender_curves.cpp
Normal file
@ -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();
|
||||
@ -435,16 +435,24 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated)
|
||||
PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles");
|
||||
|
||||
vector<Mesh::Triangle> oldtriangle = mesh->triangles;
|
||||
|
||||
/* compares curve_keys rather than strands in order to handle quick hair adjustsments in dynamic BVH - other methods could probably do this better*/
|
||||
vector<Mesh::CurveKey> oldcurve_keys = mesh->curve_keys;
|
||||
|
||||
mesh->clear();
|
||||
mesh->used_shaders = used_shaders;
|
||||
mesh->name = ustring(b_ob_data.name().c_str());
|
||||
|
||||
if(b_mesh) {
|
||||
if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision"))
|
||||
create_subd_mesh(mesh, b_mesh, &cmesh, used_shaders);
|
||||
else
|
||||
create_mesh(scene, mesh, b_mesh, used_shaders);
|
||||
if(!(hide_tris && experimental && is_cpu)) {
|
||||
if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision"))
|
||||
create_subd_mesh(mesh, b_mesh, &cmesh, used_shaders);
|
||||
else
|
||||
create_mesh(scene, mesh, b_mesh, used_shaders);
|
||||
}
|
||||
|
||||
if(experimental && is_cpu)
|
||||
sync_curves(mesh, b_mesh, b_ob, object_updated);
|
||||
|
||||
/* free derived mesh */
|
||||
b_data.meshes.remove(b_mesh);
|
||||
@ -471,6 +479,13 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated)
|
||||
if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0)
|
||||
rebuild = true;
|
||||
}
|
||||
|
||||
if(oldcurve_keys.size() != mesh->curve_keys.size())
|
||||
rebuild = true;
|
||||
else if(oldcurve_keys.size()) {
|
||||
if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(Mesh::CurveKey)*oldcurve_keys.size()) != 0)
|
||||
rebuild = true;
|
||||
}
|
||||
|
||||
mesh->tag_update(scene, rebuild);
|
||||
|
||||
|
@ -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];
|
||||
|
||||
pack_triangle(i, woop);
|
||||
if(pack.prim_type[i])
|
||||
pack_curve_seg(i, woop);
|
||||
else
|
||||
pack_triangle(i, woop);
|
||||
|
||||
memcpy(&pack.tri_woop[i * nsize], woop, sizeof(float4)*3);
|
||||
|
||||
int tob = pack.prim_object[i];
|
||||
@ -300,11 +355,15 @@ void BVH::pack_instances(size_t nodes_size)
|
||||
/* adjust primitive index to point to the triangle in the global array, for
|
||||
* meshes with transform applied and already in the top level BVH */
|
||||
for(size_t i = 0; i < pack.prim_index.size(); i++)
|
||||
if(pack.prim_index[i] != -1)
|
||||
pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset;
|
||||
if(pack.prim_index[i] != -1) {
|
||||
if(pack.prim_type[i])
|
||||
pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->curveseg_offset;
|
||||
else
|
||||
pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset;
|
||||
}
|
||||
|
||||
/* track offsets of instanced BVH data in global array */
|
||||
size_t tri_offset = pack.prim_index.size();
|
||||
size_t prim_offset = pack.prim_index.size();
|
||||
size_t nodes_offset = nodes_size;
|
||||
|
||||
/* clear array that gives the node indexes for instanced objects */
|
||||
@ -339,6 +398,7 @@ void BVH::pack_instances(size_t nodes_size)
|
||||
mesh_map.clear();
|
||||
|
||||
pack.prim_index.resize(prim_index_size);
|
||||
pack.prim_type.resize(prim_index_size);
|
||||
pack.prim_object.resize(prim_index_size);
|
||||
pack.prim_visibility.resize(prim_index_size);
|
||||
pack.tri_woop.resize(tri_woop_size);
|
||||
@ -346,6 +406,7 @@ void BVH::pack_instances(size_t nodes_size)
|
||||
pack.object_node.resize(objects.size());
|
||||
|
||||
int *pack_prim_index = (pack.prim_index.size())? &pack.prim_index[0]: NULL;
|
||||
int *pack_prim_type = (pack.prim_type.size())? &pack.prim_type[0]: NULL;
|
||||
int *pack_prim_object = (pack.prim_object.size())? &pack.prim_object[0]: NULL;
|
||||
uint *pack_prim_visibility = (pack.prim_visibility.size())? &pack.prim_visibility[0]: NULL;
|
||||
float4 *pack_tri_woop = (pack.tri_woop.size())? &pack.tri_woop[0]: NULL;
|
||||
@ -376,6 +437,7 @@ void BVH::pack_instances(size_t nodes_size)
|
||||
|
||||
int noffset = nodes_offset/nsize;
|
||||
int mesh_tri_offset = mesh->tri_offset;
|
||||
int mesh_curve_offset = mesh->curveseg_offset;
|
||||
|
||||
/* fill in node indexes for instances */
|
||||
if((bvh->pack.is_leaf.size() != 0) && bvh->pack.is_leaf[0])
|
||||
@ -389,10 +451,16 @@ void BVH::pack_instances(size_t nodes_size)
|
||||
if(bvh->pack.prim_index.size()) {
|
||||
size_t bvh_prim_index_size = bvh->pack.prim_index.size();
|
||||
int *bvh_prim_index = &bvh->pack.prim_index[0];
|
||||
int *bvh_prim_type = &bvh->pack.prim_type[0];
|
||||
uint *bvh_prim_visibility = &bvh->pack.prim_visibility[0];
|
||||
|
||||
for(size_t i = 0; i < bvh_prim_index_size; i++) {
|
||||
pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset;
|
||||
if(bvh->pack.prim_type[i])
|
||||
pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_curve_offset;
|
||||
else
|
||||
pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset;
|
||||
|
||||
pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i];
|
||||
pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i];
|
||||
pack_prim_object[pack_prim_index_offset] = 0; // unused for instances
|
||||
pack_prim_index_offset++;
|
||||
@ -401,7 +469,7 @@ void BVH::pack_instances(size_t nodes_size)
|
||||
|
||||
/* merge triangle intersection data */
|
||||
if(bvh->pack.tri_woop.size()) {
|
||||
memcpy(pack_tri_woop+pack_tri_woop_offset, &bvh->pack.tri_woop[0],
|
||||
memcpy(pack_tri_woop + pack_tri_woop_offset, &bvh->pack.tri_woop[0],
|
||||
bvh->pack.tri_woop.size()*sizeof(float4));
|
||||
pack_tri_woop_offset += bvh->pack.tri_woop.size();
|
||||
}
|
||||
@ -420,8 +488,8 @@ void BVH::pack_instances(size_t nodes_size)
|
||||
int4 data = bvh_nodes[i + nsize_bbox];
|
||||
|
||||
if(bvh_is_leaf && bvh_is_leaf[j]) {
|
||||
data.x += tri_offset;
|
||||
data.y += tri_offset;
|
||||
data.x += prim_offset;
|
||||
data.y += prim_offset;
|
||||
}
|
||||
else {
|
||||
data.x += (data.x < 0)? -noffset: noffset;
|
||||
@ -443,7 +511,7 @@ void BVH::pack_instances(size_t nodes_size)
|
||||
}
|
||||
|
||||
nodes_offset += bvh->pack.nodes.size();
|
||||
tri_offset += bvh->pack.prim_index.size();
|
||||
prim_offset += bvh->pack.prim_index.size();
|
||||
}
|
||||
}
|
||||
|
||||
@ -544,25 +612,37 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility
|
||||
|
||||
if(leaf) {
|
||||
/* refit leaf node */
|
||||
for(int tri = c0; tri < c1; tri++) {
|
||||
int tidx = pack.prim_index[tri];
|
||||
int tob = pack.prim_object[tri];
|
||||
for(int prim = c0; prim < c1; prim++) {
|
||||
int pidx = pack.prim_index[prim];
|
||||
int tob = pack.prim_object[prim];
|
||||
Object *ob = objects[tob];
|
||||
|
||||
if(tidx == -1) {
|
||||
if(pidx == -1) {
|
||||
/* object instance */
|
||||
bbox.grow(ob->bounds);
|
||||
}
|
||||
else {
|
||||
/* triangles */
|
||||
/* primitives */
|
||||
const Mesh *mesh = ob->mesh;
|
||||
int tri_offset = (params.top_level)? mesh->tri_offset: 0;
|
||||
const int *vidx = mesh->triangles[tidx - tri_offset].v;
|
||||
const float3 *vpos = &mesh->verts[0];
|
||||
|
||||
bbox.grow(vpos[vidx[0]]);
|
||||
bbox.grow(vpos[vidx[1]]);
|
||||
bbox.grow(vpos[vidx[2]]);
|
||||
if(pack.prim_type[prim]) {
|
||||
/* strands */
|
||||
int str_offset = (params.top_level)? mesh->curveseg_offset: 0;
|
||||
const int *hidx = mesh->curve_segs[pidx - str_offset].v;
|
||||
|
||||
bbox.grow(mesh->curve_keys[hidx[0]].loc, mesh->curve_keys[hidx[0]].radius);
|
||||
bbox.grow(mesh->curve_keys[hidx[1]].loc, mesh->curve_keys[hidx[1]].radius);
|
||||
}
|
||||
else {
|
||||
/* triangles */
|
||||
int tri_offset = (params.top_level)? mesh->tri_offset: 0;
|
||||
const int *vidx = mesh->triangles[pidx - tri_offset].v;
|
||||
const float3 *vpos = &mesh->verts[0];
|
||||
|
||||
bbox.grow(vpos[vidx[0]]);
|
||||
bbox.grow(vpos[vidx[1]]);
|
||||
bbox.grow(vpos[vidx[2]]);
|
||||
}
|
||||
}
|
||||
|
||||
visibility |= ob->visibility;
|
||||
|
@ -51,7 +51,9 @@ struct PackedBVH {
|
||||
/* object index to BVH node index mapping for instances */
|
||||
array<int> object_node;
|
||||
/* precomputed triangle intersection data, one triangle is 4x float4 */
|
||||
array<float4> tri_woop;
|
||||
array<float4> tri_woop;
|
||||
/* primitive type - triangle or strand (should be moved to flag?) */
|
||||
array<int> prim_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,14 +252,41 @@ void BVHSpatialSplit::split_reference(BVHBuild *builder, BVHReference& left, BVH
|
||||
/* loop over vertices/edges. */
|
||||
Object *ob = builder->objects[ref.prim_object()];
|
||||
const Mesh *mesh = ob->mesh;
|
||||
const int *inds = mesh->triangles[ref.prim_index()].v;
|
||||
const float3 *verts = &mesh->verts[0];
|
||||
const float3* v1 = &verts[inds[2]];
|
||||
|
||||
for(int i = 0; i < 3; i++) {
|
||||
const float3* v0 = v1;
|
||||
int vindex = inds[i];
|
||||
v1 = &verts[vindex];
|
||||
if (!ref.prim_type()) {
|
||||
const int *inds = mesh->triangles[ref.prim_index()].v;
|
||||
const float3 *verts = &mesh->verts[0];
|
||||
const float3* v1 = &verts[inds[2]];
|
||||
|
||||
for(int i = 0; i < 3; i++) {
|
||||
const float3* v0 = v1;
|
||||
int vindex = inds[i];
|
||||
v1 = &verts[vindex];
|
||||
float v0p = (*v0)[dim];
|
||||
float v1p = (*v1)[dim];
|
||||
|
||||
/* insert vertex to the boxes it belongs to. */
|
||||
if(v0p <= pos)
|
||||
left_bounds.grow(*v0);
|
||||
|
||||
if(v0p >= pos)
|
||||
right_bounds.grow(*v0);
|
||||
|
||||
/* edge intersects the plane => insert intersection to both boxes. */
|
||||
if((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) {
|
||||
float3 t = lerp(*v0, *v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
|
||||
left_bounds.grow(t);
|
||||
right_bounds.grow(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Strand split: NOTE - Currently ignores strand width and needs to be fixed.*/
|
||||
|
||||
const int *inds = mesh->curve_segs[ref.prim_index()].v;
|
||||
const float3* v0 = &mesh->curve_keys[inds[0]].loc;
|
||||
const float3* v1 = &mesh->curve_keys[inds[1]].loc;
|
||||
|
||||
float v0p = (*v0)[dim];
|
||||
float v1p = (*v1)[dim];
|
||||
|
||||
@ -270,6 +297,12 @@ void BVHSpatialSplit::split_reference(BVHBuild *builder, BVHReference& left, BVH
|
||||
if(v0p >= pos)
|
||||
right_bounds.grow(*v0);
|
||||
|
||||
if(v1p <= pos)
|
||||
left_bounds.grow(*v1);
|
||||
|
||||
if(v1p >= pos)
|
||||
right_bounds.grow(*v1);
|
||||
|
||||
/* edge intersects the plane => insert intersection to both boxes. */
|
||||
if((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) {
|
||||
float3 t = lerp(*v0, *v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
|
||||
@ -284,9 +317,9 @@ void BVHSpatialSplit::split_reference(BVHBuild *builder, BVHReference& left, BVH
|
||||
left_bounds.intersect(ref.bounds());
|
||||
right_bounds.intersect(ref.bounds());
|
||||
|
||||
/* set referecnes */
|
||||
left = BVHReference(left_bounds, ref.prim_index(), ref.prim_object());
|
||||
right = BVHReference(right_bounds, ref.prim_index(), ref.prim_object());
|
||||
/* set references */
|
||||
left = BVHReference(left_bounds, ref.prim_index(), ref.prim_object(), ref.prim_type());
|
||||
right = BVHReference(right_bounds, ref.prim_index(), ref.prim_object(), ref.prim_type());
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@ -205,6 +205,151 @@ __device_inline void bvh_triangle_intersect(KernelGlobals *kg, Intersection *ise
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __HAIR__
|
||||
__device_inline void bvh_curve_intersect(KernelGlobals *kg, Intersection *isect,
|
||||
float3 P, float3 idir, uint visibility, int object, int triAddr)
|
||||
{
|
||||
/* curve Intersection check */
|
||||
|
||||
int flags = kernel_data.curve_kernel_data.curveflags;
|
||||
|
||||
int prim = kernel_tex_fetch(__prim_index, triAddr);
|
||||
float4 v00 = kernel_tex_fetch(__cur_segs, prim);
|
||||
|
||||
int v1 = __float_as_int(v00.x);
|
||||
int v2 = __float_as_int(v00.y);
|
||||
|
||||
float4 P1 = kernel_tex_fetch(__cur_keys, v1);
|
||||
float4 P2 = kernel_tex_fetch(__cur_keys, v2);
|
||||
|
||||
float l = v00.w;
|
||||
float r1 = P1.w;
|
||||
float r2 = P2.w;
|
||||
float mr = max(r1,r2);
|
||||
float3 p1 = float4_to_float3(P1);
|
||||
float3 p2 = float4_to_float3(P2);
|
||||
float3 dif = P - p1;
|
||||
float3 dir = 1.0f/idir;
|
||||
|
||||
/* test bounding sphere intersection (introduce circular artifacts)*/
|
||||
/*float3 bvector = 0.5f * (p1 + p2) - P;
|
||||
float bvectorl_sq = len_squared(bvector);
|
||||
float dot_bv_dir = dot(bvector,dir);
|
||||
float maxdist = l * 0.5f + mr;
|
||||
if(bvectorl_sq - dot_bv_dir * dot_bv_dir > maxdist * maxdist)
|
||||
return;*/
|
||||
|
||||
/* obtain parameters and test midpoint distance for suitable modes*/
|
||||
float3 tg = (p2 - p1) / l;
|
||||
float gd = (r2 - r1) / l;
|
||||
float dirz = dot(dir,tg);
|
||||
float difz = dot(dif,tg);
|
||||
|
||||
float a = 1.0f - (dirz*dirz*(1 + gd*gd));
|
||||
float halfb = (dot(dir,dif) - dirz*(difz + gd*(difz*gd + r1)));
|
||||
|
||||
float tcentre = -halfb/a;
|
||||
float zcentre = difz + (dirz * tcentre);
|
||||
|
||||
if((tcentre > isect->t) && !(flags & CURVE_KN_ACCURATE))
|
||||
return;
|
||||
if((zcentre < 0 || zcentre > l) && !(flags & CURVE_KN_ACCURATE) && !(flags & CURVE_KN_INTERSECTCORRECTION))
|
||||
return;
|
||||
|
||||
/* test minimum separation*/
|
||||
float3 cprod = cross(tg, dir);
|
||||
float3 cprod2 = cross(tg, dif);
|
||||
float cprodsq = len_squared(cprod);
|
||||
float cprod2sq = len_squared(cprod2);
|
||||
float distscaled = dot(cprod,dif);
|
||||
|
||||
if(cprodsq == 0)
|
||||
distscaled = cprod2sq;
|
||||
else
|
||||
distscaled = (distscaled*distscaled)/cprodsq;
|
||||
|
||||
if(distscaled > mr*mr)
|
||||
return;
|
||||
|
||||
/* calculate true intersection*/
|
||||
float3 tdif = P - p1 + tcentre * dir;
|
||||
float tdifz = dot(tdif,tg);
|
||||
float tb = 2*(dot(dir,tdif) - dirz*(tdifz + gd*(tdifz*gd + r1)));
|
||||
float tc = dot(tdif,tdif) - tdifz * tdifz * (1 + gd*gd) - r1*r1 - 2*r1*tdifz*gd;
|
||||
float td = tb*tb - 4*a*tc;
|
||||
|
||||
if (td<0)
|
||||
return;
|
||||
|
||||
float rootd = 0.0f;
|
||||
float correction = 0.0f;
|
||||
if(flags & CURVE_KN_ACCURATE) {
|
||||
rootd = sqrtf(td);
|
||||
correction = ((-tb - rootd)/(2*a));
|
||||
}
|
||||
|
||||
float t = tcentre + correction;
|
||||
|
||||
if(t < isect->t) {
|
||||
|
||||
if(flags & CURVE_KN_INTERSECTCORRECTION) {
|
||||
rootd = sqrtf(td);
|
||||
correction = ((-tb - rootd)/(2*a));
|
||||
t = tcentre + correction;
|
||||
}
|
||||
|
||||
float z = zcentre + (dirz * correction);
|
||||
bool backface = false;
|
||||
|
||||
if(flags & CURVE_KN_BACKFACING && (t < 0.0f || z < 0 || z > l)) {
|
||||
backface = true;
|
||||
correction = ((-tb + rootd)/(2*a));
|
||||
t = tcentre + correction;
|
||||
z = zcentre + (dirz * correction);
|
||||
}
|
||||
|
||||
if(t > 0.0f && t < isect->t && z >= 0 && z <= l) {
|
||||
|
||||
if (flags & CURVE_KN_ENCLOSEFILTER) {
|
||||
|
||||
float enc_ratio = kernel_data.curve_kernel_data.encasing_ratio;
|
||||
if((dot(P - p1, tg) > -r1 * enc_ratio) && (dot(P - p2, tg) < r2 * enc_ratio)) {
|
||||
float a2 = 1.0f - (dirz*dirz*(1 + gd*gd*enc_ratio*enc_ratio));
|
||||
float c2 = dot(dif,dif) - difz * difz * (1 + gd*gd*enc_ratio*enc_ratio) - r1*r1*enc_ratio*enc_ratio - 2*r1*difz*gd*enc_ratio;
|
||||
if(a2*c2 < 0.0f)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*remove overlap - not functional yet*/
|
||||
/*if (flags & CURVE_KN_CURVEDATA) {
|
||||
float3 tg1 = float4_to_float3(kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0));
|
||||
float3 tg2 = float4_to_float3(kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1));
|
||||
if((dot(P + t * dir - p1, tg1) < 0.0f) || (dot(P + t * dir - p2, tg2) > 0.0f))
|
||||
return;
|
||||
}*/
|
||||
|
||||
#ifdef __VISIBILITY_FLAG__
|
||||
/* visibility flag test. we do it here under the assumption
|
||||
* that most triangles are culled by node flags */
|
||||
if(kernel_tex_fetch(__prim_visibility, triAddr) & visibility)
|
||||
#endif
|
||||
{
|
||||
/* record intersection */
|
||||
isect->prim = triAddr;
|
||||
isect->object = object;
|
||||
isect->u = z/l;
|
||||
isect->v = td/(4*a*a);
|
||||
isect->t = t;
|
||||
|
||||
if(backface)
|
||||
isect->u = -isect->u;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
__device_inline bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect)
|
||||
{
|
||||
/* traversal stack in CUDA thread-local memory */
|
||||
@ -281,10 +426,15 @@ __device_inline bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint
|
||||
nodeAddr = traversalStack[stackPtr];
|
||||
--stackPtr;
|
||||
|
||||
/* triangle intersection */
|
||||
/* primitive intersection */
|
||||
while(primAddr < primAddr2) {
|
||||
/* intersect ray against triangle */
|
||||
bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr);
|
||||
/* intersect ray against primitive */
|
||||
#ifdef __HAIR__
|
||||
if(kernel_tex_fetch(__prim_type, primAddr))
|
||||
bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr);
|
||||
else
|
||||
#endif
|
||||
bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr);
|
||||
|
||||
/* shadow ray early termination */
|
||||
if(visibility == PATH_RAY_SHADOW_OPAQUE && isect->prim != ~0)
|
||||
@ -401,10 +551,15 @@ __device_inline bool bvh_intersect_motion(KernelGlobals *kg, const Ray *ray, con
|
||||
nodeAddr = traversalStack[stackPtr];
|
||||
--stackPtr;
|
||||
|
||||
/* triangle intersection */
|
||||
/* primitive intersection */
|
||||
while(primAddr < primAddr2) {
|
||||
/* intersect ray against triangle */
|
||||
bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr);
|
||||
/* intersect ray against primitive */
|
||||
#ifdef __HAIR__
|
||||
if(kernel_tex_fetch(__prim_type, primAddr))
|
||||
bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr);
|
||||
else
|
||||
#endif
|
||||
bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr);
|
||||
|
||||
/* shadow ray early termination */
|
||||
if(visibility == PATH_RAY_SHADOW_OPAQUE && isect->prim != ~0)
|
||||
@ -545,5 +700,105 @@ __device_inline float3 bvh_triangle_refine(KernelGlobals *kg, ShaderData *sd, co
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __HAIR__
|
||||
__device_inline float3 bvh_curve_refine(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray, float t)
|
||||
{
|
||||
int flag = kernel_data.curve_kernel_data.curveflags;
|
||||
float3 P = ray->P;
|
||||
float3 D = ray->D;
|
||||
|
||||
if(isect->object != ~0) {
|
||||
#ifdef __OBJECT_MOTION__
|
||||
Transform tfm = sd->ob_itfm;
|
||||
#else
|
||||
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM);
|
||||
#endif
|
||||
|
||||
P = transform_point(&tfm, P);
|
||||
D = transform_direction(&tfm, D*t);
|
||||
D = normalize_len(D, &t);
|
||||
}
|
||||
|
||||
int prim = kernel_tex_fetch(__prim_index, isect->prim);
|
||||
float4 v00 = kernel_tex_fetch(__cur_segs, prim);
|
||||
|
||||
int v1 = __float_as_int(v00.x);
|
||||
int v2 = __float_as_int(v00.y);
|
||||
|
||||
float4 P1 = kernel_tex_fetch(__cur_keys, v1);
|
||||
float4 P2 = kernel_tex_fetch(__cur_keys, v2);
|
||||
float l = v00.w;
|
||||
float r1 = P1.w;
|
||||
float r2 = P2.w;
|
||||
float3 tg = float4_to_float3(P2 - P1) / l;
|
||||
float3 dif = P - float4_to_float3(P1) + t * D;
|
||||
float gd = ((r2 - r1)/l);
|
||||
|
||||
P = P + D*t;
|
||||
|
||||
dif = P - float4_to_float3(P1);
|
||||
|
||||
#ifdef __UV__
|
||||
sd->u = dot(dif,tg)/l;
|
||||
sd->v = 0.0f;
|
||||
#endif
|
||||
|
||||
if (flag & CURVE_KN_TRUETANGENTGNORMAL) {
|
||||
sd->Ng = -(D - tg * (dot(tg,D) * kernel_data.curve_kernel_data.normalmix));
|
||||
sd->Ng = normalize(sd->Ng);
|
||||
if (flag & CURVE_KN_NORMALCORRECTION)
|
||||
{
|
||||
//sd->Ng = normalize(sd->Ng);
|
||||
sd->Ng = sd->Ng - gd * tg;
|
||||
sd->Ng = normalize(sd->Ng);
|
||||
}
|
||||
}
|
||||
else {
|
||||
sd->Ng = (dif - tg * sd->u * l) / (P1.w + sd->u * l * gd);
|
||||
if (gd != 0.0f) {
|
||||
sd->Ng = sd->Ng - gd * tg ;
|
||||
sd->Ng = normalize(sd->Ng);
|
||||
}
|
||||
}
|
||||
|
||||
sd->N = sd->Ng;
|
||||
|
||||
if (flag & CURVE_KN_TANGENTGNORMAL && !(flag & CURVE_KN_TRUETANGENTGNORMAL)) {
|
||||
sd->N = -(D - tg * (dot(tg,D) * kernel_data.curve_kernel_data.normalmix));
|
||||
sd->N = normalize(sd->N);
|
||||
if (flag & CURVE_KN_NORMALCORRECTION) {
|
||||
//sd->N = normalize(sd->N);
|
||||
sd->N = sd->N - gd * tg;
|
||||
sd->N = normalize(sd->N);
|
||||
}
|
||||
}
|
||||
if (!(flag & CURVE_KN_TANGENTGNORMAL) && flag & CURVE_KN_TRUETANGENTGNORMAL) {
|
||||
sd->N = (dif - tg * sd->u * l) / (P1.w + sd->u * l * gd);
|
||||
if (gd != 0.0f) {
|
||||
sd->N = sd->N - gd * tg ;
|
||||
sd->N = normalize(sd->N);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __DPDU__
|
||||
/* dPdu/dPdv */
|
||||
sd->dPdu = tg;
|
||||
sd->dPdv = cross(tg,sd->Ng);
|
||||
#endif
|
||||
|
||||
if(isect->object != ~0) {
|
||||
#ifdef __OBJECT_MOTION__
|
||||
Transform tfm = sd->ob_tfm;
|
||||
#else
|
||||
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM);
|
||||
#endif
|
||||
|
||||
P = transform_point(&tfm, P);
|
||||
}
|
||||
|
||||
return P;
|
||||
}
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
|
@ -47,7 +47,13 @@ __device float3 direct_emissive_eval(KernelGlobals *kg, float rando,
|
||||
else
|
||||
#endif
|
||||
{
|
||||
shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time);
|
||||
#ifdef __HAIR__
|
||||
if(ls->type == LIGHT_STRAND)
|
||||
shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time, ls->prim);
|
||||
else
|
||||
#endif
|
||||
shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time);
|
||||
|
||||
ls->Ng = sd.Ng;
|
||||
|
||||
/* no path flag, we're evaluating this for all closures. that's weak but
|
||||
@ -150,7 +156,11 @@ __device float3 indirect_emission(KernelGlobals *kg, ShaderData *sd, float t, in
|
||||
/* evaluate emissive closure */
|
||||
float3 L = shader_emissive_eval(kg, sd);
|
||||
|
||||
#ifdef __HAIR__
|
||||
if(!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_SAMPLE_AS_LIGHT) && (sd->curve_seg == ~0)) {
|
||||
#else
|
||||
if(!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_SAMPLE_AS_LIGHT)) {
|
||||
#endif
|
||||
/* multiple importance sampling, get triangle light pdf,
|
||||
* and compute weight with respect to BSDF pdf */
|
||||
float pdf = triangle_light_pdf(kg, sd->Ng, sd->I, t);
|
||||
|
@ -326,6 +326,59 @@ __device float triangle_light_pdf(KernelGlobals *kg,
|
||||
return (t*t*kernel_data.integrator.pdf_triangles)/cos_pi;
|
||||
}
|
||||
|
||||
#ifdef __HAIR__
|
||||
/* Strand Light */
|
||||
|
||||
__device void curve_seg_light_sample(KernelGlobals *kg, int prim, int object,
|
||||
float randu, float randv, float time, LightSample *ls)
|
||||
{
|
||||
/* this strand code needs completion */
|
||||
float4 v00 = kernel_tex_fetch(__cur_segs, prim);
|
||||
|
||||
int v1 = __float_as_int(v00.x);
|
||||
int v2 = __float_as_int(v00.y);
|
||||
float l = v00.w;
|
||||
|
||||
float4 P1 = kernel_tex_fetch(__cur_keys, v1);
|
||||
float4 P2 = kernel_tex_fetch(__cur_keys, v2);
|
||||
float r1 = P1.w;
|
||||
float r2 = P2.w;
|
||||
float3 tg = float4_to_float3(P2 - P1) / l;
|
||||
float3 xc = make_float3(tg.x * tg.z, tg.y * tg.z, -(tg.x * tg.x + tg.y * tg.y));
|
||||
if (dot(xc, xc) == 0.0f)
|
||||
xc = make_float3(tg.x * tg.y, -(tg.x * tg.x + tg.z * tg.z), tg.z * tg.y);
|
||||
xc = normalize(xc);
|
||||
float3 yc = cross(tg, xc);
|
||||
float gd = ((r2 - r1)/l);
|
||||
|
||||
/* normal currently ignores gradient */
|
||||
ls->Ng = sinf(2 * M_PI_F * randv) * xc + cosf(2 * M_PI_F * randv) * yc;
|
||||
ls->P = randu * l * tg + (gd * l + r1) * ls->Ng;
|
||||
ls->object = object;
|
||||
ls->prim = prim;
|
||||
ls->t = 0.0f;
|
||||
ls->type = LIGHT_STRAND;
|
||||
ls->eval_fac = 1.0f;
|
||||
ls->shader = __float_as_int(v00.z);
|
||||
|
||||
#ifdef __INSTANCING__
|
||||
/* instance transform */
|
||||
if(ls->object >= 0) {
|
||||
#ifdef __OBJECT_MOTION__
|
||||
Transform itfm;
|
||||
Transform tfm = object_fetch_transform_motion_test(kg, object, time, &itfm);
|
||||
#else
|
||||
Transform tfm = object_fetch_transform(kg, ls->object, OBJECT_TRANSFORM);
|
||||
Transform itfm = object_fetch_transform(kg, ls->object, OBJECT_INVERSE_TRANSFORM);
|
||||
#endif
|
||||
|
||||
ls->P = transform_point(&tfm, ls->P);
|
||||
ls->Ng = normalize(transform_direction(&tfm, ls->Ng));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Light Distribution */
|
||||
|
||||
__device int light_distribution_sample(KernelGlobals *kg, float randt)
|
||||
@ -365,10 +418,19 @@ __device void light_sample(KernelGlobals *kg, float randt, float randu, float ra
|
||||
/* fetch light data */
|
||||
float4 l = kernel_tex_fetch(__light_distribution, index);
|
||||
int prim = __float_as_int(l.y);
|
||||
#ifdef __HAIR__
|
||||
/* currently use l.z to indicate is strand sample which isn't ideal */
|
||||
bool is_curve = __float_as_int(l.z) == 0.0f;
|
||||
#endif
|
||||
|
||||
if(prim >= 0) {
|
||||
int object = __float_as_int(l.w);
|
||||
triangle_light_sample(kg, prim, object, randu, randv, time, ls);
|
||||
#ifdef __HAIR__
|
||||
if (is_curve)
|
||||
curve_seg_light_sample(kg, prim, object, randu, randv, time, ls);
|
||||
else
|
||||
#endif
|
||||
triangle_light_sample(kg, prim, object, randu, randv, time, ls);
|
||||
}
|
||||
else {
|
||||
int point = -prim-1;
|
||||
|
@ -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,23 +66,64 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
|
||||
sd->time = ray->time;
|
||||
#endif
|
||||
|
||||
/* vectors */
|
||||
sd->P = bvh_triangle_refine(kg, sd, isect, ray);
|
||||
sd->Ng = Ng;
|
||||
sd->N = Ng;
|
||||
sd->I = -ray->D;
|
||||
sd->shader = shader;
|
||||
sd->prim = kernel_tex_fetch(__prim_index, isect->prim);
|
||||
#ifdef __HAIR__
|
||||
sd->curve_seg = ~0;
|
||||
#endif
|
||||
sd->ray_length = isect->t;
|
||||
|
||||
/* smooth normal */
|
||||
if(sd->shader & SHADER_SMOOTH_NORMAL)
|
||||
sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
|
||||
#ifdef __HAIR__
|
||||
if(kernel_tex_fetch(__prim_type, isect->prim)) {
|
||||
/* Strand Shader setting*/
|
||||
float4 CurSeg = kernel_tex_fetch(__cur_segs, sd->prim);
|
||||
sd->shader = __float_as_int(CurSeg.z);
|
||||
|
||||
sd->curve_seg = sd->prim;
|
||||
sd->prim = isect->prim;
|
||||
|
||||
float tcorr = isect->t;
|
||||
if(kernel_data.curve_kernel_data.curveflags & CURVE_KN_POSTINTERSECTCORRECTION) {
|
||||
tcorr = (isect->u < 0)? tcorr + sqrtf(isect->v) : tcorr - sqrtf(isect->v);
|
||||
sd->ray_length = tcorr;
|
||||
}
|
||||
sd->P = bvh_curve_refine(kg, sd, isect, ray, tcorr);
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
/* fetch triangle data */
|
||||
float4 Ns = kernel_tex_fetch(__tri_normal, sd->prim);
|
||||
float3 Ng = make_float3(Ns.x, Ns.y, Ns.z);
|
||||
sd->shader = __float_as_int(Ns.w);
|
||||
|
||||
#ifdef __UV__
|
||||
sd->u = isect->u;
|
||||
sd->v = isect->v;
|
||||
#endif
|
||||
|
||||
/* vectors */
|
||||
sd->P = bvh_triangle_refine(kg, sd, isect, ray);
|
||||
sd->Ng = Ng;
|
||||
sd->N = Ng;
|
||||
|
||||
|
||||
/* smooth normal */
|
||||
if(sd->shader & SHADER_SMOOTH_NORMAL)
|
||||
sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
|
||||
|
||||
#ifdef __DPDU__
|
||||
/* dPdu/dPdv */
|
||||
triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim);
|
||||
/* dPdu/dPdv */
|
||||
triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim);
|
||||
#endif
|
||||
|
||||
#ifdef __HAIR__
|
||||
}
|
||||
#endif
|
||||
|
||||
sd->I = -ray->D;
|
||||
|
||||
sd->flag = kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2);
|
||||
sd->flag |= kernel_tex_fetch(__object_flag, sd->object);
|
||||
|
||||
#ifdef __INSTANCING__
|
||||
if(isect->object != ~0) {
|
||||
/* instance transform */
|
||||
@ -135,7 +161,7 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
|
||||
|
||||
__device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
|
||||
const float3 P, const float3 Ng, const float3 I,
|
||||
int shader, int object, int prim, float u, float v, float t, float time)
|
||||
int shader, int object, int prim, float u, float v, float t, float time, int curve = ~0)
|
||||
{
|
||||
/* vectors */
|
||||
sd->P = P;
|
||||
@ -143,11 +169,15 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
|
||||
sd->Ng = Ng;
|
||||
sd->I = I;
|
||||
sd->shader = shader;
|
||||
#ifdef __HAIR__
|
||||
sd->curve_seg = curve;
|
||||
#endif
|
||||
|
||||
/* primitive */
|
||||
#ifdef __INSTANCING__
|
||||
sd->object = object;
|
||||
#endif
|
||||
/* currently no access to bvh prim index for strand sd->prim - this will cause errors with needs fixing*/
|
||||
sd->prim = prim;
|
||||
#ifdef __UV__
|
||||
sd->u = u;
|
||||
@ -183,8 +213,13 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
|
||||
#endif
|
||||
|
||||
/* smooth normal */
|
||||
#ifdef __HAIR__
|
||||
if(sd->shader & SHADER_SMOOTH_NORMAL && sd->curve_seg == ~0) {
|
||||
sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
|
||||
#else
|
||||
if(sd->shader & SHADER_SMOOTH_NORMAL) {
|
||||
sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
|
||||
#endif
|
||||
|
||||
#ifdef __INSTANCING__
|
||||
if(instanced)
|
||||
@ -194,10 +229,17 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
|
||||
|
||||
#ifdef __DPDU__
|
||||
/* dPdu/dPdv */
|
||||
#ifdef __HAIR__
|
||||
if(sd->prim == ~0 || sd->curve_seg != ~0) {
|
||||
sd->dPdu = make_float3(0.0f, 0.0f, 0.0f);
|
||||
sd->dPdv = make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
#else
|
||||
if(sd->prim == ~0) {
|
||||
sd->dPdu = make_float3(0.0f, 0.0f, 0.0f);
|
||||
sd->dPdv = make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim);
|
||||
|
||||
@ -279,6 +321,9 @@ __device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData
|
||||
sd->object = ~0;
|
||||
#endif
|
||||
sd->prim = ~0;
|
||||
#ifdef __HAIR__
|
||||
sd->curve_seg = ~0;
|
||||
#endif
|
||||
#ifdef __UV__
|
||||
sd->u = 0.0f;
|
||||
sd->v = 0.0f;
|
||||
@ -732,8 +777,20 @@ __device void shader_eval_displacement(KernelGlobals *kg, ShaderData *sd, Shader
|
||||
__device bool shader_transparent_shadow(KernelGlobals *kg, Intersection *isect)
|
||||
{
|
||||
int prim = kernel_tex_fetch(__prim_index, isect->prim);
|
||||
float4 Ns = kernel_tex_fetch(__tri_normal, prim);
|
||||
int shader = __float_as_int(Ns.w);
|
||||
int shader = 0;
|
||||
|
||||
#ifdef __HAIR__
|
||||
if(!kernel_tex_fetch(__prim_type, isect->prim)) {
|
||||
#endif
|
||||
float4 Ns = kernel_tex_fetch(__tri_normal, prim);
|
||||
shader = __float_as_int(Ns.w);
|
||||
#ifdef __HAIR__
|
||||
}
|
||||
else {
|
||||
float4 str = kernel_tex_fetch(__cur_segs, prim);
|
||||
shader = __float_as_int(str.z);
|
||||
}
|
||||
#endif
|
||||
int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*2);
|
||||
|
||||
return (flag & SD_HAS_SURFACE_TRANSPARENT) != 0;
|
||||
|
@ -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,88 +106,107 @@ __device_inline void triangle_dPdudv(KernelGlobals *kg, float3 *dPdu, float3 *dP
|
||||
|
||||
__device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy)
|
||||
{
|
||||
if(elem == ATTR_ELEMENT_FACE) {
|
||||
if(dx) *dx = 0.0f;
|
||||
if(dy) *dy = 0.0f;
|
||||
|
||||
return kernel_tex_fetch(__attributes_float, offset + sd->prim);
|
||||
}
|
||||
else if(elem == ATTR_ELEMENT_VERTEX) {
|
||||
float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, sd->prim));
|
||||
|
||||
float f0 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.x));
|
||||
float f1 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.y));
|
||||
float f2 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.z));
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
|
||||
if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
|
||||
#ifdef __HAIR__
|
||||
if(sd->curve_seg == ~0) {
|
||||
#endif
|
||||
if(elem == ATTR_ELEMENT_FACE) {
|
||||
if(dx) *dx = 0.0f;
|
||||
if(dy) *dy = 0.0f;
|
||||
|
||||
return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
|
||||
}
|
||||
else if(elem == ATTR_ELEMENT_CORNER) {
|
||||
int tri = offset + sd->prim*3;
|
||||
float f0 = kernel_tex_fetch(__attributes_float, tri + 0);
|
||||
float f1 = kernel_tex_fetch(__attributes_float, tri + 1);
|
||||
float f2 = kernel_tex_fetch(__attributes_float, tri + 2);
|
||||
return kernel_tex_fetch(__attributes_float, offset + sd->prim);
|
||||
}
|
||||
else if(elem == ATTR_ELEMENT_VERTEX) {
|
||||
float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, sd->prim));
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
|
||||
if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
|
||||
#endif
|
||||
float f0 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.x));
|
||||
float f1 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.y));
|
||||
float f2 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.z));
|
||||
|
||||
return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
|
||||
if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
|
||||
#endif
|
||||
|
||||
return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
|
||||
}
|
||||
else if(elem == ATTR_ELEMENT_CORNER) {
|
||||
int tri = offset + sd->prim*3;
|
||||
float f0 = kernel_tex_fetch(__attributes_float, tri + 0);
|
||||
float f1 = kernel_tex_fetch(__attributes_float, tri + 1);
|
||||
float f2 = kernel_tex_fetch(__attributes_float, tri + 2);
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
|
||||
if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
|
||||
#endif
|
||||
|
||||
return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
|
||||
}
|
||||
else {
|
||||
if(dx) *dx = 0.0f;
|
||||
if(dy) *dy = 0.0f;
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
#ifdef __HAIR__
|
||||
}
|
||||
else {
|
||||
if(dx) *dx = 0.0f;
|
||||
if(dy) *dy = 0.0f;
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
__device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy)
|
||||
{
|
||||
if(elem == ATTR_ELEMENT_FACE) {
|
||||
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + sd->prim));
|
||||
}
|
||||
else if(elem == ATTR_ELEMENT_VERTEX) {
|
||||
float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, sd->prim));
|
||||
|
||||
float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x)));
|
||||
float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y)));
|
||||
float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z)));
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
|
||||
if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
|
||||
#ifdef __HAIR__
|
||||
if(sd->curve_seg == ~0) {
|
||||
#endif
|
||||
if(elem == ATTR_ELEMENT_FACE) {
|
||||
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
|
||||
return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + sd->prim));
|
||||
}
|
||||
else if(elem == ATTR_ELEMENT_VERTEX) {
|
||||
float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, sd->prim));
|
||||
|
||||
float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x)));
|
||||
float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y)));
|
||||
float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z)));
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
|
||||
if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
|
||||
#endif
|
||||
|
||||
return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
|
||||
}
|
||||
else if(elem == ATTR_ELEMENT_CORNER) {
|
||||
int tri = offset + sd->prim*3;
|
||||
float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 0));
|
||||
float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 1));
|
||||
float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 2));
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
|
||||
if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
|
||||
#endif
|
||||
|
||||
return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
|
||||
}
|
||||
else {
|
||||
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
#ifdef __HAIR__
|
||||
}
|
||||
else if(elem == ATTR_ELEMENT_CORNER) {
|
||||
int tri = offset + sd->prim*3;
|
||||
float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 0));
|
||||
float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 1));
|
||||
float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 2));
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
|
||||
if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
|
||||
#endif
|
||||
|
||||
return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
|
||||
}
|
||||
else {
|
||||
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
else
|
||||
{
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* motion */
|
||||
@ -200,10 +219,16 @@ __device float4 triangle_motion_vector(KernelGlobals *kg, ShaderData *sd)
|
||||
int offset_pre = find_attribute(kg, sd, ATTR_STD_MOTION_PRE);
|
||||
int offset_post = find_attribute(kg, sd, ATTR_STD_MOTION_POST);
|
||||
|
||||
if(offset_pre != ATTR_STD_NOT_FOUND)
|
||||
motion_pre = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, offset_pre, NULL, NULL);
|
||||
if(offset_post != ATTR_STD_NOT_FOUND)
|
||||
motion_post = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, offset_post, NULL, NULL);
|
||||
#ifdef __HAIR__
|
||||
if(sd->curve_seg == ~0) {
|
||||
#endif
|
||||
if(offset_pre != ATTR_STD_NOT_FOUND)
|
||||
motion_pre = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, offset_pre, NULL, NULL);
|
||||
if(offset_post != ATTR_STD_NOT_FOUND)
|
||||
motion_post = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, offset_post, NULL, NULL);
|
||||
#ifdef __HAIR__
|
||||
}
|
||||
#endif
|
||||
|
||||
/* object motion. note that depending on the mesh having motion vectors, this
|
||||
* transformation was set match the world/object space of motion_pre/post */
|
||||
@ -259,8 +284,13 @@ __device float3 triangle_uv(KernelGlobals *kg, ShaderData *sd)
|
||||
{
|
||||
int offset_uv = find_attribute(kg, sd, ATTR_STD_UV);
|
||||
|
||||
#ifdef __HAIR__
|
||||
if(offset_uv == ATTR_STD_NOT_FOUND || sd->curve_seg != ~0)
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
#else
|
||||
if(offset_uv == ATTR_STD_NOT_FOUND)
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
#endif
|
||||
|
||||
float3 uv = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, offset_uv, NULL, NULL);
|
||||
uv.z = 1.0f;
|
||||
|
@ -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,27 +58,45 @@ __device void svm_node_attr(KernelGlobals *kg, ShaderData *sd, float *stack, uin
|
||||
|
||||
svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset);
|
||||
|
||||
/* fetch and store attribute */
|
||||
if(type == NODE_ATTR_FLOAT) {
|
||||
if(mesh_type == NODE_ATTR_FLOAT) {
|
||||
float f = triangle_attribute_float(kg, sd, elem, offset, NULL, NULL);
|
||||
stack_store_float(stack, out_offset, f);
|
||||
}
|
||||
#ifdef __HAIR__
|
||||
if (sd->curve_seg != ~0) {
|
||||
/*currently strand attributes aren't enabled - only exports stored uvs*/
|
||||
if(type == NODE_ATTR_FLOAT)
|
||||
stack_store_float(stack, out_offset, 0.0f);
|
||||
else {
|
||||
float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL);
|
||||
stack_store_float(stack, out_offset, average(f));
|
||||
float4 sd2 = kernel_tex_fetch(__tri_woop, sd->prim*3+2);
|
||||
float3 uv = make_float3(sd2.z,sd2.w,0.0f);
|
||||
stack_store_float3(stack, out_offset, uv);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(mesh_type == NODE_ATTR_FLOAT3) {
|
||||
float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL);
|
||||
stack_store_float3(stack, out_offset, f);
|
||||
else
|
||||
{
|
||||
#endif
|
||||
|
||||
/* fetch and store attribute */
|
||||
if(type == NODE_ATTR_FLOAT) {
|
||||
if(mesh_type == NODE_ATTR_FLOAT) {
|
||||
float f = triangle_attribute_float(kg, sd, elem, offset, NULL, NULL);
|
||||
stack_store_float(stack, out_offset, f);
|
||||
}
|
||||
else {
|
||||
float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL);
|
||||
stack_store_float(stack, out_offset, average(f));
|
||||
}
|
||||
}
|
||||
else {
|
||||
float f = triangle_attribute_float(kg, sd, elem, offset, NULL, NULL);
|
||||
stack_store_float3(stack, out_offset, make_float3(f, f, f));
|
||||
if(mesh_type == NODE_ATTR_FLOAT3) {
|
||||
float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL);
|
||||
stack_store_float3(stack, out_offset, f);
|
||||
}
|
||||
else {
|
||||
float f = triangle_attribute_float(kg, sd, elem, offset, NULL, NULL);
|
||||
stack_store_float3(stack, out_offset, make_float3(f, f, f));
|
||||
}
|
||||
}
|
||||
#ifdef __HAIR__
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
__device void svm_node_attr_bump_dx(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
|
||||
@ -91,30 +109,43 @@ __device void svm_node_attr_bump_dx(KernelGlobals *kg, ShaderData *sd, float *st
|
||||
svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset);
|
||||
|
||||
/* fetch and store attribute */
|
||||
if(type == NODE_ATTR_FLOAT) {
|
||||
if(mesh_type == NODE_ATTR_FLOAT) {
|
||||
float dx;
|
||||
float f = triangle_attribute_float(kg, sd, elem, offset, &dx, NULL);
|
||||
stack_store_float(stack, out_offset, f+dx);
|
||||
}
|
||||
else {
|
||||
float3 dx;
|
||||
float3 f = triangle_attribute_float3(kg, sd, elem, offset, &dx, NULL);
|
||||
stack_store_float(stack, out_offset, average(f+dx));
|
||||
}
|
||||
#ifdef __HAIR__
|
||||
if (sd->curve_seg != ~0) {
|
||||
/*currently strand attributes aren't enabled*/
|
||||
if(type == NODE_ATTR_FLOAT)
|
||||
stack_store_float(stack, out_offset, 0.0f);
|
||||
else
|
||||
stack_store_float3(stack, out_offset, make_float3(0.0f, 0.0f, 0.0f));
|
||||
}
|
||||
else {
|
||||
if(mesh_type == NODE_ATTR_FLOAT3) {
|
||||
float3 dx;
|
||||
float3 f = triangle_attribute_float3(kg, sd, elem, offset, &dx, NULL);
|
||||
stack_store_float3(stack, out_offset, f+dx);
|
||||
#endif
|
||||
if(type == NODE_ATTR_FLOAT) {
|
||||
if(mesh_type == NODE_ATTR_FLOAT) {
|
||||
float dx;
|
||||
float f = triangle_attribute_float(kg, sd, elem, offset, &dx, NULL);
|
||||
stack_store_float(stack, out_offset, f+dx);
|
||||
}
|
||||
else {
|
||||
float3 dx;
|
||||
float3 f = triangle_attribute_float3(kg, sd, elem, offset, &dx, NULL);
|
||||
stack_store_float(stack, out_offset, average(f+dx));
|
||||
}
|
||||
}
|
||||
else {
|
||||
float dx;
|
||||
float f = triangle_attribute_float(kg, sd, elem, offset, &dx, NULL);
|
||||
stack_store_float3(stack, out_offset, make_float3(f+dx, f+dx, f+dx));
|
||||
if(mesh_type == NODE_ATTR_FLOAT3) {
|
||||
float3 dx;
|
||||
float3 f = triangle_attribute_float3(kg, sd, elem, offset, &dx, NULL);
|
||||
stack_store_float3(stack, out_offset, f+dx);
|
||||
}
|
||||
else {
|
||||
float dx;
|
||||
float f = triangle_attribute_float(kg, sd, elem, offset, &dx, NULL);
|
||||
stack_store_float3(stack, out_offset, make_float3(f+dx, f+dx, f+dx));
|
||||
}
|
||||
}
|
||||
#ifdef __HAIR__
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
__device void svm_node_attr_bump_dy(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
|
||||
@ -127,30 +158,43 @@ __device void svm_node_attr_bump_dy(KernelGlobals *kg, ShaderData *sd, float *st
|
||||
svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset);
|
||||
|
||||
/* fetch and store attribute */
|
||||
if(type == NODE_ATTR_FLOAT) {
|
||||
if(mesh_type == NODE_ATTR_FLOAT) {
|
||||
float dy;
|
||||
float f = triangle_attribute_float(kg, sd, elem, offset, NULL, &dy);
|
||||
stack_store_float(stack, out_offset, f+dy);
|
||||
}
|
||||
else {
|
||||
float3 dy;
|
||||
float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, &dy);
|
||||
stack_store_float(stack, out_offset, average(f+dy));
|
||||
}
|
||||
#ifdef __HAIR__
|
||||
if (sd->curve_seg != ~0) {
|
||||
/*currently strand attributes aren't enabled*/
|
||||
if(type == NODE_ATTR_FLOAT)
|
||||
stack_store_float(stack, out_offset, 0.0f);
|
||||
else
|
||||
stack_store_float3(stack, out_offset, make_float3(0.0f, 0.0f, 0.0f));
|
||||
}
|
||||
else {
|
||||
if(mesh_type == NODE_ATTR_FLOAT3) {
|
||||
float3 dy;
|
||||
float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, &dy);
|
||||
stack_store_float3(stack, out_offset, f+dy);
|
||||
#endif
|
||||
if(type == NODE_ATTR_FLOAT) {
|
||||
if(mesh_type == NODE_ATTR_FLOAT) {
|
||||
float dy;
|
||||
float f = triangle_attribute_float(kg, sd, elem, offset, NULL, &dy);
|
||||
stack_store_float(stack, out_offset, f+dy);
|
||||
}
|
||||
else {
|
||||
float3 dy;
|
||||
float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, &dy);
|
||||
stack_store_float(stack, out_offset, average(f+dy));
|
||||
}
|
||||
}
|
||||
else {
|
||||
float dy;
|
||||
float f = triangle_attribute_float(kg, sd, elem, offset, NULL, &dy);
|
||||
stack_store_float3(stack, out_offset, make_float3(f+dy, f+dy, f+dy));
|
||||
if(mesh_type == NODE_ATTR_FLOAT3) {
|
||||
float3 dy;
|
||||
float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, &dy);
|
||||
stack_store_float3(stack, out_offset, f+dy);
|
||||
}
|
||||
else {
|
||||
float dy;
|
||||
float f = triangle_attribute_float(kg, sd, elem, offset, NULL, &dy);
|
||||
stack_store_float3(stack, out_offset, make_float3(f+dy, f+dy, f+dy));
|
||||
}
|
||||
}
|
||||
#ifdef __HAIR__
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@ -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 */
|
||||
if(sd->object == ~0) {
|
||||
#ifdef __HAIR__
|
||||
if(sd->object == ~0 || sd->curve_seg != ~0) {
|
||||
#else
|
||||
if(sd->object == ~0) {
|
||||
#endif
|
||||
stack_store_float3(stack, normal_offset, make_float3(0.0f, 0.0f, 0.0f));
|
||||
return;
|
||||
}
|
||||
@ -297,7 +301,11 @@ __device void svm_node_tangent(KernelGlobals *kg, ShaderData *sd, float *stack,
|
||||
/* UV map */
|
||||
int attr_offset = find_attribute(kg, sd, node.z);
|
||||
|
||||
#ifdef __HAIR__
|
||||
if(attr_offset == ATTR_STD_NOT_FOUND || sd->curve_seg != ~0)
|
||||
#else
|
||||
if(attr_offset == ATTR_STD_NOT_FOUND)
|
||||
#endif
|
||||
tangent = make_float3(0.0f, 0.0f, 0.0f);
|
||||
else
|
||||
tangent = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, attr_offset, NULL, NULL);
|
||||
@ -307,7 +315,11 @@ __device void svm_node_tangent(KernelGlobals *kg, ShaderData *sd, float *stack,
|
||||
int attr_offset = find_attribute(kg, sd, node.z);
|
||||
float3 generated;
|
||||
|
||||
#ifdef __HAIR__
|
||||
if(attr_offset == ATTR_STD_NOT_FOUND || sd->curve_seg != ~0)
|
||||
#else
|
||||
if(attr_offset == ATTR_STD_NOT_FOUND)
|
||||
#endif
|
||||
generated = sd->P;
|
||||
else
|
||||
generated = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, attr_offset, NULL, NULL);
|
||||
|
@ -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
|
||||
|
160
intern/cycles/render/curves.cpp
Normal file
160
intern/cycles/render/curves.cpp
Normal file
@ -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
|
||||
|
134
intern/cycles/render/curves.h
Normal file
134
intern/cycles/render/curves.h
Normal file
@ -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,39 +655,62 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene
|
||||
size_t vert_size = 0;
|
||||
size_t tri_size = 0;
|
||||
|
||||
size_t CurveKey_size = 0;
|
||||
size_t curve_seg_keys = 0;
|
||||
|
||||
foreach(Mesh *mesh, scene->meshes) {
|
||||
mesh->vert_offset = vert_size;
|
||||
mesh->tri_offset = tri_size;
|
||||
|
||||
mesh->curvekey_offset = CurveKey_size;
|
||||
mesh->curveseg_offset = curve_seg_keys;
|
||||
|
||||
vert_size += mesh->verts.size();
|
||||
tri_size += mesh->triangles.size();
|
||||
|
||||
CurveKey_size += mesh->curve_keys.size();
|
||||
curve_seg_keys += mesh->curve_segs.size();
|
||||
}
|
||||
|
||||
if(tri_size == 0)
|
||||
return;
|
||||
if(tri_size != 0) {
|
||||
/* normals */
|
||||
progress.set_status("Updating Mesh", "Computing normals");
|
||||
|
||||
/* normals */
|
||||
progress.set_status("Updating Mesh", "Computing normals");
|
||||
float4 *normal = dscene->tri_normal.resize(tri_size);
|
||||
float4 *vnormal = dscene->tri_vnormal.resize(vert_size);
|
||||
float4 *tri_verts = dscene->tri_verts.resize(vert_size);
|
||||
float4 *tri_vindex = dscene->tri_vindex.resize(tri_size);
|
||||
|
||||
float4 *normal = dscene->tri_normal.resize(tri_size);
|
||||
float4 *vnormal = dscene->tri_vnormal.resize(vert_size);
|
||||
float4 *tri_verts = dscene->tri_verts.resize(vert_size);
|
||||
float4 *tri_vindex = dscene->tri_vindex.resize(tri_size);
|
||||
foreach(Mesh *mesh, scene->meshes) {
|
||||
mesh->pack_normals(scene, &normal[mesh->tri_offset], &vnormal[mesh->vert_offset]);
|
||||
mesh->pack_verts(&tri_verts[mesh->vert_offset], &tri_vindex[mesh->tri_offset], mesh->vert_offset);
|
||||
|
||||
foreach(Mesh *mesh, scene->meshes) {
|
||||
mesh->pack_normals(scene, &normal[mesh->tri_offset], &vnormal[mesh->vert_offset]);
|
||||
mesh->pack_verts(&tri_verts[mesh->vert_offset], &tri_vindex[mesh->tri_offset], mesh->vert_offset);
|
||||
if(progress.get_cancel()) return;
|
||||
}
|
||||
|
||||
if(progress.get_cancel()) return;
|
||||
/* vertex coordinates */
|
||||
progress.set_status("Updating Mesh", "Copying Mesh to device");
|
||||
|
||||
device->tex_alloc("__tri_normal", dscene->tri_normal);
|
||||
device->tex_alloc("__tri_vnormal", dscene->tri_vnormal);
|
||||
device->tex_alloc("__tri_verts", dscene->tri_verts);
|
||||
device->tex_alloc("__tri_vindex", dscene->tri_vindex);
|
||||
}
|
||||
|
||||
/* vertex coordinates */
|
||||
progress.set_status("Updating Mesh", "Copying Mesh to device");
|
||||
if(curve_seg_keys != 0) {
|
||||
progress.set_status("Updating Mesh", "Copying Strands to device");
|
||||
|
||||
device->tex_alloc("__tri_normal", dscene->tri_normal);
|
||||
device->tex_alloc("__tri_vnormal", dscene->tri_vnormal);
|
||||
device->tex_alloc("__tri_verts", dscene->tri_verts);
|
||||
device->tex_alloc("__tri_vindex", dscene->tri_vindex);
|
||||
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)
|
||||
@ -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);
|
||||
|
58
source/blender/nodes/shader/nodes/node_shader_hair_info.c
Normal file
58
source/blender/nodes/shader/nodes/node_shader_hair_info.c
Normal file
@ -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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user