forked from bartvdbraak/blender
* Volume Rendering
Finally in 2.5 branch :) Still things to do, but will continue working in here. I won't bother repeating the commit messages from the last year or so, however I've written up some technical docs to help Ton/Brecht/etc review and find their way around the code: http://wiki.blender.org/index.php/User:Broken/VolumeRenderingDev That above page has some known issues and todos listed, but I'm still interested in bug reports. Credits for this code: * Matt Ebb (with thanks to Red Cartel/ProMotion Studios) * Raul Fernandez Hernandez (Farsthary) for patches: o Light cache based multiple scattering approximation o Initial voxeldata texture code o Depth Cutoff threshold * Andre Susano Pinto for BVH range lookup addition * Trilinear interpolation adapted from pbrt * Tricubic interpolation from libtricubic
This commit is contained in:
commit
a81b458dbd
@ -73,6 +73,9 @@ class MATERIAL_PT_shading(MaterialButtonsPanel):
|
||||
__label__ = "Shading"
|
||||
COMPAT_ENGINES = set(['BLENDER_RENDER', 'BLENDER_GAME'])
|
||||
|
||||
def poll(self, context):
|
||||
return (context.material.type in ('SURFACE', 'WIRE', 'HALO'))
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
@ -83,7 +86,7 @@ class MATERIAL_PT_shading(MaterialButtonsPanel):
|
||||
|
||||
if mat:
|
||||
|
||||
if mat.type in ('SURFACE', 'WIRE', 'VOLUME'):
|
||||
if mat.type in ('SURFACE', 'WIRE'):
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
@ -113,6 +116,9 @@ class MATERIAL_PT_strand(MaterialButtonsPanel):
|
||||
mat = context.material
|
||||
return mat and (mat.type in ('SURFACE', 'WIRE')) and (context.scene.render_data.engine in self.COMPAT_ENGINES)
|
||||
|
||||
def poll(self, context):
|
||||
return context.material.type in ('SURFACE', 'WIRE', 'HALO')
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
@ -170,6 +176,9 @@ class MATERIAL_PT_options(MaterialButtonsPanel):
|
||||
__label__ = "Options"
|
||||
COMPAT_ENGINES = set(['BLENDER_RENDER', 'BLENDER_GAME'])
|
||||
|
||||
def poll(self, context):
|
||||
return (context.material.type in ('SURFACE', 'WIRE', 'HALO'))
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
@ -204,6 +213,9 @@ class MATERIAL_PT_shadow(MaterialButtonsPanel):
|
||||
__label__ = "Shadow"
|
||||
__default_closed__ = True
|
||||
COMPAT_ENGINES = set(['BLENDER_RENDER', 'BLENDER_GAME'])
|
||||
|
||||
def poll(self, context):
|
||||
return context.material.type in ('SURFACE', 'WIRE')
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
@ -236,7 +248,7 @@ class MATERIAL_PT_diffuse(MaterialButtonsPanel):
|
||||
|
||||
def poll(self, context):
|
||||
mat = context.material
|
||||
return mat and (mat.type != 'HALO') and (context.scene.render_data.engine in self.COMPAT_ENGINES)
|
||||
return mat and (mat.type in ('SURFACE', 'WIRE')) and (context.scene.render_data.engine in self.COMPAT_ENGINES)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
@ -290,7 +302,7 @@ class MATERIAL_PT_specular(MaterialButtonsPanel):
|
||||
|
||||
def poll(self, context):
|
||||
mat = context.material
|
||||
return mat and (mat.type != 'HALO') and (context.scene.render_data.engine in self.COMPAT_ENGINES)
|
||||
return mat and (mat.type in ('SURFACE', 'WIRE')) and (context.scene.render_data.engine in self.COMPAT_ENGINES)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
@ -499,6 +511,125 @@ class MATERIAL_PT_transp(MaterialButtonsPanel):
|
||||
sub.active = rayt.gloss < 1
|
||||
sub.itemR(rayt, "gloss_threshold", text="Threshold")
|
||||
sub.itemR(rayt, "gloss_samples", text="Samples")
|
||||
|
||||
class MATERIAL_PT_volume_shading(MaterialButtonsPanel):
|
||||
__label__ = "Shading"
|
||||
__default_closed__ = False
|
||||
COMPAT_ENGINES = set(['BLENDER_RENDER'])
|
||||
|
||||
def poll(self, context):
|
||||
return (context.material.type == 'VOLUME') and (context.scene.render_data.engine in self.COMPAT_ENGINES)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
mat = context.material
|
||||
vol = context.material.volume
|
||||
|
||||
split = layout.split()
|
||||
|
||||
row = split.row()
|
||||
row.itemR(vol, "density")
|
||||
row.itemR(vol, "scattering")
|
||||
|
||||
split = layout.split()
|
||||
col = split.column()
|
||||
col.itemR(vol, "absorption")
|
||||
col.itemR(vol, "absorption_color", text="")
|
||||
|
||||
|
||||
col = split.column()
|
||||
col.itemR(vol, "emission")
|
||||
col.itemR(vol, "emission_color", text="")
|
||||
|
||||
|
||||
|
||||
class MATERIAL_PT_volume_scattering(MaterialButtonsPanel):
|
||||
__label__ = "Scattering"
|
||||
__default_closed__ = False
|
||||
COMPAT_ENGINES = set(['BLENDER_RENDER'])
|
||||
|
||||
def poll(self, context):
|
||||
return (context.material.type == 'VOLUME') and (context.scene.render_data.engine in self.COMPAT_ENGINES)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
mat = context.material
|
||||
vol = context.material.volume
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.itemR(vol, "scattering_mode", text="")
|
||||
if vol.scattering_mode == 'SINGLE_SCATTERING':
|
||||
col.itemR(vol, "light_cache")
|
||||
sub = col.column()
|
||||
sub.active = vol.light_cache
|
||||
sub.itemR(vol, "cache_resolution")
|
||||
elif vol.scattering_mode in ('MULTIPLE_SCATTERING', 'SINGLE_PLUS_MULTIPLE_SCATTERING'):
|
||||
col.itemR(vol, "cache_resolution")
|
||||
|
||||
col = col.column(align=True)
|
||||
col.itemR(vol, "ms_diffusion")
|
||||
col.itemR(vol, "ms_spread")
|
||||
col.itemR(vol, "ms_intensity")
|
||||
|
||||
col = split.column()
|
||||
# col.itemL(text="Anisotropic Scattering:")
|
||||
col.itemR(vol, "phase_function", text="")
|
||||
if vol.phase_function in ('SCHLICK', 'HENYEY-GREENSTEIN'):
|
||||
col.itemR(vol, "asymmetry")
|
||||
|
||||
class MATERIAL_PT_volume_transp(MaterialButtonsPanel):
|
||||
__label__= "Transparency"
|
||||
COMPAT_ENGINES = set(['BLENDER_RENDER'])
|
||||
|
||||
def poll(self, context):
|
||||
mat = context.material
|
||||
return mat and (mat.type == 'VOLUME') and (context.scene.render_data.engine in self.COMPAT_ENGINES)
|
||||
|
||||
def draw_header(self, context):
|
||||
layout = self.layout
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
mat = context.material
|
||||
rayt = context.material.raytrace_transparency
|
||||
|
||||
row= layout.row()
|
||||
row.itemR(mat, "transparency_method", expand=True)
|
||||
row.active = mat.transparency and (not mat.shadeless)
|
||||
|
||||
class MATERIAL_PT_volume_integration(MaterialButtonsPanel):
|
||||
__label__ = "Integration"
|
||||
__default_closed__ = False
|
||||
COMPAT_ENGINES = set(['BLENDER_RENDER'])
|
||||
|
||||
def poll(self, context):
|
||||
return (context.material.type == 'VOLUME') and (context.scene.render_data.engine in self.COMPAT_ENGINES)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
mat = context.material
|
||||
vol = context.material.volume
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.itemL(text="Step Calculation:")
|
||||
col.itemR(vol, "step_calculation", text="")
|
||||
col = col.column(align=True)
|
||||
col.itemR(vol, "step_size")
|
||||
col.itemR(vol, "shading_step_size")
|
||||
|
||||
col = split.column()
|
||||
col.itemL()
|
||||
col.itemR(vol, "depth_cutoff")
|
||||
col.itemR(vol, "density_scale")
|
||||
|
||||
|
||||
class MATERIAL_PT_halo(MaterialButtonsPanel):
|
||||
__label__= "Halo"
|
||||
@ -587,6 +718,10 @@ bpy.types.register(MATERIAL_PT_shading)
|
||||
bpy.types.register(MATERIAL_PT_transp)
|
||||
bpy.types.register(MATERIAL_PT_mirror)
|
||||
bpy.types.register(MATERIAL_PT_sss)
|
||||
bpy.types.register(MATERIAL_PT_volume_shading)
|
||||
bpy.types.register(MATERIAL_PT_volume_scattering)
|
||||
bpy.types.register(MATERIAL_PT_volume_transp)
|
||||
bpy.types.register(MATERIAL_PT_volume_integration)
|
||||
bpy.types.register(MATERIAL_PT_halo)
|
||||
bpy.types.register(MATERIAL_PT_flare)
|
||||
bpy.types.register(MATERIAL_PT_physics)
|
||||
|
@ -210,35 +210,51 @@ class TEXTURE_PT_influence(TextureSlotPanel):
|
||||
sub.itemR(tex, factor, text=name, slider=True)
|
||||
|
||||
if ma:
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.itemL(text="Diffuse:")
|
||||
factor_but(col, tex.map_diffuse, "map_diffuse", "diffuse_factor", "Intensity")
|
||||
factor_but(col, tex.map_colordiff, "map_colordiff", "colordiff_factor", "Color")
|
||||
factor_but(col, tex.map_alpha, "map_alpha", "alpha_factor", "Alpha")
|
||||
factor_but(col, tex.map_translucency, "map_translucency", "translucency_factor", "Translucency")
|
||||
if ma.type in ['SURFACE', 'HALO', 'WIRE']:
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.itemL(text="Diffuse:")
|
||||
factor_but(col, tex.map_diffuse, "map_diffuse", "diffuse_factor", "Intensity")
|
||||
factor_but(col, tex.map_colordiff, "map_colordiff", "colordiff_factor", "Color")
|
||||
factor_but(col, tex.map_alpha, "map_alpha", "alpha_factor", "Alpha")
|
||||
factor_but(col, tex.map_translucency, "map_translucency", "translucency_factor", "Translucency")
|
||||
|
||||
col.itemL(text="Specular:")
|
||||
factor_but(col, tex.map_specular, "map_specular", "specular_factor", "Intensity")
|
||||
factor_but(col, tex.map_colorspec, "map_colorspec", "colorspec_factor", "Color")
|
||||
factor_but(col, tex.map_hardness, "map_hardness", "hardness_factor", "Hardness")
|
||||
col.itemL(text="Specular:")
|
||||
factor_but(col, tex.map_specular, "map_specular", "specular_factor", "Intensity")
|
||||
factor_but(col, tex.map_colorspec, "map_colorspec", "colorspec_factor", "Color")
|
||||
factor_but(col, tex.map_hardness, "map_hardness", "hardness_factor", "Hardness")
|
||||
|
||||
col = split.column()
|
||||
col.itemL(text="Shading:")
|
||||
factor_but(col, tex.map_ambient, "map_ambient", "ambient_factor", "Ambient")
|
||||
factor_but(col, tex.map_emit, "map_emit", "emit_factor", "Emit")
|
||||
factor_but(col, tex.map_mirror, "map_mirror", "mirror_factor", "Mirror")
|
||||
factor_but(col, tex.map_raymir, "map_raymir", "raymir_factor", "Ray Mirror")
|
||||
col = split.column()
|
||||
col.itemL(text="Shading:")
|
||||
factor_but(col, tex.map_ambient, "map_ambient", "ambient_factor", "Ambient")
|
||||
factor_but(col, tex.map_emit, "map_emit", "emit_factor", "Emit")
|
||||
factor_but(col, tex.map_mirror, "map_mirror", "mirror_factor", "Mirror")
|
||||
factor_but(col, tex.map_raymir, "map_raymir", "raymir_factor", "Ray Mirror")
|
||||
|
||||
col.itemL(text="Geometry:")
|
||||
factor_but(col, tex.map_normal, "map_normal", "normal_factor", "Normal")
|
||||
factor_but(col, tex.map_warp, "map_warp", "warp_factor", "Warp")
|
||||
factor_but(col, tex.map_displacement, "map_displacement", "displacement_factor", "Displace")
|
||||
col.itemL(text="Geometry:")
|
||||
factor_but(col, tex.map_normal, "map_normal", "normal_factor", "Normal")
|
||||
factor_but(col, tex.map_warp, "map_warp", "warp_factor", "Warp")
|
||||
factor_but(col, tex.map_displacement, "map_displacement", "displacement_factor", "Displace")
|
||||
|
||||
#sub = col.column()
|
||||
#sub.active = tex.map_translucency or tex.map_emit or tex.map_alpha or tex.map_raymir or tex.map_hardness or tex.map_ambient or tex.map_specularity or tex.map_reflection or tex.map_mirror
|
||||
#sub.itemR(tex, "default_value", text="Amount", slider=True)
|
||||
elif ma.type == 'VOLUME':
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
factor_but(col, tex.map_density, "map_density", "density_factor", "Density")
|
||||
factor_but(col, tex.map_emission, "map_emission", "emission_factor", "Emission")
|
||||
factor_but(col, tex.map_absorption, "map_absorption", "absorption_factor", "Absorption")
|
||||
factor_but(col, tex.map_scattering, "map_scattering", "scattering_factor", "Scattering")
|
||||
|
||||
col = split.column()
|
||||
col.itemL(text=" ")
|
||||
factor_but(col, tex.map_alpha, "map_coloremission", "coloremission_factor", "Emission Color")
|
||||
factor_but(col, tex.map_colorabsorption, "map_colorabsorption", "colorabsorption_factor", "Absorption Color")
|
||||
|
||||
|
||||
#sub = col.column()
|
||||
#sub.active = tex.map_translucency or tex.map_emit or tex.map_alpha or tex.map_raymir or tex.map_hardness or tex.map_ambient or tex.map_specularity or tex.map_reflection or tex.map_mirror
|
||||
#sub.itemR(tex, "default_value", text="Amount", slider=True)
|
||||
elif la:
|
||||
row = layout.row()
|
||||
factor_but(row, tex.map_color, "map_color", "color_factor", "Color")
|
||||
@ -596,6 +612,62 @@ class TEXTURE_PT_distortednoise(TextureTypePanel):
|
||||
flow.itemR(tex, "distortion_amount", text="Distortion")
|
||||
flow.itemR(tex, "noise_size", text="Size")
|
||||
flow.itemR(tex, "nabla")
|
||||
|
||||
class TEXTURE_PT_voxeldata(TextureButtonsPanel):
|
||||
__idname__= "TEXTURE_PT_voxeldata"
|
||||
__label__ = "Voxel Data"
|
||||
|
||||
def poll(self, context):
|
||||
tex = context.texture
|
||||
return (tex and tex.type == 'VOXEL_DATA')
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
tex = context.texture
|
||||
vd = tex.voxeldata
|
||||
|
||||
layout.itemR(vd, "file_format")
|
||||
if vd.file_format in ['BLENDER_VOXEL', 'RAW_8BIT']:
|
||||
layout.itemR(vd, "source_path")
|
||||
if vd.file_format == 'RAW_8BIT':
|
||||
layout.itemR(vd, "resolution")
|
||||
if vd.file_format == 'SMOKE':
|
||||
layout.itemR(vd, "domain_object")
|
||||
|
||||
layout.itemR(vd, "still")
|
||||
if vd.still:
|
||||
layout.itemR(vd, "still_frame_number")
|
||||
|
||||
layout.itemR(vd, "interpolation")
|
||||
layout.itemR(vd, "intensity")
|
||||
|
||||
class TEXTURE_PT_pointdensity(TextureButtonsPanel):
|
||||
__idname__= "TEXTURE_PT_pointdensity"
|
||||
__label__ = "Point Density"
|
||||
|
||||
def poll(self, context):
|
||||
tex = context.texture
|
||||
return (tex and tex.type == 'POINT_DENSITY')
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
tex = context.texture
|
||||
pd = tex.pointdensity
|
||||
|
||||
layout.itemR(pd, "point_source")
|
||||
layout.itemR(pd, "object")
|
||||
if pd.point_source == 'PARTICLE_SYSTEM':
|
||||
layout.item_pointerR(pd, "particle_system", pd.object, "particle_systems", text="")
|
||||
layout.itemR(pd, "radius")
|
||||
layout.itemR(pd, "falloff")
|
||||
if pd.falloff == 'SOFT':
|
||||
layout.itemR(pd, "falloff_softness")
|
||||
layout.itemR(pd, "color_source")
|
||||
layout.itemR(pd, "turbulence")
|
||||
layout.itemR(pd, "turbulence_size")
|
||||
layout.itemR(pd, "turbulence_depth")
|
||||
layout.itemR(pd, "turbulence_influence")
|
||||
|
||||
|
||||
bpy.types.register(TEXTURE_PT_context_texture)
|
||||
bpy.types.register(TEXTURE_PT_preview)
|
||||
@ -613,6 +685,8 @@ bpy.types.register(TEXTURE_PT_envmap)
|
||||
bpy.types.register(TEXTURE_PT_musgrave)
|
||||
bpy.types.register(TEXTURE_PT_voronoi)
|
||||
bpy.types.register(TEXTURE_PT_distortednoise)
|
||||
bpy.types.register(TEXTURE_PT_voxeldata)
|
||||
bpy.types.register(TEXTURE_PT_pointdensity)
|
||||
bpy.types.register(TEXTURE_PT_colors)
|
||||
bpy.types.register(TEXTURE_PT_mapping)
|
||||
bpy.types.register(TEXTURE_PT_influence)
|
||||
|
@ -40,6 +40,8 @@ struct ColorBand;
|
||||
struct HaloRen;
|
||||
struct TexMapping;
|
||||
struct EnvMap;
|
||||
struct PointDensity;
|
||||
struct VoxelData;
|
||||
|
||||
/* in ColorBand struct */
|
||||
#define MAXCOLORBAND 32
|
||||
@ -75,6 +77,16 @@ void BKE_free_envmap(struct EnvMap *env);
|
||||
struct EnvMap *BKE_add_envmap(void);
|
||||
struct EnvMap *BKE_copy_envmap(struct EnvMap *env);
|
||||
|
||||
void BKE_free_pointdensitydata(struct PointDensity *pd);
|
||||
void BKE_free_pointdensity(struct PointDensity *pd);
|
||||
struct PointDensity *BKE_add_pointdensity(void);
|
||||
struct PointDensity *BKE_copy_pointdensity(struct PointDensity *pd);
|
||||
|
||||
void BKE_free_voxeldatadata(struct VoxelData *vd);
|
||||
void BKE_free_voxeldata(struct VoxelData *vd);
|
||||
struct VoxelData *BKE_add_voxeldata(void);
|
||||
struct VoxelData *BKE_copy_voxeldata(struct VoxelData *vd);
|
||||
|
||||
int BKE_texture_dependsOnTime(const struct Tex *texture);
|
||||
|
||||
#endif
|
||||
|
@ -170,6 +170,21 @@ void init_material(Material *ma)
|
||||
ma->sss_front= 1.0f;
|
||||
ma->sss_back= 1.0f;
|
||||
|
||||
ma->vol.density = 1.0f;
|
||||
ma->vol.emission = 0.0f;
|
||||
ma->vol.absorption = 1.0f;
|
||||
ma->vol.scattering = 1.0f;
|
||||
ma->vol.emission_col[0] = ma->vol.emission_col[1] = ma->vol.emission_col[2] = 1.0f;
|
||||
ma->vol.absorption_col[0] = ma->vol.absorption_col[1] = ma->vol.absorption_col[2] = 0.0f;
|
||||
ma->vol.density_scale = 1.0f;
|
||||
ma->vol.depth_cutoff = 0.01f;
|
||||
ma->vol.stepsize_type = MA_VOL_STEP_RANDOMIZED;
|
||||
ma->vol.stepsize = 0.2f;
|
||||
ma->vol.shade_stepsize = 0.2f;
|
||||
ma->vol.shade_type = MA_VOL_SHADE_SINGLE;
|
||||
ma->vol.shadeflag |= MA_VOL_PRECACHESHADING;
|
||||
ma->vol.precache_resolution = 50;
|
||||
|
||||
ma->mode= MA_TRACEBLE|MA_SHADBUF|MA_SHADOW|MA_RAYBIAS|MA_TANGENT_STR|MA_ZTRANSP;
|
||||
|
||||
ma->preview = NULL;
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_arithb.h"
|
||||
#include "BLI_rand.h"
|
||||
#include "BLI_kdopbvh.h"
|
||||
|
||||
#include "DNA_texture_types.h"
|
||||
#include "DNA_key_types.h"
|
||||
@ -417,6 +418,8 @@ void free_texture(Tex *tex)
|
||||
free_plugin_tex(tex->plugin);
|
||||
if(tex->coba) MEM_freeN(tex->coba);
|
||||
if(tex->env) BKE_free_envmap(tex->env);
|
||||
if(tex->pd) BKE_free_pointdensity(tex->pd);
|
||||
if(tex->vd) BKE_free_voxeldata(tex->vd);
|
||||
BKE_previewimg_free(&tex->preview);
|
||||
BKE_icon_delete((struct ID*)tex);
|
||||
tex->id.icon_id = 0;
|
||||
@ -486,6 +489,16 @@ void default_tex(Tex *tex)
|
||||
tex->env->depth=0;
|
||||
}
|
||||
|
||||
if (tex->pd) {
|
||||
tex->pd->radius = 0.3f;
|
||||
tex->pd->falloff_type = TEX_PD_FALLOFF_STD;
|
||||
}
|
||||
|
||||
if (tex->vd) {
|
||||
tex->vd->resol[0] = tex->vd->resol[1] = tex->vd->resol[2] = 0;
|
||||
tex->vd->interp_type=TEX_VD_LINEAR;
|
||||
tex->vd->file_format=TEX_VD_SMOKE;
|
||||
}
|
||||
pit = tex->plugin;
|
||||
if (pit) {
|
||||
varstr= pit->varstr;
|
||||
@ -739,7 +752,7 @@ void autotexname(Tex *tex)
|
||||
{
|
||||
char texstr[20][12]= {"None" , "Clouds" , "Wood", "Marble", "Magic" , "Blend",
|
||||
"Stucci", "Noise" , "Image", "Plugin", "EnvMap" , "Musgrave",
|
||||
"Voronoi", "DistNoise", "", "", "", "", "", ""};
|
||||
"Voronoi", "DistNoise", "Point Density", "Voxel Data", "", "", "", ""};
|
||||
Image *ima;
|
||||
char di[FILE_MAXDIR], fi[FILE_MAXFILE];
|
||||
|
||||
@ -887,6 +900,106 @@ void BKE_free_envmap(EnvMap *env)
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
PointDensity *BKE_add_pointdensity(void)
|
||||
{
|
||||
PointDensity *pd;
|
||||
|
||||
pd= MEM_callocN(sizeof(PointDensity), "pointdensity");
|
||||
pd->flag = 0;
|
||||
pd->radius = 0.3f;
|
||||
pd->falloff_type = TEX_PD_FALLOFF_STD;
|
||||
pd->falloff_softness = 2.0;
|
||||
pd->source = TEX_PD_PSYS;
|
||||
pd->point_tree = NULL;
|
||||
pd->point_data = NULL;
|
||||
pd->noise_size = 0.5f;
|
||||
pd->noise_depth = 1;
|
||||
pd->noise_fac = 1.0f;
|
||||
pd->noise_influence = TEX_PD_NOISE_STATIC;
|
||||
pd->coba = add_colorband(1);
|
||||
pd->speed_scale = 1.0f;
|
||||
pd->totpoints = 0;
|
||||
pd->coba = add_colorband(1);
|
||||
pd->object = NULL;
|
||||
pd->psys = NULL;
|
||||
return pd;
|
||||
}
|
||||
|
||||
PointDensity *BKE_copy_pointdensity(PointDensity *pd)
|
||||
{
|
||||
PointDensity *pdn;
|
||||
|
||||
pdn= MEM_dupallocN(pd);
|
||||
pdn->point_tree = NULL;
|
||||
pdn->point_data = NULL;
|
||||
if(pdn->coba) pdn->coba= MEM_dupallocN(pdn->coba);
|
||||
|
||||
return pdn;
|
||||
}
|
||||
|
||||
void BKE_free_pointdensitydata(PointDensity *pd)
|
||||
{
|
||||
if (pd->point_tree) {
|
||||
BLI_bvhtree_free(pd->point_tree);
|
||||
pd->point_tree = NULL;
|
||||
}
|
||||
if (pd->point_data) {
|
||||
MEM_freeN(pd->point_data);
|
||||
pd->point_data = NULL;
|
||||
}
|
||||
if(pd->coba) MEM_freeN(pd->coba);
|
||||
}
|
||||
|
||||
void BKE_free_pointdensity(PointDensity *pd)
|
||||
{
|
||||
BKE_free_pointdensitydata(pd);
|
||||
MEM_freeN(pd);
|
||||
}
|
||||
|
||||
|
||||
void BKE_free_voxeldatadata(struct VoxelData *vd)
|
||||
{
|
||||
if (vd->dataset) {
|
||||
MEM_freeN(vd->dataset);
|
||||
vd->dataset = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void BKE_free_voxeldata(struct VoxelData *vd)
|
||||
{
|
||||
BKE_free_voxeldatadata(vd);
|
||||
MEM_freeN(vd);
|
||||
}
|
||||
|
||||
struct VoxelData *BKE_add_voxeldata(void)
|
||||
{
|
||||
VoxelData *vd;
|
||||
|
||||
vd= MEM_callocN(sizeof(struct VoxelData), "voxeldata");
|
||||
vd->dataset = NULL;
|
||||
vd->resol[0] = vd->resol[1] = vd->resol[2] = 1;
|
||||
vd->interp_type= TEX_VD_LINEAR;
|
||||
vd->file_format= TEX_VD_SMOKE;
|
||||
vd->int_multiplier = 1.0;
|
||||
vd->object = NULL;
|
||||
|
||||
return vd;
|
||||
}
|
||||
|
||||
struct VoxelData *BKE_copy_voxeldata(struct VoxelData *vd)
|
||||
{
|
||||
VoxelData *vdn;
|
||||
|
||||
vdn= MEM_dupallocN(vd);
|
||||
vdn->dataset = NULL;
|
||||
|
||||
return vdn;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
int BKE_texture_dependsOnTime(const struct Tex *texture)
|
||||
{
|
||||
|
@ -325,6 +325,7 @@ void printvec4f(char *str, float v[4]);
|
||||
|
||||
void VecAddf(float *v, float *v1, float *v2);
|
||||
void VecSubf(float *v, float *v1, float *v2);
|
||||
void VecMulVecf(float *v, float *v1, float *v2);
|
||||
void VecLerpf(float *target, float *a, float *b, float t);
|
||||
void VecMidf(float *v, float *v1, float *v2);
|
||||
|
||||
|
@ -71,6 +71,8 @@ typedef void (*BVHTree_NearestPointCallback) (void *userdata, int index, const f
|
||||
/* callback must update hit in case it finds a nearest successful hit */
|
||||
typedef void (*BVHTree_RayCastCallback) (void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit);
|
||||
|
||||
/* callback to range search query */
|
||||
typedef void (*BVHTree_RangeQuery) (void *userdata, int index, float squared_dist);
|
||||
|
||||
BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis);
|
||||
void BLI_bvhtree_free(BVHTree *tree);
|
||||
@ -95,5 +97,9 @@ int BLI_bvhtree_ray_cast(BVHTree *tree, const float *co, const float *dir, float
|
||||
|
||||
float BLI_bvhtree_bb_raycast(float *bv, float *light_start, float *light_end, float *pos);
|
||||
|
||||
/* range query */
|
||||
int BLI_bvhtree_range_query(BVHTree *tree, const float *co, float radius, BVHTree_RangeQuery callback, void *userdata);
|
||||
|
||||
|
||||
#endif // BLI_KDOPBVH_H
|
||||
|
||||
|
40
source/blender/blenlib/BLI_voxel.h
Normal file
40
source/blender/blenlib/BLI_voxel.h
Normal file
@ -0,0 +1,40 @@
|
||||
/**
|
||||
*
|
||||
* ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Matt Ebb, Raul Fernandez Hernandez (Farsthary).
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef BLI_VOXEL_H
|
||||
#define BLI_VOXEL_H
|
||||
|
||||
/* find the index number of a voxel, given x/y/z integer coords and resolution vector */
|
||||
#define V_I(x, y, z, res) ( (z)*(res)[1]*(res)[0] + (y)*(res)[0] + (x) )
|
||||
|
||||
/* all input coordinates must be in bounding box 0.0 - 1.0 */
|
||||
float voxel_sample_nearest(float *data, int *res, float *co);
|
||||
float voxel_sample_trilinear(float *data, int *res, float *co);
|
||||
float voxel_sample_tricubic(float *data, int *res, float *co);
|
||||
|
||||
#endif /* BLI_VOXEL_H */
|
@ -72,10 +72,10 @@ struct BVHTree
|
||||
char start_axis, stop_axis; // KDOP_AXES array indices according to axis
|
||||
};
|
||||
|
||||
typedef struct BVHOverlapData
|
||||
{
|
||||
BVHTree *tree1, *tree2;
|
||||
BVHTreeOverlap *overlap;
|
||||
typedef struct BVHOverlapData
|
||||
{
|
||||
BVHTree *tree1, *tree2;
|
||||
BVHTreeOverlap *overlap;
|
||||
int i, max_overlap; /* i is number of overlaps */
|
||||
int start_axis, stop_axis;
|
||||
} BVHOverlapData;
|
||||
@ -109,7 +109,7 @@ typedef struct BVHRayCastData
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Bounding Volume Hierarchy Definition
|
||||
//
|
||||
//
|
||||
// Notes: From OBB until 26-DOP --> all bounding volumes possible, just choose type below
|
||||
// Notes: You have to choose the type at compile time ITM
|
||||
// Notes: You can choose the tree type --> binary, quad, octree, choose below
|
||||
@ -188,10 +188,10 @@ int ADJUST_MEMORY(void *local_memblock, void **memblock, int new_size, int *max_
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Introsort
|
||||
// Introsort
|
||||
// with permission deriven from the following Java code:
|
||||
// http://ralphunden.net/content/tutorials/a-guide-to-introsort/
|
||||
// and he derived it from the SUN STL
|
||||
// and he derived it from the SUN STL
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
static int size_threshold = 16;
|
||||
/*
|
||||
@ -362,7 +362,7 @@ static void create_kdop_hull(BVHTree *tree, BVHNode *node, float *co, int numpoi
|
||||
float newminmax;
|
||||
float *bv = node->bv;
|
||||
int i, k;
|
||||
|
||||
|
||||
// don't init boudings for the moving case
|
||||
if(!moving)
|
||||
{
|
||||
@ -372,7 +372,7 @@ static void create_kdop_hull(BVHTree *tree, BVHNode *node, float *co, int numpoi
|
||||
bv[2*i + 1] = -FLT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for(k = 0; k < numpoints; k++)
|
||||
{
|
||||
// for all Axes.
|
||||
@ -394,7 +394,7 @@ static void refit_kdop_hull(BVHTree *tree, BVHNode *node, int start, int end)
|
||||
int i, j;
|
||||
float *bv = node->bv;
|
||||
|
||||
|
||||
|
||||
for (i = tree->start_axis; i < tree->stop_axis; i++)
|
||||
{
|
||||
bv[2*i] = FLT_MAX;
|
||||
@ -406,10 +406,10 @@ static void refit_kdop_hull(BVHTree *tree, BVHNode *node, int start, int end)
|
||||
// for all Axes.
|
||||
for (i = tree->start_axis; i < tree->stop_axis; i++)
|
||||
{
|
||||
newmin = tree->nodes[j]->bv[(2 * i)];
|
||||
newmin = tree->nodes[j]->bv[(2 * i)];
|
||||
if ((newmin < bv[(2 * i)]))
|
||||
bv[(2 * i)] = newmin;
|
||||
|
||||
|
||||
newmax = tree->nodes[j]->bv[(2 * i) + 1];
|
||||
if ((newmax > bv[(2 * i) + 1]))
|
||||
bv[(2 * i) + 1] = newmax;
|
||||
@ -427,14 +427,14 @@ static char get_largest_axis(float *bv)
|
||||
middle_point[0] = (bv[1]) - (bv[0]); // x axis
|
||||
middle_point[1] = (bv[3]) - (bv[2]); // y axis
|
||||
middle_point[2] = (bv[5]) - (bv[4]); // z axis
|
||||
if (middle_point[0] > middle_point[1])
|
||||
if (middle_point[0] > middle_point[1])
|
||||
{
|
||||
if (middle_point[0] > middle_point[2])
|
||||
return 1; // max x axis
|
||||
else
|
||||
return 5; // max z axis
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
if (middle_point[1] > middle_point[2])
|
||||
return 3; // max y axis
|
||||
@ -448,24 +448,24 @@ static char get_largest_axis(float *bv)
|
||||
static void node_join(BVHTree *tree, BVHNode *node)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
|
||||
for (i = tree->start_axis; i < tree->stop_axis; i++)
|
||||
{
|
||||
node->bv[2*i] = FLT_MAX;
|
||||
node->bv[2*i + 1] = -FLT_MAX;
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < tree->tree_type; i++)
|
||||
{
|
||||
if (node->children[i])
|
||||
if (node->children[i])
|
||||
{
|
||||
for (j = tree->start_axis; j < tree->stop_axis; j++)
|
||||
{
|
||||
// update minimum
|
||||
if (node->children[i]->bv[(2 * j)] < node->bv[(2 * j)])
|
||||
// update minimum
|
||||
if (node->children[i]->bv[(2 * j)] < node->bv[(2 * j)])
|
||||
node->bv[(2 * j)] = node->children[i]->bv[(2 * j)];
|
||||
|
||||
// update maximum
|
||||
|
||||
// update maximum
|
||||
if (node->children[i]->bv[(2 * j) + 1] > node->bv[(2 * j) + 1])
|
||||
node->bv[(2 * j) + 1] = node->children[i]->bv[(2 * j) + 1];
|
||||
}
|
||||
@ -518,7 +518,7 @@ static void bvhtree_info(BVHTree *tree)
|
||||
static void verify_tree(BVHTree *tree)
|
||||
{
|
||||
int i, j, check = 0;
|
||||
|
||||
|
||||
// check the pointer list
|
||||
for(i = 0; i < tree->totleaf; i++)
|
||||
{
|
||||
@ -538,7 +538,7 @@ static void verify_tree(BVHTree *tree)
|
||||
check = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// check the leaf list
|
||||
for(i = 0; i < tree->totleaf; i++)
|
||||
{
|
||||
@ -558,7 +558,7 @@ static void verify_tree(BVHTree *tree)
|
||||
check = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
printf("branches: %d, leafs: %d, total: %d\n", tree->totbranch, tree->totleaf, tree->totbranch + tree->totleaf);
|
||||
}
|
||||
#endif
|
||||
@ -703,7 +703,7 @@ static void non_recursive_bvh_div_nodes(BVHTree *tree, BVHNode *branches_array,
|
||||
|
||||
BVHBuildHelper data;
|
||||
int depth;
|
||||
|
||||
|
||||
// set parent from root node to NULL
|
||||
BVHNode *tmp = branches_array+0;
|
||||
tmp->parent = NULL;
|
||||
@ -722,7 +722,7 @@ static void non_recursive_bvh_div_nodes(BVHTree *tree, BVHNode *branches_array,
|
||||
}
|
||||
|
||||
branches_array--; //Implicit trees use 1-based indexs
|
||||
|
||||
|
||||
build_implicit_tree_helper(tree, &data);
|
||||
|
||||
//Loop tree levels (log N) loops
|
||||
@ -806,11 +806,11 @@ BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
|
||||
{
|
||||
BVHTree *tree;
|
||||
int numnodes, i;
|
||||
|
||||
|
||||
// theres not support for trees below binary-trees :P
|
||||
if(tree_type < 2)
|
||||
return NULL;
|
||||
|
||||
|
||||
if(tree_type > MAX_TREETYPE)
|
||||
return NULL;
|
||||
|
||||
@ -820,13 +820,13 @@ BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
|
||||
//so that tangent rays can still hit a bounding volume..
|
||||
//this bug would show up when casting a ray aligned with a kdop-axis and with an edge of 2 faces
|
||||
epsilon = MAX2(FLT_EPSILON, epsilon);
|
||||
|
||||
|
||||
if(tree)
|
||||
{
|
||||
tree->epsilon = epsilon;
|
||||
tree->tree_type = tree_type;
|
||||
tree->tree_type = tree_type;
|
||||
tree->axis = axis;
|
||||
|
||||
|
||||
if(axis == 26)
|
||||
{
|
||||
tree->start_axis = 0;
|
||||
@ -863,13 +863,13 @@ BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
|
||||
numnodes = maxsize + implicit_needed_branches(tree_type, maxsize) + tree_type;
|
||||
|
||||
tree->nodes = (BVHNode **)MEM_callocN(sizeof(BVHNode *)*numnodes, "BVHNodes");
|
||||
|
||||
|
||||
if(!tree->nodes)
|
||||
{
|
||||
MEM_freeN(tree);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
tree->nodebv = (float*)MEM_callocN(sizeof(float)* axis * numnodes, "BVHNodeBV");
|
||||
if(!tree->nodebv)
|
||||
{
|
||||
@ -886,7 +886,7 @@ BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
|
||||
}
|
||||
|
||||
tree->nodearray = (BVHNode *)MEM_callocN(sizeof(BVHNode)* numnodes, "BVHNodeArray");
|
||||
|
||||
|
||||
if(!tree->nodearray)
|
||||
{
|
||||
MEM_freeN(tree->nodechild);
|
||||
@ -902,14 +902,14 @@ BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
|
||||
tree->nodearray[i].bv = tree->nodebv + i * axis;
|
||||
tree->nodearray[i].children = tree->nodechild + i * tree_type;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
void BLI_bvhtree_free(BVHTree *tree)
|
||||
{
|
||||
{
|
||||
if(tree)
|
||||
{
|
||||
MEM_freeN(tree->nodes);
|
||||
@ -946,27 +946,27 @@ int BLI_bvhtree_insert(BVHTree *tree, int index, float *co, int numpoints)
|
||||
{
|
||||
int i;
|
||||
BVHNode *node = NULL;
|
||||
|
||||
|
||||
// insert should only possible as long as tree->totbranch is 0
|
||||
if(tree->totbranch > 0)
|
||||
return 0;
|
||||
|
||||
|
||||
if(tree->totleaf+1 >= MEM_allocN_len(tree->nodes)/sizeof(*(tree->nodes)))
|
||||
return 0;
|
||||
|
||||
|
||||
// TODO check if have enough nodes in array
|
||||
|
||||
|
||||
node = tree->nodes[tree->totleaf] = &(tree->nodearray[tree->totleaf]);
|
||||
tree->totleaf++;
|
||||
|
||||
|
||||
create_kdop_hull(tree, node, co, numpoints, 0);
|
||||
node->index= index;
|
||||
|
||||
|
||||
// inflate the bv with some epsilon
|
||||
for (i = tree->start_axis; i < tree->stop_axis; i++)
|
||||
{
|
||||
node->bv[(2 * i)] -= tree->epsilon; // minimum
|
||||
node->bv[(2 * i) + 1] += tree->epsilon; // maximum
|
||||
node->bv[(2 * i)] -= tree->epsilon; // minimum
|
||||
node->bv[(2 * i) + 1] += tree->epsilon; // maximum
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -978,23 +978,23 @@ int BLI_bvhtree_update_node(BVHTree *tree, int index, float *co, float *co_movin
|
||||
{
|
||||
int i;
|
||||
BVHNode *node= NULL;
|
||||
|
||||
|
||||
// check if index exists
|
||||
if(index > tree->totleaf)
|
||||
return 0;
|
||||
|
||||
|
||||
node = tree->nodearray + index;
|
||||
|
||||
|
||||
create_kdop_hull(tree, node, co, numpoints, 0);
|
||||
|
||||
|
||||
if(co_moving)
|
||||
create_kdop_hull(tree, node, co_moving, numpoints, 1);
|
||||
|
||||
|
||||
// inflate the bv with some epsilon
|
||||
for (i = tree->start_axis; i < tree->stop_axis; i++)
|
||||
{
|
||||
node->bv[(2 * i)] -= tree->epsilon; // minimum
|
||||
node->bv[(2 * i) + 1] += tree->epsilon; // maximum
|
||||
node->bv[(2 * i)] -= tree->epsilon; // minimum
|
||||
node->bv[(2 * i) + 1] += tree->epsilon; // maximum
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -1030,24 +1030,24 @@ static int tree_overlap(BVHNode *node1, BVHNode *node2, int start_axis, int stop
|
||||
float *bv2 = node2->bv;
|
||||
|
||||
float *bv1_end = bv1 + (stop_axis<<1);
|
||||
|
||||
|
||||
bv1 += start_axis<<1;
|
||||
bv2 += start_axis<<1;
|
||||
|
||||
|
||||
// test all axis if min + max overlap
|
||||
for (; bv1 != bv1_end; bv1+=2, bv2+=2)
|
||||
{
|
||||
if ((*(bv1) > *(bv2 + 1)) || (*(bv2) > *(bv1 + 1)))
|
||||
if ((*(bv1) > *(bv2 + 1)) || (*(bv2) > *(bv1 + 1)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void traverse(BVHOverlapData *data, BVHNode *node1, BVHNode *node2)
|
||||
{
|
||||
int j;
|
||||
|
||||
|
||||
if(tree_overlap(node1, node2, data->start_axis, data->stop_axis))
|
||||
{
|
||||
// check if node1 is a leaf
|
||||
@ -1056,17 +1056,17 @@ static void traverse(BVHOverlapData *data, BVHNode *node1, BVHNode *node2)
|
||||
// check if node2 is a leaf
|
||||
if(!node2->totnode)
|
||||
{
|
||||
|
||||
|
||||
if(node1 == node2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(data->i >= data->max_overlap)
|
||||
{
|
||||
{
|
||||
// try to make alloc'ed memory bigger
|
||||
data->overlap = realloc(data->overlap, sizeof(BVHTreeOverlap)*data->max_overlap*2);
|
||||
|
||||
|
||||
if(!data->overlap)
|
||||
{
|
||||
printf("Out of Memory in traverse\n");
|
||||
@ -1074,7 +1074,7 @@ static void traverse(BVHOverlapData *data, BVHNode *node1, BVHNode *node2)
|
||||
}
|
||||
data->max_overlap *= 2;
|
||||
}
|
||||
|
||||
|
||||
// both leafs, insert overlap!
|
||||
data->overlap[data->i].indexA = node1->index;
|
||||
data->overlap[data->i].indexB = node2->index;
|
||||
@ -1092,7 +1092,7 @@ static void traverse(BVHOverlapData *data, BVHNode *node1, BVHNode *node2)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
for(j = 0; j < data->tree2->tree_type; j++)
|
||||
{
|
||||
if(node1->children[j])
|
||||
@ -1108,21 +1108,21 @@ BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, int *result)
|
||||
int j, total = 0;
|
||||
BVHTreeOverlap *overlap = NULL, *to = NULL;
|
||||
BVHOverlapData **data;
|
||||
|
||||
|
||||
// check for compatibility of both trees (can't compare 14-DOP with 18-DOP)
|
||||
if((tree1->axis != tree2->axis) && (tree1->axis == 14 || tree2->axis == 14) && (tree1->axis == 18 || tree2->axis == 18))
|
||||
return 0;
|
||||
|
||||
|
||||
// fast check root nodes for collision before doing big splitting + traversal
|
||||
if(!tree_overlap(tree1->nodes[tree1->totleaf], tree2->nodes[tree2->totleaf], MIN2(tree1->start_axis, tree2->start_axis), MIN2(tree1->stop_axis, tree2->stop_axis)))
|
||||
return 0;
|
||||
|
||||
data = MEM_callocN(sizeof(BVHOverlapData *)* tree1->tree_type, "BVHOverlapData_star");
|
||||
|
||||
|
||||
for(j = 0; j < tree1->tree_type; j++)
|
||||
{
|
||||
data[j] = (BVHOverlapData *)MEM_callocN(sizeof(BVHOverlapData), "BVHOverlapData");
|
||||
|
||||
|
||||
// init BVHOverlapData
|
||||
data[j]->overlap = (BVHTreeOverlap *)malloc(sizeof(BVHTreeOverlap)*MAX2(tree1->totleaf, tree2->totleaf));
|
||||
data[j]->tree1 = tree1;
|
||||
@ -1138,25 +1138,25 @@ BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, int *result)
|
||||
{
|
||||
traverse(data[j], tree1->nodes[tree1->totleaf]->children[j], tree2->nodes[tree2->totleaf]);
|
||||
}
|
||||
|
||||
|
||||
for(j = 0; j < tree1->tree_type; j++)
|
||||
total += data[j]->i;
|
||||
|
||||
|
||||
to = overlap = (BVHTreeOverlap *)MEM_callocN(sizeof(BVHTreeOverlap)*total, "BVHTreeOverlap");
|
||||
|
||||
|
||||
for(j = 0; j < tree1->tree_type; j++)
|
||||
{
|
||||
memcpy(to, data[j]->overlap, data[j]->i*sizeof(BVHTreeOverlap));
|
||||
to+=data[j]->i;
|
||||
}
|
||||
|
||||
|
||||
for(j = 0; j < tree1->tree_type; j++)
|
||||
{
|
||||
free(data[j]->overlap);
|
||||
MEM_freeN(data[j]);
|
||||
}
|
||||
MEM_freeN(data);
|
||||
|
||||
|
||||
(*result) = total;
|
||||
return overlap;
|
||||
}
|
||||
@ -1173,7 +1173,7 @@ static float squared_dist(const float *a, const float *b)
|
||||
}
|
||||
|
||||
//Determines the nearest point of the given node BV. Returns the squared distance to that point.
|
||||
static float calc_nearest_point(BVHNearestData *data, BVHNode *node, float *nearest)
|
||||
static float calc_nearest_point(const float *proj, BVHNode *node, float *nearest)
|
||||
{
|
||||
int i;
|
||||
const float *bv = node->bv;
|
||||
@ -1181,12 +1181,12 @@ static float calc_nearest_point(BVHNearestData *data, BVHNode *node, float *near
|
||||
//nearest on AABB hull
|
||||
for(i=0; i != 3; i++, bv += 2)
|
||||
{
|
||||
if(bv[0] > data->proj[i])
|
||||
if(bv[0] > proj[i])
|
||||
nearest[i] = bv[0];
|
||||
else if(bv[1] < data->proj[i])
|
||||
else if(bv[1] < proj[i])
|
||||
nearest[i] = bv[1];
|
||||
else
|
||||
nearest[i] = data->proj[i];
|
||||
nearest[i] = proj[i];
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1208,7 +1208,7 @@ static float calc_nearest_point(BVHNearestData *data, BVHNode *node, float *near
|
||||
}
|
||||
}
|
||||
*/
|
||||
return squared_dist(data->co, nearest);
|
||||
return squared_dist(proj, nearest);
|
||||
}
|
||||
|
||||
|
||||
@ -1231,7 +1231,7 @@ static void dfs_find_nearest_dfs(BVHNearestData *data, BVHNode *node)
|
||||
else
|
||||
{
|
||||
data->nearest.index = node->index;
|
||||
data->nearest.dist = calc_nearest_point(data, node, data->nearest.co);
|
||||
data->nearest.dist = calc_nearest_point(data->proj, node, data->nearest.co);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1240,12 +1240,12 @@ static void dfs_find_nearest_dfs(BVHNearestData *data, BVHNode *node)
|
||||
int i;
|
||||
float nearest[3];
|
||||
|
||||
if(data->proj[ (int)node->main_axis ] <= node->children[0]->bv[(int)node->main_axis*2+1])
|
||||
if(data->proj[ node->main_axis ] <= node->children[0]->bv[node->main_axis*2+1])
|
||||
{
|
||||
|
||||
for(i=0; i != node->totnode; i++)
|
||||
{
|
||||
if( calc_nearest_point(data, node->children[i], nearest) >= data->nearest.dist) continue;
|
||||
if( calc_nearest_point(data->proj, node->children[i], nearest) >= data->nearest.dist) continue;
|
||||
dfs_find_nearest_dfs(data, node->children[i]);
|
||||
}
|
||||
}
|
||||
@ -1253,7 +1253,7 @@ static void dfs_find_nearest_dfs(BVHNearestData *data, BVHNode *node)
|
||||
{
|
||||
for(i=node->totnode-1; i >= 0 ; i--)
|
||||
{
|
||||
if( calc_nearest_point(data, node->children[i], nearest) >= data->nearest.dist) continue;
|
||||
if( calc_nearest_point(data->proj, node->children[i], nearest) >= data->nearest.dist) continue;
|
||||
dfs_find_nearest_dfs(data, node->children[i]);
|
||||
}
|
||||
}
|
||||
@ -1263,7 +1263,7 @@ static void dfs_find_nearest_dfs(BVHNearestData *data, BVHNode *node)
|
||||
static void dfs_find_nearest_begin(BVHNearestData *data, BVHNode *node)
|
||||
{
|
||||
float nearest[3], sdist;
|
||||
sdist = calc_nearest_point(data, node, nearest);
|
||||
sdist = calc_nearest_point(data->proj, node, nearest);
|
||||
if(sdist >= data->nearest.dist) return;
|
||||
dfs_find_nearest_dfs(data, node);
|
||||
}
|
||||
@ -1301,7 +1301,7 @@ static void bfs_find_nearest(BVHNearestData *data, BVHNode *node)
|
||||
}
|
||||
|
||||
current.node = node;
|
||||
current.dist = calc_nearest_point(data, node, nearest);
|
||||
current.dist = calc_nearest_point(data->proj, node, nearest);
|
||||
|
||||
while(current.dist < data->nearest.dist)
|
||||
{
|
||||
@ -1329,7 +1329,7 @@ static void bfs_find_nearest(BVHNearestData *data, BVHNode *node)
|
||||
}
|
||||
|
||||
heap[heap_size].node = current.node->children[i];
|
||||
heap[heap_size].dist = calc_nearest_point(data, current.node->children[i], nearest);
|
||||
heap[heap_size].dist = calc_nearest_point(data->proj, current.node->children[i], nearest);
|
||||
|
||||
if(heap[heap_size].dist >= data->nearest.dist) continue;
|
||||
heap_size++;
|
||||
@ -1339,7 +1339,7 @@ static void bfs_find_nearest(BVHNearestData *data, BVHNode *node)
|
||||
push_heaps++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(heap_size == 0) break;
|
||||
|
||||
current = heap[0];
|
||||
@ -1355,6 +1355,7 @@ static void bfs_find_nearest(BVHNearestData *data, BVHNode *node)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int BLI_bvhtree_find_nearest(BVHTree *tree, const float *co, BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata)
|
||||
{
|
||||
int i;
|
||||
@ -1435,7 +1436,7 @@ static float ray_nearest_hit(BVHRayCastData *data, float *bv)
|
||||
if(lu > low) low = lu;
|
||||
if(ll < upper) upper = ll;
|
||||
}
|
||||
|
||||
|
||||
if(low > upper) return FLT_MAX;
|
||||
}
|
||||
}
|
||||
@ -1532,28 +1533,115 @@ float BLI_bvhtree_bb_raycast(float *bv, float *light_start, float *light_end, fl
|
||||
float dist = 0.0;
|
||||
|
||||
data.hit.dist = FLT_MAX;
|
||||
|
||||
|
||||
// get light direction
|
||||
data.ray.direction[0] = light_end[0] - light_start[0];
|
||||
data.ray.direction[1] = light_end[1] - light_start[1];
|
||||
data.ray.direction[2] = light_end[2] - light_start[2];
|
||||
|
||||
|
||||
data.ray.radius = 0.0;
|
||||
|
||||
|
||||
data.ray.origin[0] = light_start[0];
|
||||
data.ray.origin[1] = light_start[1];
|
||||
data.ray.origin[2] = light_start[2];
|
||||
|
||||
|
||||
Normalize(data.ray.direction);
|
||||
VECCOPY(data.ray_dot_axis, data.ray.direction);
|
||||
|
||||
|
||||
dist = ray_nearest_hit(&data, bv);
|
||||
|
||||
|
||||
if(dist > 0.0)
|
||||
{
|
||||
VECADDFAC(pos, light_start, data.ray.direction, dist);
|
||||
}
|
||||
return dist;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Range Query - as request by broken :P
|
||||
*
|
||||
* Allocs and fills an array with the indexs of node that are on the given spherical range (center, radius)
|
||||
* Returns the size of the array.
|
||||
*/
|
||||
typedef struct RangeQueryData
|
||||
{
|
||||
BVHTree *tree;
|
||||
const float *center;
|
||||
float radius; //squared radius
|
||||
|
||||
int hits;
|
||||
|
||||
BVHTree_RangeQuery callback;
|
||||
void *userdata;
|
||||
|
||||
|
||||
} RangeQueryData;
|
||||
|
||||
|
||||
static void dfs_range_query(RangeQueryData *data, BVHNode *node)
|
||||
{
|
||||
if(node->totnode == 0)
|
||||
{
|
||||
|
||||
//Calculate the node min-coords (if the node was a point then this is the point coordinates)
|
||||
float co[3];
|
||||
co[0] = node->bv[0];
|
||||
co[1] = node->bv[2];
|
||||
co[2] = node->bv[4];
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
for(i=0; i != node->totnode; i++)
|
||||
{
|
||||
float nearest[3];
|
||||
float dist = calc_nearest_point(data->center, node->children[i], nearest);
|
||||
if(dist < data->radius)
|
||||
{
|
||||
//Its a leaf.. call the callback
|
||||
if(node->children[i]->totnode == 0)
|
||||
{
|
||||
data->hits++;
|
||||
data->callback( data->userdata, node->children[i]->index, dist );
|
||||
}
|
||||
else
|
||||
dfs_range_query( data, node->children[i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int BLI_bvhtree_range_query(BVHTree *tree, const float *co, float radius, BVHTree_RangeQuery callback, void *userdata)
|
||||
{
|
||||
BVHNode * root = tree->nodes[tree->totleaf];
|
||||
|
||||
RangeQueryData data;
|
||||
data.tree = tree;
|
||||
data.center = co;
|
||||
data.radius = radius*radius;
|
||||
data.hits = 0;
|
||||
|
||||
data.callback = callback;
|
||||
data.userdata = userdata;
|
||||
|
||||
if(root != NULL)
|
||||
{
|
||||
float nearest[3];
|
||||
float dist = calc_nearest_point(data.center, root, nearest);
|
||||
if(dist < data.radius)
|
||||
{
|
||||
//Its a leaf.. call the callback
|
||||
if(root->totnode == 0)
|
||||
{
|
||||
data.hits++;
|
||||
data.callback( data.userdata, root->index, dist );
|
||||
}
|
||||
else
|
||||
dfs_range_query( &data, root );
|
||||
}
|
||||
}
|
||||
|
||||
return data.hits;
|
||||
}
|
||||
|
@ -2176,6 +2176,13 @@ void VecSubf(float *v, float *v1, float *v2)
|
||||
v[2]= v1[2]- v2[2];
|
||||
}
|
||||
|
||||
void VecMulVecf(float *v, float *v1, float *v2)
|
||||
{
|
||||
v[0] = v1[0] * v2[0];
|
||||
v[1] = v1[1] * v2[1];
|
||||
v[2] = v1[2] * v2[2];
|
||||
}
|
||||
|
||||
void VecLerpf(float *target, float *a, float *b, float t)
|
||||
{
|
||||
float s = 1.0f-t;
|
||||
|
299
source/blender/blenlib/intern/voxel.c
Normal file
299
source/blender/blenlib/intern/voxel.c
Normal file
@ -0,0 +1,299 @@
|
||||
/**
|
||||
*
|
||||
* ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Matt Ebb, Raul Fernandez Hernandez (Farsthary).
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
#include <math.h>
|
||||
|
||||
#include "BLI_voxel.h"
|
||||
|
||||
#include "BKE_utildefines.h"
|
||||
|
||||
|
||||
#if defined( _MSC_VER ) && !defined( __cplusplus )
|
||||
# define inline __inline
|
||||
#endif // defined( _MSC_VER ) && !defined( __cplusplus )
|
||||
|
||||
static inline float D(float *data, int *res, int x, int y, int z)
|
||||
{
|
||||
CLAMP(x, 0, res[0]-1);
|
||||
CLAMP(y, 0, res[1]-1);
|
||||
CLAMP(z, 0, res[2]-1);
|
||||
return data[ V_I(x, y, z, res) ];
|
||||
}
|
||||
|
||||
/* *** nearest neighbour *** */
|
||||
/* input coordinates must be in bounding box 0.0 - 1.0 */
|
||||
float voxel_sample_nearest(float *data, int *res, float *co)
|
||||
{
|
||||
int xi, yi, zi;
|
||||
|
||||
xi = co[0] * res[0];
|
||||
yi = co[1] * res[1];
|
||||
zi = co[2] * res[2];
|
||||
|
||||
return D(data, res, xi, yi, zi);
|
||||
}
|
||||
|
||||
|
||||
/* *** trilinear *** */
|
||||
/* input coordinates must be in bounding box 0.0 - 1.0 */
|
||||
|
||||
static inline float lerp(float t, float v1, float v2) {
|
||||
return (1.f - t) * v1 + t * v2;
|
||||
}
|
||||
|
||||
/* trilinear interpolation - taken partly from pbrt's implementation: http://www.pbrt.org */
|
||||
float voxel_sample_trilinear(float *data, int *res, float *co)
|
||||
{
|
||||
float voxx, voxy, voxz;
|
||||
int vx, vy, vz;
|
||||
float dx, dy, dz;
|
||||
float d00, d10, d01, d11, d0, d1, d_final;
|
||||
|
||||
if (!data) return 0.f;
|
||||
|
||||
voxx = co[0] * res[0] - 0.5f;
|
||||
voxy = co[1] * res[1] - 0.5f;
|
||||
voxz = co[2] * res[2] - 0.5f;
|
||||
|
||||
vx = (int)voxx; vy = (int)voxy; vz = (int)voxz;
|
||||
|
||||
dx = voxx - vx; dy = voxy - vy; dz = voxz - vz;
|
||||
|
||||
d00 = lerp(dx, D(data, res, vx, vy, vz), D(data, res, vx+1, vy, vz));
|
||||
d10 = lerp(dx, D(data, res, vx, vy+1, vz), D(data, res, vx+1, vy+1, vz));
|
||||
d01 = lerp(dx, D(data, res, vx, vy, vz+1), D(data, res, vx+1, vy, vz+1));
|
||||
d11 = lerp(dx, D(data, res, vx, vy+1, vz+1), D(data, res, vx+1, vy+1, vz+1));
|
||||
d0 = lerp(dy, d00, d10);
|
||||
d1 = lerp(dy, d01, d11);
|
||||
d_final = lerp(dz, d0, d1);
|
||||
|
||||
return d_final;
|
||||
}
|
||||
|
||||
/* *** tricubic *** */
|
||||
|
||||
int C[64][64] = {
|
||||
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{-3, 3, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 2,-2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 9,-9,-9, 9, 0, 0, 0, 0, 6, 3,-6,-3, 0, 0, 0, 0, 6,-6, 3,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{-6, 6, 6,-6, 0, 0, 0, 0,-3,-3, 3, 3, 0, 0, 0, 0,-4, 4,-2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-2,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{-6, 6, 6,-6, 0, 0, 0, 0,-4,-2, 4, 2, 0, 0, 0, 0,-3, 3,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 4,-4,-4, 4, 0, 0, 0, 0, 2, 2,-2,-2, 0, 0, 0, 0, 2,-2, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,-9,-9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3,-6,-3, 0, 0, 0, 0, 6,-6, 3,-3, 0, 0, 0, 0, 4, 2, 2, 1, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3,-3, 3, 3, 0, 0, 0, 0,-4, 4,-2, 2, 0, 0, 0, 0,-2,-2,-1,-1, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4,-2, 4, 2, 0, 0, 0, 0,-3, 3,-3, 3, 0, 0, 0, 0,-2,-1,-2,-1, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,-4,-4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2,-2,-2, 0, 0, 0, 0, 2,-2, 2,-2, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0},
|
||||
{-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 9,-9, 0, 0,-9, 9, 0, 0, 6, 3, 0, 0,-6,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,-6, 0, 0, 3,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{-6, 6, 0, 0, 6,-6, 0, 0,-3,-3, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 4, 0, 0,-2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-2, 0, 0,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,-9, 0, 0,-9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3, 0, 0,-6,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,-6, 0, 0, 3,-3, 0, 0, 4, 2, 0, 0, 2, 1, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 0, 0, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3,-3, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 4, 0, 0,-2, 2, 0, 0,-2,-2, 0, 0,-1,-1, 0, 0},
|
||||
{ 9, 0,-9, 0,-9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, 0,-6, 0,-3, 0, 6, 0,-6, 0, 3, 0,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 9, 0,-9, 0,-9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, 0,-6, 0,-3, 0, 6, 0,-6, 0, 3, 0,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 0, 2, 0, 1, 0},
|
||||
{-27,27,27,-27,27,-27,-27,27,-18,-9,18, 9,18, 9,-18,-9,-18,18,-9, 9,18,-18, 9,-9,-18,18,18,-18,-9, 9, 9,-9,-12,-6,-6,-3,12, 6, 6, 3,-12,-6,12, 6,-6,-3, 6, 3,-12,12,-6, 6,-6, 6,-3, 3,-8,-4,-4,-2,-4,-2,-2,-1},
|
||||
{18,-18,-18,18,-18,18,18,-18, 9, 9,-9,-9,-9,-9, 9, 9,12,-12, 6,-6,-12,12,-6, 6,12,-12,-12,12, 6,-6,-6, 6, 6, 6, 3, 3,-6,-6,-3,-3, 6, 6,-6,-6, 3, 3,-3,-3, 8,-8, 4,-4, 4,-4, 2,-2, 4, 4, 2, 2, 2, 2, 1, 1},
|
||||
{-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0,-3, 0, 3, 0, 3, 0,-4, 0, 4, 0,-2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-2, 0,-1, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0,-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0,-3, 0, 3, 0, 3, 0,-4, 0, 4, 0,-2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-2, 0,-1, 0,-1, 0},
|
||||
{18,-18,-18,18,-18,18,18,-18,12, 6,-12,-6,-12,-6,12, 6, 9,-9, 9,-9,-9, 9,-9, 9,12,-12,-12,12, 6,-6,-6, 6, 6, 3, 6, 3,-6,-3,-6,-3, 8, 4,-8,-4, 4, 2,-4,-2, 6,-6, 6,-6, 3,-3, 3,-3, 4, 2, 4, 2, 2, 1, 2, 1},
|
||||
{-12,12,12,-12,12,-12,-12,12,-6,-6, 6, 6, 6, 6,-6,-6,-6, 6,-6, 6, 6,-6, 6,-6,-8, 8, 8,-8,-4, 4, 4,-4,-3,-3,-3,-3, 3, 3, 3, 3,-4,-4, 4, 4,-2,-2, 2, 2,-4, 4,-4, 4,-2, 2,-2, 2,-2,-2,-2,-2,-1,-1,-1,-1},
|
||||
{ 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{-6, 6, 0, 0, 6,-6, 0, 0,-4,-2, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 4,-4, 0, 0,-4, 4, 0, 0, 2, 2, 0, 0,-2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 0, 0, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4,-2, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0,-3, 3, 0, 0,-2,-1, 0, 0,-2,-1, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,-4, 0, 0,-4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0,-2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 2,-2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0},
|
||||
{-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0,-2, 0, 4, 0, 2, 0,-3, 0, 3, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0,-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0,-2, 0, 4, 0, 2, 0,-3, 0, 3, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0,-2, 0,-1, 0},
|
||||
{18,-18,-18,18,-18,18,18,-18,12, 6,-12,-6,-12,-6,12, 6,12,-12, 6,-6,-12,12,-6, 6, 9,-9,-9, 9, 9,-9,-9, 9, 8, 4, 4, 2,-8,-4,-4,-2, 6, 3,-6,-3, 6, 3,-6,-3, 6,-6, 3,-3, 6,-6, 3,-3, 4, 2, 2, 1, 4, 2, 2, 1},
|
||||
{-12,12,12,-12,12,-12,-12,12,-6,-6, 6, 6, 6, 6,-6,-6,-8, 8,-4, 4, 8,-8, 4,-4,-6, 6, 6,-6,-6, 6, 6,-6,-4,-4,-2,-2, 4, 4, 2, 2,-3,-3, 3, 3,-3,-3, 3, 3,-4, 4,-2, 2,-4, 4,-2, 2,-2,-2,-1,-1,-2,-2,-1,-1},
|
||||
{ 4, 0,-4, 0,-4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0,-2, 0,-2, 0, 2, 0,-2, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 4, 0,-4, 0,-4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0,-2, 0,-2, 0, 2, 0,-2, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0},
|
||||
{-12,12,12,-12,12,-12,-12,12,-8,-4, 8, 4, 8, 4,-8,-4,-6, 6,-6, 6, 6,-6, 6,-6,-6, 6, 6,-6,-6, 6, 6,-6,-4,-2,-4,-2, 4, 2, 4, 2,-4,-2, 4, 2,-4,-2, 4, 2,-3, 3,-3, 3,-3, 3,-3, 3,-2,-1,-2,-1,-2,-1,-2,-1},
|
||||
{ 8,-8,-8, 8,-8, 8, 8,-8, 4, 4,-4,-4,-4,-4, 4, 4, 4,-4, 4,-4,-4, 4,-4, 4, 4,-4,-4, 4, 4,-4,-4, 4, 2, 2, 2, 2,-2,-2,-2,-2, 2, 2,-2,-2, 2, 2,-2,-2, 2,-2, 2,-2, 2,-2, 2,-2, 1, 1, 1, 1, 1, 1, 1, 1}};
|
||||
|
||||
static int ijk2n(int i, int j, int k) {
|
||||
return(i+4*j+16*k);
|
||||
}
|
||||
|
||||
static void tricubic_get_coeff_stacked(float a[64], float x[64]) {
|
||||
int i,j;
|
||||
for (i=0;i<64;i++) {
|
||||
a[i]=(float)(0.0);
|
||||
for (j=0;j<64;j++) {
|
||||
a[i]+=C[i][j]*x[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static void tricubic_get_coeff(float a[64], float f[8], float dfdx[8], float dfdy[8], float dfdz[8], float d2fdxdy[8], float d2fdxdz[8], float d2fdydz[8], float d3fdxdydz[8]) {
|
||||
int i;
|
||||
float x[64];
|
||||
for (i=0;i<8;i++) {
|
||||
x[0+i]=f[i];
|
||||
x[8+i]=dfdx[i];
|
||||
x[16+i]=dfdy[i];
|
||||
x[24+i]=dfdz[i];
|
||||
x[32+i]=d2fdxdy[i];
|
||||
x[40+i]=d2fdxdz[i];
|
||||
x[48+i]=d2fdydz[i];
|
||||
x[56+i]=d3fdxdydz[i];
|
||||
}
|
||||
tricubic_get_coeff_stacked(a,x);
|
||||
}
|
||||
|
||||
static float tricubic_eval(float a[64], float x, float y, float z) {
|
||||
int i,j,k;
|
||||
float ret=(float)(0.0);
|
||||
|
||||
for (i=0;i<4;i++) {
|
||||
for (j=0;j<4;j++) {
|
||||
for (k=0;k<4;k++) {
|
||||
ret+=a[ijk2n(i,j,k)]*pow(x,i)*pow(y,j)*pow(z,k);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/* tricubic interpolation
|
||||
* from 'libtricubic': http://www.lekien.com/~francois/software/tricubic/
|
||||
* input coordinates must be in bounding box 0.0 - 1.0 */
|
||||
float voxel_sample_tricubic(float *data, int *res, float *co)
|
||||
{
|
||||
float xx, yy, zz;
|
||||
int xi,yi,zi;
|
||||
int *n = res;
|
||||
float dx,dy,dz;
|
||||
float a[64];
|
||||
|
||||
xx = co[0] * res[0] - 0.5f;
|
||||
yy = co[1] * res[1] - 0.5f;
|
||||
zz = co[2] * res[2] - 0.5f;
|
||||
|
||||
xi = (int)xx; yi = (int)yy; zi = (int)zz;
|
||||
|
||||
{
|
||||
float fval[8]={data[V_I(xi,yi,zi,n)],data[V_I(xi+1,yi,zi,n)],data[V_I(xi,yi+1,zi,n)],data[V_I(xi+1,yi+1,zi,n)],data[V_I(xi,yi,zi+1,n)],data[V_I(xi+1,yi,zi+1,n)],data[V_I(xi,yi+1,zi+1,n)],data[V_I(xi+1,yi+1,zi+1,n)]};
|
||||
|
||||
float dfdxval[8]={0.5f*(data[V_I(xi+1,yi,zi,n)]-data[V_I(xi-1,yi,zi,n)]),0.5f*(data[V_I(xi+2,yi,zi,n)]-data[V_I(xi,yi,zi,n)]),
|
||||
0.5f*(data[V_I(xi+1,yi+1,zi,n)]-data[V_I(xi-1,yi+1,zi,n)]),0.5f*(data[V_I(xi+2,yi+1,zi,n)]-data[V_I(xi,yi+1,zi,n)]),
|
||||
0.5f*(data[V_I(xi+1,yi,zi+1,n)]-data[V_I(xi-1,yi,zi+1,n)]),0.5f*(data[V_I(xi+2,yi,zi+1,n)]-data[V_I(xi,yi,zi+1,n)]),
|
||||
0.5f*(data[V_I(xi+1,yi+1,zi+1,n)]-data[V_I(xi-1,yi+1,zi+1,n)]),
|
||||
0.5f*(data[V_I(xi+2,yi+1,zi+1,n)]-data[V_I(xi,yi+1,zi+1,n)])};
|
||||
|
||||
float dfdyval[8]={0.5f*(data[V_I(xi,yi+1,zi,n)]-data[V_I(xi,yi-1,zi,n)]),0.5f*(data[V_I(xi+1,yi+1,zi,n)]-data[V_I(xi+1,yi-1,zi,n)]),
|
||||
0.5f*(data[V_I(xi,yi+2,zi,n)]-data[V_I(xi,yi,zi,n)]),0.5f*(data[V_I(xi+1,yi+2,zi,n)]-data[V_I(xi+1,yi,zi,n)]),
|
||||
0.5f*(data[V_I(xi,yi+1,zi+1,n)]-data[V_I(xi,yi-1,zi+1,n)]),0.5f*(data[V_I(xi+1,yi+1,zi+1,n)]-data[V_I(xi+1,yi-1,zi+1,n)]),
|
||||
0.5f*(data[V_I(xi,yi+2,zi+1,n)]-data[V_I(xi,yi,zi+1,n)]),
|
||||
0.5f*(data[V_I(xi+1,yi+2,zi+1,n)]-data[V_I(xi+1,yi,zi+1,n)])};
|
||||
|
||||
float dfdzval[8]={0.5f*(data[V_I(xi,yi,zi+1,n)]-data[V_I(xi,yi,zi-1,n)]),0.5f*(data[V_I(xi+1,yi,zi+1,n)]-data[V_I(xi+1,yi,zi-1,n)]),
|
||||
0.5f*(data[V_I(xi,yi+1,zi+1,n)]-data[V_I(xi,yi+1,zi-1,n)]),0.5f*(data[V_I(xi+1,yi+1,zi+1,n)]-data[V_I(xi+1,yi+1,zi-1,n)]),
|
||||
0.5f*(data[V_I(xi,yi,zi+2,n)]-data[V_I(xi,yi,zi,n)]),0.5f*(data[V_I(xi+1,yi,zi+2,n)]-data[V_I(xi+1,yi,zi,n)]),
|
||||
0.5f*(data[V_I(xi,yi+1,zi+2,n)]-data[V_I(xi,yi+1,zi,n)]),
|
||||
0.5f*(data[V_I(xi+1,yi+1,zi+2,n)]-data[V_I(xi+1,yi+1,zi,n)])};
|
||||
|
||||
float d2fdxdyval[8]={0.25*(data[V_I(xi+1,yi+1,zi,n)]-data[V_I(xi-1,yi+1,zi,n)]-data[V_I(xi+1,yi-1,zi,n)]+data[V_I(xi-1,yi-1,zi,n)]),
|
||||
0.25*(data[V_I(xi+2,yi+1,zi,n)]-data[V_I(xi,yi+1,zi,n)]-data[V_I(xi+2,yi-1,zi,n)]+data[V_I(xi,yi-1,zi,n)]),
|
||||
0.25*(data[V_I(xi+1,yi+2,zi,n)]-data[V_I(xi-1,yi+2,zi,n)]-data[V_I(xi+1,yi,zi,n)]+data[V_I(xi-1,yi,zi,n)]),
|
||||
0.25*(data[V_I(xi+2,yi+2,zi,n)]-data[V_I(xi,yi+2,zi,n)]-data[V_I(xi+2,yi,zi,n)]+data[V_I(xi,yi,zi,n)]),
|
||||
0.25*(data[V_I(xi+1,yi+1,zi+1,n)]-data[V_I(xi-1,yi+1,zi+1,n)]-data[V_I(xi+1,yi-1,zi+1,n)]+data[V_I(xi-1,yi-1,zi+1,n)]),
|
||||
0.25*(data[V_I(xi+2,yi+1,zi+1,n)]-data[V_I(xi,yi+1,zi+1,n)]-data[V_I(xi+2,yi-1,zi+1,n)]+data[V_I(xi,yi-1,zi+1,n)]),
|
||||
0.25*(data[V_I(xi+1,yi+2,zi+1,n)]-data[V_I(xi-1,yi+2,zi+1,n)]-data[V_I(xi+1,yi,zi+1,n)]+data[V_I(xi-1,yi,zi+1,n)]),
|
||||
0.25*(data[V_I(xi+2,yi+2,zi+1,n)]-data[V_I(xi,yi+2,zi+1,n)]-data[V_I(xi+2,yi,zi+1,n)]+data[V_I(xi,yi,zi+1,n)])};
|
||||
|
||||
float d2fdxdzval[8]={0.25f*(data[V_I(xi+1,yi,zi+1,n)]-data[V_I(xi-1,yi,zi+1,n)]-data[V_I(xi+1,yi,zi-1,n)]+data[V_I(xi-1,yi,zi-1,n)]),
|
||||
0.25f*(data[V_I(xi+2,yi,zi+1,n)]-data[V_I(xi,yi,zi+1,n)]-data[V_I(xi+2,yi,zi-1,n)]+data[V_I(xi,yi,zi-1,n)]),
|
||||
0.25f*(data[V_I(xi+1,yi+1,zi+1,n)]-data[V_I(xi-1,yi+1,zi+1,n)]-data[V_I(xi+1,yi+1,zi-1,n)]+data[V_I(xi-1,yi+1,zi-1,n)]),
|
||||
0.25f*(data[V_I(xi+2,yi+1,zi+1,n)]-data[V_I(xi,yi+1,zi+1,n)]-data[V_I(xi+2,yi+1,zi-1,n)]+data[V_I(xi,yi+1,zi-1,n)]),
|
||||
0.25f*(data[V_I(xi+1,yi,zi+2,n)]-data[V_I(xi-1,yi,zi+2,n)]-data[V_I(xi+1,yi,zi,n)]+data[V_I(xi-1,yi,zi,n)]),
|
||||
0.25f*(data[V_I(xi+2,yi,zi+2,n)]-data[V_I(xi,yi,zi+2,n)]-data[V_I(xi+2,yi,zi,n)]+data[V_I(xi,yi,zi,n)]),
|
||||
0.25f*(data[V_I(xi+1,yi+1,zi+2,n)]-data[V_I(xi-1,yi+1,zi+2,n)]-data[V_I(xi+1,yi+1,zi,n)]+data[V_I(xi-1,yi+1,zi,n)]),
|
||||
0.25f*(data[V_I(xi+2,yi+1,zi+2,n)]-data[V_I(xi,yi+1,zi+2,n)]-data[V_I(xi+2,yi+1,zi,n)]+data[V_I(xi,yi+1,zi,n)])};
|
||||
|
||||
|
||||
float d2fdydzval[8]={0.25f*(data[V_I(xi,yi+1,zi+1,n)]-data[V_I(xi,yi-1,zi+1,n)]-data[V_I(xi,yi+1,zi-1,n)]+data[V_I(xi,yi-1,zi-1,n)]),
|
||||
0.25f*(data[V_I(xi+1,yi+1,zi+1,n)]-data[V_I(xi+1,yi-1,zi+1,n)]-data[V_I(xi+1,yi+1,zi-1,n)]+data[V_I(xi+1,yi-1,zi-1,n)]),
|
||||
0.25f*(data[V_I(xi,yi+2,zi+1,n)]-data[V_I(xi,yi,zi+1,n)]-data[V_I(xi,yi+2,zi-1,n)]+data[V_I(xi,yi,zi-1,n)]),
|
||||
0.25f*(data[V_I(xi+1,yi+2,zi+1,n)]-data[V_I(xi+1,yi,zi+1,n)]-data[V_I(xi+1,yi+2,zi-1,n)]+data[V_I(xi+1,yi,zi-1,n)]),
|
||||
0.25f*(data[V_I(xi,yi+1,zi+2,n)]-data[V_I(xi,yi-1,zi+2,n)]-data[V_I(xi,yi+1,zi,n)]+data[V_I(xi,yi-1,zi,n)]),
|
||||
0.25f*(data[V_I(xi+1,yi+1,zi+2,n)]-data[V_I(xi+1,yi-1,zi+2,n)]-data[V_I(xi+1,yi+1,zi,n)]+data[V_I(xi+1,yi-1,zi,n)]),
|
||||
0.25f*(data[V_I(xi,yi+2,zi+2,n)]-data[V_I(xi,yi,zi+2,n)]-data[V_I(xi,yi+2,zi,n)]+data[V_I(xi,yi,zi,n)]),
|
||||
0.25f*(data[V_I(xi+1,yi+2,zi+2,n)]-data[V_I(xi+1,yi,zi+2,n)]-data[V_I(xi+1,yi+2,zi,n)]+data[V_I(xi+1,yi,zi,n)])};
|
||||
|
||||
|
||||
float d3fdxdydzval[8]={0.125f*(data[V_I(xi+1,yi+1,zi+1,n)]-data[V_I(xi-1,yi+1,zi+1,n)]-data[V_I(xi+1,yi-1,zi+1,n)]+data[V_I(xi-1,yi-1,zi+1,n)]-data[V_I(xi+1,yi+1,zi-1,n)]+data[V_I(xi-1,yi+1,zi-1,n)]+data[V_I(xi+1,yi-1,zi-1,n)]-data[V_I(xi-1,yi-1,zi-1,n)]),
|
||||
0.125f*(data[V_I(xi+2,yi+1,zi+1,n)]-data[V_I(xi,yi+1,zi+1,n)]-data[V_I(xi+2,yi-1,zi+1,n)]+data[V_I(xi,yi-1,zi+1,n)]-data[V_I(xi+2,yi+1,zi-1,n)]+data[V_I(xi,yi+1,zi-1,n)]+data[V_I(xi+2,yi-1,zi-1,n)]-data[V_I(xi,yi-1,zi-1,n)]),
|
||||
0.125f*(data[V_I(xi+1,yi+2,zi+1,n)]-data[V_I(xi-1,yi+2,zi+1,n)]-data[V_I(xi+1,yi,zi+1,n)]+data[V_I(xi-1,yi,zi+1,n)]-data[V_I(xi+1,yi+2,zi-1,n)]+data[V_I(xi-1,yi+2,zi-1,n)]+data[V_I(xi+1,yi,zi-1,n)]-data[V_I(xi-1,yi,zi-1,n)]),
|
||||
0.125f*(data[V_I(xi+2,yi+2,zi+1,n)]-data[V_I(xi,yi+2,zi+1,n)]-data[V_I(xi+2,yi,zi+1,n)]+data[V_I(xi,yi,zi+1,n)]-data[V_I(xi+2,yi+2,zi-1,n)]+data[V_I(xi,yi+2,zi-1,n)]+data[V_I(xi+2,yi,zi-1,n)]-data[V_I(xi,yi,zi-1,n)]),
|
||||
0.125f*(data[V_I(xi+1,yi+1,zi+2,n)]-data[V_I(xi-1,yi+1,zi+2,n)]-data[V_I(xi+1,yi-1,zi+2,n)]+data[V_I(xi-1,yi-1,zi+2,n)]-data[V_I(xi+1,yi+1,zi,n)]+data[V_I(xi-1,yi+1,zi,n)]+data[V_I(xi+1,yi-1,zi,n)]-data[V_I(xi-1,yi-1,zi,n)]),
|
||||
0.125f*(data[V_I(xi+2,yi+1,zi+2,n)]-data[V_I(xi,yi+1,zi+2,n)]-data[V_I(xi+2,yi-1,zi+2,n)]+data[V_I(xi,yi-1,zi+2,n)]-data[V_I(xi+2,yi+1,zi,n)]+data[V_I(xi,yi+1,zi,n)]+data[V_I(xi+2,yi-1,zi,n)]-data[V_I(xi,yi-1,zi,n)]),
|
||||
0.125f*(data[V_I(xi+1,yi+2,zi+2,n)]-data[V_I(xi-1,yi+2,zi+2,n)]-data[V_I(xi+1,yi,zi+2,n)]+data[V_I(xi-1,yi,zi+2,n)]-data[V_I(xi+1,yi+2,zi,n)]+data[V_I(xi-1,yi+2,zi,n)]+data[V_I(xi+1,yi,zi,n)]-data[V_I(xi-1,yi,zi,n)]),
|
||||
0.125f*(data[V_I(xi+2,yi+2,zi+2,n)]-data[V_I(xi,yi+2,zi+2,n)]-data[V_I(xi+2,yi,zi+2,n)]+data[V_I(xi,yi,zi+2,n)]-data[V_I(xi+2,yi+2,zi,n)]+data[V_I(xi,yi+2,zi,n)]+data[V_I(xi+2,yi,zi,n)]-data[V_I(xi,yi,zi,n)])};
|
||||
|
||||
|
||||
tricubic_get_coeff(a,fval,dfdxval,dfdyval,dfdzval,d2fdxdyval,d2fdxdzval,d2fdydzval,d3fdxdydzval);
|
||||
}
|
||||
|
||||
dx = xx-xi;
|
||||
dy = yy-yi;
|
||||
dz = zz-zi;
|
||||
|
||||
return tricubic_eval(a,dx,dy,dz);
|
||||
|
||||
}
|
||||
|
@ -2819,6 +2819,11 @@ static void lib_link_texture(FileData *fd, Main *main)
|
||||
tex->ima= newlibadr_us(fd, tex->id.lib, tex->ima);
|
||||
tex->ipo= newlibadr_us(fd, tex->id.lib, tex->ipo);
|
||||
if(tex->env) tex->env->object= newlibadr(fd, tex->id.lib, tex->env->object);
|
||||
if(tex->pd) {
|
||||
tex->pd->object= newlibadr(fd, tex->id.lib, tex->pd->object);
|
||||
tex->pd->psys= newlibadr(fd, tex->id.lib, tex->pd->psys);
|
||||
}
|
||||
if(tex->vd) tex->vd->object= newlibadr(fd, tex->id.lib, tex->vd->object);
|
||||
|
||||
if(tex->nodetree)
|
||||
lib_link_ntree(fd, &tex->id, tex->nodetree);
|
||||
@ -2851,6 +2856,16 @@ static void direct_link_texture(FileData *fd, Tex *tex)
|
||||
memset(tex->env->cube, 0, 6*sizeof(void *));
|
||||
tex->env->ok= 0;
|
||||
}
|
||||
tex->pd= newdataadr(fd, tex->pd);
|
||||
if(tex->pd) {
|
||||
tex->pd->point_tree = NULL;
|
||||
tex->pd->coba= newdataadr(fd, tex->pd->coba);
|
||||
}
|
||||
|
||||
tex->vd= newdataadr(fd, tex->vd);
|
||||
if(tex->vd) {
|
||||
tex->vd->dataset = NULL;
|
||||
}
|
||||
|
||||
tex->nodetree= newdataadr(fd, tex->nodetree);
|
||||
if(tex->nodetree)
|
||||
@ -9478,6 +9493,24 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* volume rendering settings */
|
||||
if (ma->vol.stepsize < 0.0001f) {
|
||||
ma->vol.density = 1.0f;
|
||||
ma->vol.emission = 0.0f;
|
||||
ma->vol.absorption = 1.0f;
|
||||
ma->vol.scattering = 1.0f;
|
||||
ma->vol.emission_col[0] = ma->vol.emission_col[1] = ma->vol.emission_col[2] = 1.0f;
|
||||
ma->vol.absorption_col[0] = ma->vol.absorption_col[1] = ma->vol.absorption_col[2] = 0.0f;
|
||||
ma->vol.density_scale = 1.0f;
|
||||
ma->vol.depth_cutoff = 0.01f;
|
||||
ma->vol.stepsize_type = MA_VOL_STEP_RANDOMIZED;
|
||||
ma->vol.stepsize = 0.2f;
|
||||
ma->vol.shade_stepsize = 0.2f;
|
||||
ma->vol.shade_type = MA_VOL_SHADE_SINGLE;
|
||||
ma->vol.shadeflag |= MA_VOL_PRECACHESHADING;
|
||||
ma->vol.precache_resolution = 50;
|
||||
}
|
||||
}
|
||||
|
||||
for(sce = main->scene.first; sce; sce = sce->id.next) {
|
||||
|
@ -1572,6 +1572,11 @@ static void write_textures(WriteData *wd, ListBase *idbase)
|
||||
if(tex->type == TEX_PLUGIN && tex->plugin) writestruct(wd, DATA, "PluginTex", 1, tex->plugin);
|
||||
if(tex->coba) writestruct(wd, DATA, "ColorBand", 1, tex->coba);
|
||||
if(tex->type == TEX_ENVMAP && tex->env) writestruct(wd, DATA, "EnvMap", 1, tex->env);
|
||||
if(tex->type == TEX_POINTDENSITY && tex->pd) {
|
||||
writestruct(wd, DATA, "PointDensity", 1, tex->pd);
|
||||
if(tex->pd->coba) writestruct(wd, DATA, "ColorBand", 1, tex->pd->coba);
|
||||
}
|
||||
if(tex->type == TEX_VOXELDATA && tex->vd) writestruct(wd, DATA, "VoxelData", 1, tex->vd);
|
||||
|
||||
/* nodetree is integral part of texture, no libdata */
|
||||
if(tex->nodetree) {
|
||||
|
@ -307,6 +307,8 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre
|
||||
/* turn on raytracing if needed */
|
||||
if(mat->mode_l & MA_RAYMIRROR)
|
||||
sce->r.mode |= R_RAYTRACE;
|
||||
if(mat->material_type == MA_TYPE_VOLUME)
|
||||
sce->r.mode |= R_RAYTRACE;
|
||||
if((mat->mode_l & MA_RAYTRANSP) && (mat->mode_l & MA_TRANSP))
|
||||
sce->r.mode |= R_RAYTRACE;
|
||||
if(mat->sss_flag & MA_DIFF_SSS)
|
||||
|
@ -47,6 +47,34 @@ struct Ipo;
|
||||
|
||||
/* WATCH IT: change type? also make changes in ipo.h */
|
||||
|
||||
typedef struct VolumeSettings {
|
||||
float density;
|
||||
float emission;
|
||||
float absorption;
|
||||
float scattering;
|
||||
|
||||
float emission_col[3];
|
||||
float absorption_col[3];
|
||||
float density_scale;
|
||||
float depth_cutoff;
|
||||
|
||||
short phasefunc_type;
|
||||
short vpad[3];
|
||||
float phasefunc_g;
|
||||
|
||||
float stepsize;
|
||||
float shade_stepsize;
|
||||
|
||||
short stepsize_type;
|
||||
short shadeflag;
|
||||
short shade_type;
|
||||
short precache_resolution;
|
||||
|
||||
float ms_diff;
|
||||
float ms_intensity;
|
||||
int ms_steps;
|
||||
} VolumeSettings;
|
||||
|
||||
typedef struct Material {
|
||||
ID id;
|
||||
struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */
|
||||
@ -62,6 +90,8 @@ typedef struct Material {
|
||||
float translucency;
|
||||
/* end synced with render_types.h */
|
||||
|
||||
struct VolumeSettings vol;
|
||||
|
||||
float fresnel_mir, fresnel_mir_i;
|
||||
float fresnel_tra, fresnel_tra_i;
|
||||
float filter; /* filter added, for raytrace transparency and transmissivity */
|
||||
@ -287,6 +317,14 @@ typedef struct Material {
|
||||
#define MAP_WARP 8192
|
||||
#define MAP_LAYER 16384
|
||||
|
||||
/* volume mapto - reuse definitions for now - a bit naughty! */
|
||||
#define MAP_DENSITY 128
|
||||
#define MAP_EMISSION 64
|
||||
#define MAP_EMISSION_COL 1
|
||||
#define MAP_ABSORPTION 512
|
||||
#define MAP_ABSORPTION_COL 8
|
||||
#define MAP_SCATTERING 16
|
||||
|
||||
/* mapto for halo */
|
||||
//#define MAP_HA_COL 1
|
||||
//#define MAP_HA_ALPHA 128
|
||||
@ -330,5 +368,29 @@ typedef struct Material {
|
||||
/* sss_flag */
|
||||
#define MA_DIFF_SSS 1
|
||||
|
||||
/* vol_stepsize_type */
|
||||
#define MA_VOL_STEP_RANDOMIZED 0
|
||||
#define MA_VOL_STEP_CONSTANT 1
|
||||
#define MA_VOL_STEP_ADAPTIVE 2
|
||||
|
||||
/* vol_shadeflag */
|
||||
#define MA_VOL_SHADED 1
|
||||
#define MA_VOL_RECVSHADOW 4
|
||||
#define MA_VOL_PRECACHESHADING 8
|
||||
|
||||
/* vol_shading_type */
|
||||
#define MA_VOL_SHADE_NONE 0
|
||||
#define MA_VOL_SHADE_SINGLE 1
|
||||
#define MA_VOL_SHADE_MULTIPLE 2
|
||||
#define MA_VOL_SHADE_SINGLEPLUSMULTIPLE 3
|
||||
|
||||
/* vol_phasefunc_type */
|
||||
#define MA_VOL_PH_ISOTROPIC 0
|
||||
#define MA_VOL_PH_MIEHAZY 1
|
||||
#define MA_VOL_PH_MIEMURKY 2
|
||||
#define MA_VOL_PH_RAYLEIGH 3
|
||||
#define MA_VOL_PH_HG 4
|
||||
#define MA_VOL_PH_SCHLICK 5
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -128,6 +128,55 @@ typedef struct EnvMap {
|
||||
short recalc, lastsize;
|
||||
} EnvMap;
|
||||
|
||||
typedef struct PointDensity {
|
||||
short flag;
|
||||
|
||||
short falloff_type;
|
||||
float falloff_softness;
|
||||
float radius;
|
||||
short source;
|
||||
short color_source;
|
||||
int totpoints;
|
||||
|
||||
int pdpad;
|
||||
|
||||
struct Object *object; /* for 'Object' or 'Particle system' type - source object */
|
||||
struct ParticleSystem *psys;
|
||||
short psys_cache_space; /* cache points in worldspace, object space, ... ? */
|
||||
short ob_cache_space; /* cache points in worldspace, object space, ... ? */
|
||||
|
||||
short pdpad2[2];
|
||||
|
||||
void *point_tree; /* the acceleration tree containing points */
|
||||
float *point_data; /* dynamically allocated extra for extra information, like particle age */
|
||||
|
||||
float noise_size;
|
||||
short noise_depth;
|
||||
short noise_influence;
|
||||
short noise_basis;
|
||||
short pdpad3[3];
|
||||
float noise_fac;
|
||||
|
||||
float speed_scale;
|
||||
struct ColorBand *coba; /* for time -> color */
|
||||
|
||||
} PointDensity;
|
||||
|
||||
typedef struct VoxelData {
|
||||
int resol[3];
|
||||
int interp_type;
|
||||
short file_format;
|
||||
short flag;
|
||||
int pad;
|
||||
|
||||
struct Object *object; /* for rendering smoke sims */
|
||||
float int_multiplier;
|
||||
int still_frame;
|
||||
char source_path[240];
|
||||
float *dataset;
|
||||
|
||||
} VoxelData;
|
||||
|
||||
typedef struct Tex {
|
||||
ID id;
|
||||
struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */
|
||||
@ -181,6 +230,8 @@ typedef struct Tex {
|
||||
struct ColorBand *coba;
|
||||
struct EnvMap *env;
|
||||
struct PreviewImage * preview;
|
||||
struct PointDensity *pd;
|
||||
struct VoxelData *vd;
|
||||
|
||||
char use_nodes;
|
||||
char pad[7];
|
||||
@ -220,6 +271,8 @@ typedef struct TexMapping {
|
||||
#define TEX_MUSGRAVE 11
|
||||
#define TEX_VORONOI 12
|
||||
#define TEX_DISTNOISE 13
|
||||
#define TEX_POINTDENSITY 14
|
||||
#define TEX_VOXELDATA 15
|
||||
|
||||
/* musgrave stype */
|
||||
#define TEX_MFRACTAL 0
|
||||
@ -417,5 +470,59 @@ typedef struct TexMapping {
|
||||
#define ENV_NORMAL 1
|
||||
#define ENV_OSA 2
|
||||
|
||||
/* **************** PointDensity ********************* */
|
||||
|
||||
/* source */
|
||||
#define TEX_PD_PSYS 0
|
||||
#define TEX_PD_OBJECT 1
|
||||
#define TEX_PD_FILE 2
|
||||
|
||||
/* falloff_type */
|
||||
#define TEX_PD_FALLOFF_STD 0
|
||||
#define TEX_PD_FALLOFF_SMOOTH 1
|
||||
#define TEX_PD_FALLOFF_SOFT 2
|
||||
#define TEX_PD_FALLOFF_CONSTANT 3
|
||||
#define TEX_PD_FALLOFF_ROOT 4
|
||||
|
||||
/* psys_cache_space */
|
||||
#define TEX_PD_OBJECTLOC 0
|
||||
#define TEX_PD_OBJECTSPACE 1
|
||||
#define TEX_PD_WORLDSPACE 2
|
||||
|
||||
/* flag */
|
||||
#define TEX_PD_TURBULENCE 1
|
||||
|
||||
|
||||
/* noise_influence */
|
||||
#define TEX_PD_NOISE_STATIC 0
|
||||
#define TEX_PD_NOISE_VEL 1
|
||||
#define TEX_PD_NOISE_AGE 2
|
||||
#define TEX_PD_NOISE_TIME 3
|
||||
|
||||
/* color_source */
|
||||
#define TEX_PD_COLOR_CONSTANT 0
|
||||
#define TEX_PD_COLOR_PARTAGE 1
|
||||
#define TEX_PD_COLOR_PARTSPEED 2
|
||||
#define TEX_PD_COLOR_PARTVEL 3
|
||||
|
||||
#define POINT_DATA_VEL 1
|
||||
#define POINT_DATA_LIFE 2
|
||||
|
||||
/******************** Voxel Data *****************************/
|
||||
/* flag */
|
||||
#define TEX_VD_STILL 1
|
||||
|
||||
/* interpolation */
|
||||
#define TEX_VD_NEARESTNEIGHBOR 0
|
||||
#define TEX_VD_LINEAR 1
|
||||
#define TEX_VD_TRICUBIC 2
|
||||
|
||||
/* file format */
|
||||
#define TEX_VD_BLENDERVOXEL 0
|
||||
#define TEX_VD_RAW_8BIT 1
|
||||
#define TEX_VD_RAW_16BIT 2
|
||||
#define TEX_VD_IMAGE_SEQUENCE 3
|
||||
#define TEX_VD_SMOKE 4
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -321,6 +321,8 @@ extern StructRNA RNA_ParticleTarget;
|
||||
extern StructRNA RNA_PluginSequence;
|
||||
extern StructRNA RNA_PluginTexture;
|
||||
extern StructRNA RNA_PointCache;
|
||||
extern StructRNA RNA_PointDensity;
|
||||
extern StructRNA RNA_PointDensityTexture;
|
||||
extern StructRNA RNA_PointerProperty;
|
||||
extern StructRNA RNA_Pose;
|
||||
extern StructRNA RNA_PoseChannel;
|
||||
@ -499,6 +501,8 @@ extern StructRNA RNA_VertexGroup;
|
||||
extern StructRNA RNA_VertexGroupElement;
|
||||
extern StructRNA RNA_VertexPaint;
|
||||
extern StructRNA RNA_VoronoiTexture;
|
||||
extern StructRNA RNA_VoxelData;
|
||||
extern StructRNA RNA_VoxelDataTexture;
|
||||
extern StructRNA RNA_WaveModifier;
|
||||
extern StructRNA RNA_Window;
|
||||
extern StructRNA RNA_WindowManager;
|
||||
|
@ -479,6 +479,75 @@ static void rna_def_material_mtex(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Ambient Factor", "Amount texture affects ambient.");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
/* volume material */
|
||||
prop= RNA_def_property(srna, "map_coloremission", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_EMISSION_COL);
|
||||
RNA_def_property_ui_text(prop, "Emission Color", "Causes the texture to affect the colour of emission");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "map_colorabsorption", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_ABSORPTION_COL);
|
||||
RNA_def_property_ui_text(prop, "Absorption Color", "Causes the texture to affect the result colour after absorption");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "map_density", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_DENSITY);
|
||||
RNA_def_property_ui_text(prop, "Density", "Causes the texture to affect the volume's density");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "map_emission", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_EMISSION);
|
||||
RNA_def_property_ui_text(prop, "Emission", "Causes the texture to affect the volume's emission");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "map_absorption", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_ABSORPTION);
|
||||
RNA_def_property_ui_text(prop, "Absorption", "Causes the texture to affect the volume's absorption");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "map_scattering", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_SCATTERING);
|
||||
RNA_def_property_ui_text(prop, "Scattering", "Causes the texture to affect the volume's scattering");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "coloremission_factor", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "colfac");
|
||||
RNA_def_property_ui_range(prop, 0, 1, 10, 3);
|
||||
RNA_def_property_ui_text(prop, "Emission Color Factor", "Amount texture affects emission color.");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "colorabsorption_factor", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "colfac");
|
||||
RNA_def_property_ui_range(prop, 0, 1, 10, 3);
|
||||
RNA_def_property_ui_text(prop, "Absorpion Color Factor", "Amount texture affects diffuse color.");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "density_factor", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "varfac");
|
||||
RNA_def_property_ui_range(prop, 0, 1, 10, 3);
|
||||
RNA_def_property_ui_text(prop, "Density Factor", "Amount texture affects density.");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "emission_factor", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "varfac");
|
||||
RNA_def_property_ui_range(prop, 0, 1, 10, 3);
|
||||
RNA_def_property_ui_text(prop, "Emission Factor", "Amount texture affects emission.");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "absorption_factor", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "varfac");
|
||||
RNA_def_property_ui_range(prop, 0, 1, 10, 3);
|
||||
RNA_def_property_ui_text(prop, "Absorption Factor", "Amount texture affects absorption.");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "scattering_factor", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "varfac");
|
||||
RNA_def_property_ui_range(prop, 0, 1, 10, 3);
|
||||
RNA_def_property_ui_text(prop, "Scattering Factor", "Amount texture affects scattering.");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
/* end volume material */
|
||||
|
||||
prop= RNA_def_property(srna, "enabled", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_funcs(prop, "rna_MaterialTextureSlot_enabled_get", "rna_MaterialTextureSlot_enabled_set");
|
||||
RNA_def_property_ui_text(prop, "Enabled", "Enable this material texture slot.");
|
||||
@ -809,6 +878,159 @@ static void rna_def_material_raytra(BlenderRNA *brna)
|
||||
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_material_volume(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
static EnumPropertyItem prop_scattering_items[] = {
|
||||
{MA_VOL_SHADE_NONE, "NONE", 0, "None", ""},
|
||||
{MA_VOL_SHADE_SINGLE, "SINGLE_SCATTERING", 0, "Single Scattering", ""},
|
||||
{MA_VOL_SHADE_MULTIPLE, "MULTIPLE_SCATTERING", 0, "Multiple Scattering", ""},
|
||||
{MA_VOL_SHADE_SINGLEPLUSMULTIPLE, "SINGLE_PLUS_MULTIPLE_SCATTERING", 0, "Single + Multiple Scattering", ""},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
static EnumPropertyItem prop_stepsize_items[] = {
|
||||
{MA_VOL_STEP_RANDOMIZED, "RANDOMIZED", 0, "Randomized", ""},
|
||||
{MA_VOL_STEP_CONSTANT, "CONSTANT", 0, "Constant", ""},
|
||||
//{MA_VOL_STEP_ADAPTIVE, "ADAPTIVE", 0, "Adaptive", ""},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
static EnumPropertyItem prop_phasefunction_items[] = {
|
||||
{MA_VOL_PH_ISOTROPIC, "ISOTROPIC", 0, "Isotropic", ""},
|
||||
{MA_VOL_PH_MIEHAZY, "MIE_HAZY", 0, "Mie Hazy", ""},
|
||||
{MA_VOL_PH_MIEMURKY, "MIE_MURKY", 0, "Mie Murky", ""},
|
||||
{MA_VOL_PH_RAYLEIGH, "RAYLEIGH", 0, "Rayleigh", ""},
|
||||
{MA_VOL_PH_HG, "HENYEY-GREENSTEIN", 0, "Henyey-Greenstein", ""},
|
||||
{MA_VOL_PH_SCHLICK, "SCHLICK", 0, "Schlick", ""},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
srna= RNA_def_struct(brna, "MaterialVolume", NULL);
|
||||
RNA_def_struct_sdna(srna, "VolumeSettings");
|
||||
RNA_def_struct_nested(brna, srna, "Material");
|
||||
RNA_def_struct_ui_text(srna, "Material Volume", "Volume rendering settings for a Material datablock.");
|
||||
|
||||
prop= RNA_def_property(srna, "step_calculation", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "stepsize_type");
|
||||
RNA_def_property_enum_items(prop, prop_stepsize_items);
|
||||
RNA_def_property_ui_text(prop, "Step Calculation", "Method of calculating the steps through the volume");
|
||||
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "step_size", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "stepsize");
|
||||
RNA_def_property_range(prop, 0.0f, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 1, 3);
|
||||
RNA_def_property_ui_text(prop, "Step Size", "Distance between subsequent volume depth samples.");
|
||||
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "shading_step_size", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "shade_stepsize");
|
||||
RNA_def_property_range(prop, 0.0f, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 1, 3);
|
||||
RNA_def_property_ui_text(prop, "Shading Step Size", "Distance between subsequent volume shading samples.");
|
||||
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "scattering_mode", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "shade_type");
|
||||
RNA_def_property_enum_items(prop, prop_scattering_items);
|
||||
RNA_def_property_ui_text(prop, "Scattering Mode", "Method of shading, attenuating, and scattering light through the volume");
|
||||
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "light_cache", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "shadeflag", MA_VOL_PRECACHESHADING); /* use bitflags */
|
||||
RNA_def_property_ui_text(prop, "Light Cache", "Pre-calculate the shading information into a voxel grid, speeds up shading at slightly less accuracy");
|
||||
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "cache_resolution", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "precache_resolution");
|
||||
RNA_def_property_range(prop, 0, 1024);
|
||||
RNA_def_property_ui_text(prop, "Resolution", "Resolution of the voxel grid, low resolutions are faster, high resolutions use more memory.");
|
||||
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "ms_diffusion", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "ms_diff");
|
||||
RNA_def_property_range(prop, 0.0f, FLT_MAX);
|
||||
RNA_def_property_ui_text(prop, "Diffusion", "Diffusion factor, the strength of the blurring effect");
|
||||
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "ms_spread", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "ms_steps");
|
||||
RNA_def_property_range(prop, 0, 1024);
|
||||
RNA_def_property_ui_text(prop, "Spread", "Simulation steps, the effective distance over which the light is diffused");
|
||||
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "ms_intensity", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "ms_intensity");
|
||||
RNA_def_property_range(prop, 0.0f, FLT_MAX);
|
||||
RNA_def_property_ui_text(prop, "Intensity", "Multiplier for multiple scattered light energy");
|
||||
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "depth_cutoff", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "depth_cutoff");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Depth Cutoff", "Stop ray marching early if transmission drops below this luminance - higher values give speedups in dense volumes at the expense of accuracy.");
|
||||
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "density", PROP_FLOAT, PROP_PERCENTAGE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "density");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Density", "The base density of the volume");
|
||||
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "density_scale", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "density_scale");
|
||||
RNA_def_property_range(prop, 0.0f, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
|
||||
RNA_def_property_ui_text(prop, "Density Scale", "Multiplier for the material's density");
|
||||
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "absorption", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "absorption");
|
||||
RNA_def_property_range(prop, 0.0f, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
|
||||
RNA_def_property_ui_text(prop, "Absorption", "Amount of light that gets absorbed by the volume - higher values mean light travels less distance");
|
||||
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "absorption_color", PROP_FLOAT, PROP_COLOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "absorption_col");
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_ui_text(prop, "Absorption Color", "");
|
||||
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING_DRAW, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "scattering", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "scattering");
|
||||
RNA_def_property_range(prop, 0.0f, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1 ,3);
|
||||
RNA_def_property_ui_text(prop, "Scattering", "Amount of light that gets scattered by the volume - values > 1.0 are non-physical");
|
||||
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "emission", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "emission");
|
||||
RNA_def_property_range(prop, 0.0f, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
|
||||
RNA_def_property_ui_text(prop, "Emission", "Amount of light that gets emitted by the volume");
|
||||
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "emission_color", PROP_FLOAT, PROP_COLOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "emission_col");
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_ui_text(prop, "Emission Color", "");
|
||||
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING_DRAW, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "phase_function", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "phasefunc_type");
|
||||
RNA_def_property_enum_items(prop, prop_phasefunction_items);
|
||||
RNA_def_property_ui_text(prop, "Phase Function", "Isotropic/Anisotropic scattering");
|
||||
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "asymmetry", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "phasefunc_g");
|
||||
RNA_def_property_range(prop, -1.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Asymmetry", "Continuum between forward scattering and back scattering");
|
||||
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void rna_def_material_halo(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
@ -1182,7 +1404,7 @@ void RNA_def_material(BlenderRNA *brna)
|
||||
static EnumPropertyItem prop_type_items[] = {
|
||||
{MA_TYPE_SURFACE, "SURFACE", 0, "Surface", "Render object as a surface."},
|
||||
{MA_TYPE_WIRE, "WIRE", 0, "Wire", "Render the edges of faces as wires (not supported in ray tracing)."},
|
||||
// {MA_TYPE_VOLUME, "VOLUME", 0, "Volume", "Render object as a volume."},
|
||||
{MA_TYPE_VOLUME, "VOLUME", 0, "Volume", "Render object as a volume."},
|
||||
{MA_TYPE_HALO, "HALO", 0, "Halo", "Render object as halo particles."},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
static EnumPropertyItem transparency_items[] = {
|
||||
@ -1365,6 +1587,11 @@ void RNA_def_material(BlenderRNA *brna)
|
||||
RNA_def_property_pointer_funcs(prop, "rna_Material_transp_get", NULL, NULL);
|
||||
RNA_def_property_ui_text(prop, "Raytrace Transparency", "Raytraced reflection settings for the material.");
|
||||
|
||||
prop= RNA_def_property(srna, "volume", PROP_POINTER, PROP_NEVER_NULL);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "vol");
|
||||
RNA_def_property_struct_type(prop, "MaterialVolume");
|
||||
RNA_def_property_ui_text(prop, "Volume", "Volume settings for the material.");
|
||||
|
||||
prop= RNA_def_property(srna, "halo", PROP_POINTER, PROP_NEVER_NULL);
|
||||
RNA_def_property_struct_type(prop, "MaterialHalo");
|
||||
RNA_def_property_pointer_funcs(prop, "rna_Material_halo_get", NULL, NULL);
|
||||
@ -1408,6 +1635,7 @@ void RNA_def_material(BlenderRNA *brna)
|
||||
/* nested structs */
|
||||
rna_def_material_raymirror(brna);
|
||||
rna_def_material_raytra(brna);
|
||||
rna_def_material_volume(brna);
|
||||
rna_def_material_halo(brna);
|
||||
rna_def_material_sss(brna);
|
||||
rna_def_material_mtex(brna);
|
||||
|
@ -86,11 +86,32 @@ StructRNA *rna_Texture_refine(struct PointerRNA *ptr)
|
||||
return &RNA_VoronoiTexture;
|
||||
case TEX_DISTNOISE:
|
||||
return &RNA_DistortedNoiseTexture;
|
||||
case TEX_POINTDENSITY:
|
||||
return &RNA_PointDensityTexture;
|
||||
case TEX_VOXELDATA:
|
||||
return &RNA_VoxelDataTexture;
|
||||
default:
|
||||
return &RNA_Texture;
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_Texture_type_set(PointerRNA *ptr, int value)
|
||||
{
|
||||
Tex *tex= (Tex*)ptr->data;
|
||||
|
||||
if (value == TEX_VOXELDATA) {
|
||||
if (tex->vd == NULL) {
|
||||
tex->vd = BKE_add_voxeldata();
|
||||
}
|
||||
} else if (value == TEX_POINTDENSITY) {
|
||||
if (tex->pd == NULL) {
|
||||
tex->pd = BKE_add_pointdensity();
|
||||
}
|
||||
}
|
||||
|
||||
tex->type = value;
|
||||
}
|
||||
|
||||
static int rna_TextureSlot_name_length(PointerRNA *ptr)
|
||||
{
|
||||
MTex *mtex= ptr->data;
|
||||
@ -1304,6 +1325,200 @@ static void rna_def_texture_distorted_noise(BlenderRNA *brna)
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_texture_pointdensity(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
static EnumPropertyItem point_source_items[] = {
|
||||
{TEX_PD_PSYS, "PARTICLE_SYSTEM", 0, "Particle System", "Generate point density from a particle system"},
|
||||
{TEX_PD_OBJECT, "OBJECT", 0, "Object Vertices", "Generate point density from an object's vertices"},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
static EnumPropertyItem falloff_items[] = {
|
||||
{TEX_PD_FALLOFF_STD, "STANDARD", 0, "Standard", ""},
|
||||
{TEX_PD_FALLOFF_SMOOTH, "SMOOTH", 0, "Smooth", ""},
|
||||
{TEX_PD_FALLOFF_SOFT, "SOFT", 0, "Soft", ""},
|
||||
{TEX_PD_FALLOFF_CONSTANT, "CONSTANT", 0, "Constant", "Density is constant within lookup radius"},
|
||||
{TEX_PD_FALLOFF_ROOT, "ROOT", 0, "Root", ""},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
static EnumPropertyItem color_source_items[] = {
|
||||
{TEX_PD_COLOR_CONSTANT, "CONSTANT", 0, "Constant", ""},
|
||||
{TEX_PD_COLOR_PARTAGE, "PARTICLE_AGE", 0, "Particle Age", "Lifetime mapped as 0.0 - 1.0 intensity"},
|
||||
{TEX_PD_COLOR_PARTSPEED, "PARTICLE_SPEED", 0, "Particle Speed", "Particle speed (absolute magnitude of velocity) mapped as 0.0-1.0 intensity"},
|
||||
{TEX_PD_COLOR_PARTVEL, "PARTICLE_VELOCITY", 0, "Particle Velocity", "XYZ velocity mapped to RGB colors"},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
static EnumPropertyItem turbulence_influence_items[] = {
|
||||
{TEX_PD_NOISE_STATIC, "STATIC", 0, "Static", "Noise patterns will remain unchanged, faster and suitable for stills"},
|
||||
{TEX_PD_NOISE_VEL, "PARTICLE_VELOCITY", 0, "Particle Velocity", "Turbulent noise driven by particle velocity"},
|
||||
{TEX_PD_NOISE_AGE, "PARTICLE_AGE", 0, "Particle Age", "Turbulent noise driven by the particle's age between birth and death"},
|
||||
{TEX_PD_NOISE_TIME, "GLOBAL_TIME", 0, "Global Time", "Turbulent noise driven by the global current frame"},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
srna= RNA_def_struct(brna, "PointDensity", NULL);
|
||||
RNA_def_struct_sdna(srna, "PointDensity");
|
||||
RNA_def_struct_ui_text(srna, "PointDensity", "Point density settings.");
|
||||
|
||||
prop= RNA_def_property(srna, "point_source", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "source");
|
||||
RNA_def_property_enum_items(prop, point_source_items);
|
||||
RNA_def_property_ui_text(prop, "Point Source", "Point data to use as renderable point density");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "object");
|
||||
RNA_def_property_ui_text(prop, "Object", "Object to take point data from");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "particle_system", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "psys");
|
||||
RNA_def_property_ui_text(prop, "Particle System", "Particle System to render as points");
|
||||
RNA_def_property_struct_type(prop, "ParticleSystem");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "radius", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "radius");
|
||||
RNA_def_property_range(prop, 0.01, FLT_MAX);
|
||||
RNA_def_property_ui_text(prop, "Radius", "Radius from the shaded sample to look for points within");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "falloff", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "falloff_type");
|
||||
RNA_def_property_enum_items(prop, falloff_items);
|
||||
RNA_def_property_ui_text(prop, "Falloff", "Method of attenuating density by distance from the point");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "falloff_softness", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "falloff_softness");
|
||||
RNA_def_property_range(prop, 0.01, FLT_MAX);
|
||||
RNA_def_property_ui_text(prop, "Softness", "Softness of the 'soft' falloff option");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "color_source", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "color_source");
|
||||
RNA_def_property_enum_items(prop, color_source_items);
|
||||
RNA_def_property_ui_text(prop, "Color Source", "Data to derive color results from");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "turbulence", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", TEX_PD_TURBULENCE);
|
||||
RNA_def_property_ui_text(prop, "Turbulence", "Add directed noise to the density at render-time");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "turbulence_size", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "noise_size");
|
||||
RNA_def_property_range(prop, 0.01, FLT_MAX);
|
||||
RNA_def_property_ui_text(prop, "Size", "Scale of the added turbulent noise");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "turbulence_depth", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "noise_depth");
|
||||
RNA_def_property_range(prop, 0, INT_MAX);
|
||||
RNA_def_property_ui_text(prop, "Depth", "Level of detail in the added turbulent noise");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "turbulence_influence", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "noise_influence");
|
||||
RNA_def_property_enum_items(prop, turbulence_influence_items);
|
||||
RNA_def_property_ui_text(prop, "Turbulence Influence", "Method for driving added turbulent noise");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
|
||||
|
||||
srna= RNA_def_struct(brna, "PointDensityTexture", "Texture");
|
||||
RNA_def_struct_sdna(srna, "Tex");
|
||||
RNA_def_struct_ui_text(srna, "Point Density", "Settings for the Point Density texture");
|
||||
|
||||
prop= RNA_def_property(srna, "pointdensity", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "pd");
|
||||
RNA_def_property_struct_type(prop, "PointDensity");
|
||||
RNA_def_property_ui_text(prop, "Point Density", "The point density settings associated with this texture");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_texture_voxeldata(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
static EnumPropertyItem interpolation_type_items[] = {
|
||||
{TEX_VD_NEARESTNEIGHBOR, "NEREASTNEIGHBOR", 0, "Nearest Neighbor", "No interpolation, fast but blocky and low quality."},
|
||||
{TEX_VD_LINEAR, "TRILINEAR", 0, "Trilinear", "Good smoothness and speed"},
|
||||
{TEX_VD_TRICUBIC, "TRICUBIC", 0, "Tricubic", "High quality interpolation, but slow"},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
static EnumPropertyItem file_format_items[] = {
|
||||
{TEX_VD_BLENDERVOXEL, "BLENDER_VOXEL", 0, "Blender Voxel", "Default binary voxel file format"},
|
||||
{TEX_VD_RAW_8BIT, "RAW_8BIT", 0, "8 bit RAW", "8 bit greyscale binary data"},
|
||||
{TEX_VD_IMAGE_SEQUENCE, "IMAGE_SEQUENCE", 0, "Image Sequence", "Generate voxels from a sequence of image slices"},
|
||||
{TEX_VD_SMOKE, "SMOKE", 0, "Smoke", "Render voxels from a Blender smoke simulation"},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
srna= RNA_def_struct(brna, "VoxelData", NULL);
|
||||
RNA_def_struct_sdna(srna, "VoxelData");
|
||||
RNA_def_struct_ui_text(srna, "VoxelData", "Voxel data settings.");
|
||||
|
||||
prop= RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "interp_type");
|
||||
RNA_def_property_enum_items(prop, interpolation_type_items);
|
||||
RNA_def_property_ui_text(prop, "Interpolation", "Method to interpolate/smooth values between voxel cells");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "intensity", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "int_multiplier");
|
||||
RNA_def_property_range(prop, 0.01, FLT_MAX);
|
||||
RNA_def_property_ui_text(prop, "Intensity", "Multiplier for intensity values");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "file_format", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "file_format");
|
||||
RNA_def_property_enum_items(prop, file_format_items);
|
||||
RNA_def_property_ui_text(prop, "File Format", "Format of the source data set to render ");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "source_path", PROP_STRING, PROP_FILEPATH);
|
||||
RNA_def_property_string_sdna(prop, NULL, "source_path");
|
||||
RNA_def_property_ui_text(prop, "Source Path", "The external source data file to use");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "resolution", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "resol");
|
||||
RNA_def_property_ui_text(prop, "Resolution", "Resolution of the voxel grid.");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "still", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", TEX_VD_STILL);
|
||||
RNA_def_property_ui_text(prop, "Still Frame Only", "Always render a still frame from the voxel data sequence");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "still_frame_number", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "still_frame");
|
||||
RNA_def_property_range(prop, 0, INT_MAX);
|
||||
RNA_def_property_ui_text(prop, "Still Frame Number", "The frame number to always use");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "domain_object", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "object");
|
||||
RNA_def_property_ui_text(prop, "Domain Object", "Object used as the smoke simulation domain");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
|
||||
srna= RNA_def_struct(brna, "VoxelDataTexture", "Texture");
|
||||
RNA_def_struct_sdna(srna, "Tex");
|
||||
RNA_def_struct_ui_text(srna, "Voxel Data", "Settings for the Voxel Data texture");
|
||||
|
||||
prop= RNA_def_property(srna, "voxeldata", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "vd");
|
||||
RNA_def_property_struct_type(prop, "VoxelData");
|
||||
RNA_def_property_ui_text(prop, "Voxel Data", "The voxel data associated with this texture");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_texture(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
@ -1324,6 +1539,8 @@ static void rna_def_texture(BlenderRNA *brna)
|
||||
{TEX_MUSGRAVE, "MUSGRAVE", ICON_TEXTURE, "Musgrave", ""},
|
||||
{TEX_VORONOI, "VORONOI", ICON_TEXTURE, "Voronoi", ""},
|
||||
{TEX_DISTNOISE, "DISTORTED_NOISE", ICON_TEXTURE, "Distorted Noise", ""},
|
||||
{TEX_POINTDENSITY, "POINT_DENSITY", ICON_TEXTURE, "Point Density", ""},
|
||||
{TEX_VOXELDATA, "VOXEL_DATA", ICON_TEXTURE, "Voxel Data", ""},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
srna= RNA_def_struct(brna, "Texture", "ID");
|
||||
@ -1336,6 +1553,7 @@ static void rna_def_texture(BlenderRNA *brna)
|
||||
//RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "type");
|
||||
RNA_def_property_enum_items(prop, prop_type_items);
|
||||
RNA_def_property_enum_funcs(prop, NULL, "rna_Texture_type_set", NULL);
|
||||
RNA_def_property_ui_text(prop, "Type", "");
|
||||
RNA_def_property_update(prop, NC_TEXTURE, NULL);
|
||||
|
||||
@ -1399,6 +1617,8 @@ static void rna_def_texture(BlenderRNA *brna)
|
||||
rna_def_texture_musgrave(brna);
|
||||
rna_def_texture_voronoi(brna);
|
||||
rna_def_texture_distorted_noise(brna);
|
||||
rna_def_texture_pointdensity(brna);
|
||||
rna_def_texture_voxeldata(brna);
|
||||
/* XXX add more types here .. */
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@ SET(INC
|
||||
intern/include ../../../intern/guardedalloc ../blenlib ../makesdna
|
||||
extern/include ../blenkernel ../imbuf
|
||||
../include ../../kernel/gen_messaging ../blenloader
|
||||
../../../intern/smoke/extern
|
||||
../makesrna
|
||||
)
|
||||
|
||||
|
@ -6,7 +6,7 @@ sources = env.Glob('intern/source/*.c')
|
||||
|
||||
incs = 'intern/include #/intern/guardedalloc ../blenlib ../makesdna ../makesrna'
|
||||
incs += ' extern/include ../blenkernel ../radiosity/extern/include ../imbuf'
|
||||
incs += ' ../include ../blenloader'
|
||||
incs += ' ../include ../blenloader ../../../intern/smoke/extern'
|
||||
|
||||
defs = []
|
||||
|
||||
|
@ -112,7 +112,7 @@ typedef struct ShadeInput
|
||||
|
||||
/* internal face coordinates */
|
||||
float u, v, dx_u, dx_v, dy_u, dy_v;
|
||||
float co[3], view[3];
|
||||
float co[3], view[3], camera_co[3];
|
||||
|
||||
/* copy from material, keep synced so we can do memcopy */
|
||||
/* current size: 23*4 */
|
||||
@ -160,6 +160,7 @@ typedef struct ShadeInput
|
||||
|
||||
int samplenr; /* sample counter, to detect if we should do shadow again */
|
||||
int depth; /* 1 or larger on raytrace shading */
|
||||
int volume_depth; /* number of intersections through volumes */
|
||||
|
||||
/* stored copy of original face normal (facenor)
|
||||
* before flipping. Used in Front/back output on geometry node */
|
||||
|
44
source/blender/render/intern/include/pointdensity.h
Normal file
44
source/blender/render/intern/include/pointdensity.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
*
|
||||
* ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Matt Ebb
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef POINTDENSITY_H
|
||||
#define POINTDENSITY_H
|
||||
|
||||
/**
|
||||
* Make point density kd-trees for all point density textures in the scene
|
||||
*/
|
||||
|
||||
struct Render;
|
||||
struct TexResult;
|
||||
|
||||
void make_pointdensities(struct Render *re);
|
||||
void free_pointdensities(struct Render *re);
|
||||
int pointdensitytex(struct Tex *tex, float *texvec, struct TexResult *texres);
|
||||
|
||||
#endif /* POINTDENSITY_H */
|
||||
|
@ -201,6 +201,9 @@ struct Render
|
||||
ListBase customdata_names;
|
||||
|
||||
struct Object *excludeob;
|
||||
ListBase render_volumes_inside;
|
||||
ListBase volumes;
|
||||
ListBase volume_precache_parts;
|
||||
|
||||
/* arena for allocating data for use during render, for
|
||||
* example dynamic TFaces to go in the VlakRen structure.
|
||||
@ -292,7 +295,9 @@ typedef struct ObjectInstanceRen {
|
||||
|
||||
float dupliorco[3], dupliuv[2];
|
||||
float (*duplitexmat)[4];
|
||||
|
||||
|
||||
struct VolumePrecache *volume_precache;
|
||||
|
||||
float *vectors;
|
||||
int totvector;
|
||||
} ObjectInstanceRen;
|
||||
@ -402,6 +407,45 @@ typedef struct StrandRen {
|
||||
float orco[3];
|
||||
} StrandRen;
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
typedef struct VolumeOb
|
||||
{
|
||||
struct VolumeOb *next, *prev;
|
||||
struct Material *ma;
|
||||
struct ObjectRen *obr;
|
||||
} VolumeOb;
|
||||
|
||||
typedef struct MatInside {
|
||||
struct MatInside *next, *prev;
|
||||
struct Material *ma;
|
||||
} MatInside;
|
||||
|
||||
typedef struct VolPrecachePart
|
||||
{
|
||||
struct VolPrecachePart *next, *prev;
|
||||
struct RayTree *tree;
|
||||
struct ShadeInput *shi;
|
||||
struct ObjectInstanceRen *obi;
|
||||
int num;
|
||||
int minx, maxx;
|
||||
int miny, maxy;
|
||||
int minz, maxz;
|
||||
int res[3];
|
||||
float bbmin[3];
|
||||
float voxel[3];
|
||||
int working, done;
|
||||
} VolPrecachePart;
|
||||
|
||||
typedef struct VolumePrecache
|
||||
{
|
||||
int res[3];
|
||||
float *data_r;
|
||||
float *data_g;
|
||||
float *data_b;
|
||||
} VolumePrecache;
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct LampRen;
|
||||
struct MTex;
|
||||
|
@ -33,6 +33,7 @@ struct VlakRen;
|
||||
struct StrandSegment;
|
||||
struct StrandPoint;
|
||||
struct ObjectInstanceRen obi;
|
||||
struct Isect;
|
||||
|
||||
/* shadeinput.c */
|
||||
|
||||
@ -52,6 +53,7 @@ typedef struct ShadeSample {
|
||||
|
||||
/* also the node shader callback */
|
||||
void shade_material_loop(struct ShadeInput *shi, struct ShadeResult *shr);
|
||||
void shade_volume_loop(struct ShadeInput *shi, struct ShadeResult *shr);
|
||||
|
||||
void shade_input_set_triangle_i(struct ShadeInput *shi, struct ObjectInstanceRen *obi, struct VlakRen *vlr, short i1, short i2, short i3);
|
||||
void shade_input_set_triangle(struct ShadeInput *shi, volatile int obi, volatile int facenr, int normal_flip);
|
||||
@ -87,7 +89,11 @@ void shade_color(struct ShadeInput *shi, ShadeResult *shr);
|
||||
void ambient_occlusion_to_diffuse(struct ShadeInput *shi, float *diff);
|
||||
void ambient_occlusion(struct ShadeInput *shi);
|
||||
|
||||
ListBase *get_lights(struct ShadeInput *shi);
|
||||
float lamp_get_visibility(struct LampRen *lar, float *co, float *lv, float *dist);
|
||||
void lamp_get_shadow(struct LampRen *lar, ShadeInput *shi, float inp, float *shadfac, int do_real);
|
||||
|
||||
float fresnel_fac(float *view, float *vn, float fresnel, float fac);
|
||||
|
||||
/* rayshade.c */
|
||||
extern void shade_ray(struct Isect *is, struct ShadeInput *shi, struct ShadeResult *shr);
|
||||
|
@ -56,6 +56,7 @@ void do_halo_tex(struct HaloRen *har, float xn, float yn, float *colf);
|
||||
void do_sky_tex(float *rco, float *lo, float *dxyview, float *hor, float *zen, float *blend, int skyflag, short thread);
|
||||
void do_material_tex(struct ShadeInput *shi);
|
||||
void do_lamp_tex(LampRen *la, float *lavec, struct ShadeInput *shi, float *colf, int effect);
|
||||
void do_volume_tex(struct ShadeInput *shi, float *xyz, int mapto_flag, float *col, float *val);
|
||||
|
||||
void init_render_textures(Render *re);
|
||||
void end_render_textures(void);
|
||||
|
34
source/blender/render/intern/include/volume_precache.h
Normal file
34
source/blender/render/intern/include/volume_precache.h
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
*
|
||||
* ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Matt Ebb.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
void volume_precache(Render *re);
|
||||
void free_volume_precache(Render *re);
|
||||
int point_inside_volume_objectinstance(ObjectInstanceRen *obi, float *co);
|
||||
int using_lightcache(Material *ma);
|
||||
|
||||
#define VOL_MS_TIMESTEP 0.1f
|
47
source/blender/render/intern/include/volumetric.h
Normal file
47
source/blender/render/intern/include/volumetric.h
Normal file
@ -0,0 +1,47 @@
|
||||
/**
|
||||
*
|
||||
* ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Matt Ebb.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
float vol_get_stepsize(struct ShadeInput *shi, int context);
|
||||
float vol_get_density(struct ShadeInput *shi, float *co);
|
||||
void vol_get_scattering(ShadeInput *shi, float *scatter_col, float *co, float stepsize, float density);
|
||||
|
||||
void shade_volume_outside(ShadeInput *shi, ShadeResult *shr);
|
||||
void shade_volume_inside(ShadeInput *shi, ShadeResult *shr);
|
||||
void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is);
|
||||
|
||||
#define STEPSIZE_VIEW 0
|
||||
#define STEPSIZE_SHADE 1
|
||||
|
||||
#define VOL_IS_BACKFACE 1
|
||||
#define VOL_IS_SAMEMATERIAL 2
|
||||
|
||||
#define VOL_BOUNDS_DEPTH 0
|
||||
#define VOL_BOUNDS_SS 1
|
||||
|
||||
#define VOL_SHADE_OUTSIDE 0
|
||||
#define VOL_SHADE_INSIDE 1
|
45
source/blender/render/intern/include/voxeldata.h
Normal file
45
source/blender/render/intern/include/voxeldata.h
Normal file
@ -0,0 +1,45 @@
|
||||
/**
|
||||
*
|
||||
* ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Raul Fernandez Hernandez (Farsthary), Matt Ebb.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef VOXELDATA_H
|
||||
#define VOXELDATA_H
|
||||
|
||||
struct Render;
|
||||
struct TexResult;
|
||||
|
||||
typedef struct VoxelDataHeader
|
||||
{
|
||||
int resolX, resolY, resolZ;
|
||||
int frames;
|
||||
} VoxelDataHeader;
|
||||
|
||||
void make_voxeldata(struct Render *re);
|
||||
void free_voxeldata(struct Render *re);
|
||||
int voxeldatatex(struct Tex *tex, float *texvec, struct TexResult *texres);
|
||||
|
||||
#endif /* VOXELDATA_H */
|
@ -100,6 +100,8 @@
|
||||
|
||||
#include "envmap.h"
|
||||
#include "occlusion.h"
|
||||
#include "pointdensity.h"
|
||||
#include "voxeldata.h"
|
||||
#include "render_types.h"
|
||||
#include "rendercore.h"
|
||||
#include "renderdatabase.h"
|
||||
@ -108,6 +110,7 @@
|
||||
#include "shading.h"
|
||||
#include "strand.h"
|
||||
#include "texture.h"
|
||||
#include "volume_precache.h"
|
||||
#include "sss.h"
|
||||
#include "strand.h"
|
||||
#include "zbuf.h"
|
||||
@ -917,6 +920,7 @@ static Material *give_render_material(Render *re, Object *ob, int nr)
|
||||
|
||||
if(re->r.mode & R_SPEED) ma->texco |= NEED_UV;
|
||||
|
||||
if(ma->material_type == MA_TYPE_VOLUME) ma->mode |= MA_TRANSP;
|
||||
if((ma->mode & MA_TRANSP) && (ma->mode & MA_ZTRANSP))
|
||||
re->flag |= R_ZTRA;
|
||||
|
||||
@ -2976,6 +2980,52 @@ static void use_mesh_edge_lookup(ObjectRen *obr, DerivedMesh *dm, MEdge *medge,
|
||||
}
|
||||
}
|
||||
|
||||
static void free_camera_inside_volumes(Render *re)
|
||||
{
|
||||
BLI_freelistN(&re->render_volumes_inside);
|
||||
}
|
||||
|
||||
static void init_camera_inside_volumes(Render *re)
|
||||
{
|
||||
ObjectInstanceRen *obi;
|
||||
VolumeOb *vo;
|
||||
float co[3] = {0.f, 0.f, 0.f};
|
||||
|
||||
for(vo= re->volumes.first; vo; vo= vo->next) {
|
||||
for(obi= re->instancetable.first; obi; obi= obi->next) {
|
||||
if (obi->obr == vo->obr) {
|
||||
if (point_inside_volume_objectinstance(obi, co)) {
|
||||
MatInside *mi;
|
||||
|
||||
mi = MEM_mallocN(sizeof(MatInside), "camera inside material");
|
||||
mi->ma = vo->ma;
|
||||
|
||||
BLI_addtail(&(re->render_volumes_inside), mi);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* debug {
|
||||
MatInside *m;
|
||||
for (m=re->render_volumes_inside.first; m; m=m->next) {
|
||||
printf("matinside: ma: %s \n", m->ma->id.name+2);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
static void add_volume(Render *re, ObjectRen *obr, Material *ma)
|
||||
{
|
||||
struct VolumeOb *vo;
|
||||
|
||||
vo = MEM_mallocN(sizeof(VolumeOb), "volume object");
|
||||
|
||||
vo->ma = ma;
|
||||
vo->obr = obr;
|
||||
|
||||
BLI_addtail(&re->volumes, vo);
|
||||
}
|
||||
|
||||
static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
|
||||
{
|
||||
Object *ob= obr->ob;
|
||||
@ -3025,6 +3075,9 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
|
||||
}
|
||||
need_nmap_tangent= 1;
|
||||
}
|
||||
|
||||
if (ma->material_type == MA_TYPE_VOLUME)
|
||||
add_volume(re, obr, ma);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3809,6 +3862,7 @@ static void set_fullsample_flag(Render *re, ObjectRen *obr)
|
||||
vlr->flag |= R_FULL_OSA;
|
||||
else if(trace) {
|
||||
if(mode & MA_SHLESS);
|
||||
else if(vlr->mat->material_type == MA_TYPE_VOLUME);
|
||||
else if((mode & MA_RAYMIRROR) || ((mode & MA_TRANSP) && (mode & MA_RAYTRANSP)))
|
||||
/* for blurry reflect/refract, better to take more samples
|
||||
* inside the raytrace than as OSA samples */
|
||||
@ -4334,6 +4388,8 @@ void RE_Database_Free(Render *re)
|
||||
curvemapping_free(lar->curfalloff);
|
||||
}
|
||||
|
||||
free_volume_precache(re);
|
||||
|
||||
BLI_freelistN(&re->lampren);
|
||||
BLI_freelistN(&re->lights);
|
||||
|
||||
@ -4360,6 +4416,11 @@ void RE_Database_Free(Render *re)
|
||||
end_render_materials();
|
||||
end_render_textures();
|
||||
|
||||
free_pointdensities(re);
|
||||
free_voxeldata(re);
|
||||
|
||||
free_camera_inside_volumes(re);
|
||||
|
||||
if(re->wrld.aosphere) {
|
||||
MEM_freeN(re->wrld.aosphere);
|
||||
re->wrld.aosphere= NULL;
|
||||
@ -4752,6 +4813,8 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view)
|
||||
|
||||
/* MAKE RENDER DATA */
|
||||
database_init_objects(re, lay, 0, 0, 0, 0);
|
||||
|
||||
init_camera_inside_volumes(re);
|
||||
|
||||
if(!re->test_break(re->tbh)) {
|
||||
int tothalo;
|
||||
@ -4800,6 +4863,13 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view)
|
||||
/* ENVIRONMENT MAPS */
|
||||
if(!re->test_break(re->tbh))
|
||||
make_envmaps(re);
|
||||
|
||||
/* point density texture */
|
||||
if(!re->test_break(re->tbh))
|
||||
make_pointdensities(re);
|
||||
/* voxel data texture */
|
||||
if(!re->test_break(re->tbh))
|
||||
make_voxeldata(re);
|
||||
}
|
||||
|
||||
if(!re->test_break(re->tbh))
|
||||
@ -4816,6 +4886,11 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view)
|
||||
if((re->r.mode & R_SSS) && !re->test_break(re->tbh))
|
||||
if(re->r.renderer==R_INTERN)
|
||||
make_sss_tree(re);
|
||||
|
||||
if(!re->test_break(re->tbh))
|
||||
if(re->r.mode & R_RAYTRACE)
|
||||
volume_precache(re);
|
||||
|
||||
}
|
||||
|
||||
if(re->test_break(re->tbh))
|
||||
|
@ -630,7 +630,7 @@ static OcclusionTree *occ_tree_build(Render *re)
|
||||
if((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak;
|
||||
else vlr++;
|
||||
|
||||
if(vlr->mat->mode & MA_TRACEBLE)
|
||||
if((vlr->mat->mode & MA_TRACEBLE) && (vlr->mat->material_type == MA_TYPE_SURFACE))
|
||||
totface++;
|
||||
}
|
||||
}
|
||||
@ -663,7 +663,7 @@ static OcclusionTree *occ_tree_build(Render *re)
|
||||
if((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak;
|
||||
else vlr++;
|
||||
|
||||
if(vlr->mat->mode & MA_TRACEBLE) {
|
||||
if((vlr->mat->mode & MA_TRACEBLE) && (vlr->mat->material_type == MA_TYPE_SURFACE)) {
|
||||
tree->face[b].obi= c;
|
||||
tree->face[b].facenr= a;
|
||||
tree->occlusion[b]= 1.0f;
|
||||
|
484
source/blender/render/intern/source/pointdensity.c
Normal file
484
source/blender/render/intern/source/pointdensity.c
Normal file
@ -0,0 +1,484 @@
|
||||
/*
|
||||
* ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributors: Matt Ebb
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_arithb.h"
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_kdopbvh.h"
|
||||
|
||||
#include "BKE_DerivedMesh.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_lattice.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_particle.h"
|
||||
#include "BKE_texture.h"
|
||||
|
||||
#include "DNA_texture_types.h"
|
||||
#include "DNA_particle_types.h"
|
||||
|
||||
#include "render_types.h"
|
||||
#include "renderdatabase.h"
|
||||
#include "texture.h"
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
|
||||
/* only to be used here in this file, it's for speed */
|
||||
extern struct Render R;
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
|
||||
static int point_data_used(PointDensity *pd)
|
||||
{
|
||||
int pd_bitflag = 0;
|
||||
|
||||
if ((pd->noise_influence == TEX_PD_NOISE_VEL) || (pd->color_source == TEX_PD_COLOR_PARTVEL) || (pd->color_source == TEX_PD_COLOR_PARTSPEED))
|
||||
pd_bitflag |= POINT_DATA_VEL;
|
||||
if ((pd->noise_influence == TEX_PD_NOISE_AGE) || (pd->color_source == TEX_PD_COLOR_PARTAGE))
|
||||
pd_bitflag |= POINT_DATA_LIFE;
|
||||
|
||||
return pd_bitflag;
|
||||
}
|
||||
|
||||
|
||||
/* additional data stored alongside the point density BVH,
|
||||
* accessible by point index number to retrieve other information
|
||||
* such as particle velocity or lifetime */
|
||||
static void alloc_point_data(PointDensity *pd, int total_particles, int point_data_used)
|
||||
{
|
||||
int data_size = 0;
|
||||
|
||||
if (point_data_used & POINT_DATA_VEL) {
|
||||
/* store 3 channels of velocity data */
|
||||
data_size += 3;
|
||||
}
|
||||
if (point_data_used & POINT_DATA_LIFE) {
|
||||
/* store 1 channel of lifetime data */
|
||||
data_size += 1;
|
||||
}
|
||||
|
||||
if (data_size)
|
||||
pd->point_data = MEM_mallocN(sizeof(float)*data_size*total_particles, "particle point data");
|
||||
}
|
||||
|
||||
static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, ParticleSystem *psys)
|
||||
{
|
||||
DerivedMesh* dm;
|
||||
ParticleKey state;
|
||||
ParticleData *pa=NULL;
|
||||
float cfra = bsystem_time(re->scene, ob, (float)re->scene->r.cfra, 0.0);
|
||||
int i, childexists;
|
||||
int total_particles, offset=0;
|
||||
int data_used = point_data_used(pd);
|
||||
float partco[3];
|
||||
float obview[4][4];
|
||||
|
||||
|
||||
/* init everything */
|
||||
if (!psys || !ob || !pd) return;
|
||||
|
||||
Mat4MulMat4(obview, re->viewinv, ob->obmat);
|
||||
|
||||
/* Just to create a valid rendering context for particles */
|
||||
psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, 0);
|
||||
|
||||
dm = mesh_create_derived_render(re->scene, ob,CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL);
|
||||
|
||||
if ( !psys_check_enabled(ob, psys)) {
|
||||
psys_render_restore(ob, psys);
|
||||
return;
|
||||
}
|
||||
|
||||
/* in case ob->imat isn't up-to-date */
|
||||
Mat4Invert(ob->imat, ob->obmat);
|
||||
|
||||
total_particles = psys->totpart+psys->totchild;
|
||||
psys->lattice=psys_get_lattice(re->scene,ob,psys);
|
||||
|
||||
pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6);
|
||||
alloc_point_data(pd, total_particles, data_used);
|
||||
pd->totpoints = total_particles;
|
||||
if (data_used & POINT_DATA_VEL) offset = pd->totpoints*3;
|
||||
|
||||
if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT))
|
||||
childexists = 1;
|
||||
|
||||
for (i=0, pa=psys->particles; i < total_particles; i++, pa++) {
|
||||
|
||||
state.time = cfra;
|
||||
if(psys_get_particle_state(re->scene, ob, psys, i, &state, 0)) {
|
||||
|
||||
VECCOPY(partco, state.co);
|
||||
|
||||
if (pd->psys_cache_space == TEX_PD_OBJECTSPACE)
|
||||
Mat4MulVecfl(ob->imat, partco);
|
||||
else if (pd->psys_cache_space == TEX_PD_OBJECTLOC) {
|
||||
float obloc[3];
|
||||
VECCOPY(obloc, ob->loc);
|
||||
VecSubf(partco, partco, obloc);
|
||||
} else {
|
||||
/* TEX_PD_WORLDSPACE */
|
||||
}
|
||||
|
||||
BLI_bvhtree_insert(pd->point_tree, i, partco, 1);
|
||||
|
||||
if (data_used & POINT_DATA_VEL) {
|
||||
pd->point_data[i*3 + 0] = state.vel[0];
|
||||
pd->point_data[i*3 + 1] = state.vel[1];
|
||||
pd->point_data[i*3 + 2] = state.vel[2];
|
||||
}
|
||||
if (data_used & POINT_DATA_LIFE) {
|
||||
float pa_time;
|
||||
|
||||
if (i < psys->totpart) {
|
||||
pa_time = (cfra - pa->time)/pa->lifetime;
|
||||
} else {
|
||||
ChildParticle *cpa= (psys->child + i) - psys->totpart;
|
||||
float pa_birthtime, pa_dietime;
|
||||
|
||||
pa_time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime);
|
||||
}
|
||||
|
||||
pd->point_data[offset + i] = pa_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_bvhtree_balance(pd->point_tree);
|
||||
dm->release(dm);
|
||||
|
||||
if(psys->lattice){
|
||||
end_latt_deform(psys->lattice);
|
||||
psys->lattice=0;
|
||||
}
|
||||
|
||||
psys_render_restore(ob, psys);
|
||||
}
|
||||
|
||||
|
||||
static void pointdensity_cache_object(Render *re, PointDensity *pd, ObjectRen *obr)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!obr || !pd) return;
|
||||
if(!obr->vertnodes) return;
|
||||
|
||||
/* in case ob->imat isn't up-to-date */
|
||||
Mat4Invert(obr->ob->imat, obr->ob->obmat);
|
||||
|
||||
pd->point_tree = BLI_bvhtree_new(obr->totvert, 0.0, 4, 6);
|
||||
pd->totpoints = obr->totvert;
|
||||
|
||||
for(i=0; i<obr->totvert; i++) {
|
||||
float ver_co[3];
|
||||
VertRen *ver= RE_findOrAddVert(obr, i);
|
||||
|
||||
VECCOPY(ver_co, ver->co);
|
||||
Mat4MulVecfl(re->viewinv, ver_co);
|
||||
|
||||
if (pd->ob_cache_space == TEX_PD_OBJECTSPACE) {
|
||||
Mat4MulVecfl(obr->ob->imat, ver_co);
|
||||
} else if (pd->psys_cache_space == TEX_PD_OBJECTLOC) {
|
||||
VecSubf(ver_co, ver_co, obr->ob->loc);
|
||||
} else {
|
||||
/* TEX_PD_WORLDSPACE */
|
||||
}
|
||||
|
||||
BLI_bvhtree_insert(pd->point_tree, i, ver_co, 1);
|
||||
}
|
||||
|
||||
BLI_bvhtree_balance(pd->point_tree);
|
||||
|
||||
}
|
||||
static void cache_pointdensity(Render *re, Tex *tex)
|
||||
{
|
||||
PointDensity *pd = tex->pd;
|
||||
|
||||
if (pd->point_tree) {
|
||||
BLI_bvhtree_free(pd->point_tree);
|
||||
pd->point_tree = NULL;
|
||||
}
|
||||
|
||||
if (pd->source == TEX_PD_PSYS) {
|
||||
Object *ob = pd->object;
|
||||
|
||||
if (!ob) return;
|
||||
if (!pd->psys) return;
|
||||
|
||||
pointdensity_cache_psys(re, pd, ob, pd->psys);
|
||||
}
|
||||
else if (pd->source == TEX_PD_OBJECT) {
|
||||
Object *ob = pd->object;
|
||||
ObjectRen *obr;
|
||||
int found=0;
|
||||
|
||||
/* find the obren that corresponds to the object */
|
||||
for (obr=re->objecttable.first; obr; obr=obr->next) {
|
||||
if (obr->ob == ob) {
|
||||
found=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) return;
|
||||
|
||||
pointdensity_cache_object(re, pd, obr);
|
||||
}
|
||||
}
|
||||
|
||||
static void free_pointdensity(Render *re, Tex *tex)
|
||||
{
|
||||
PointDensity *pd = tex->pd;
|
||||
|
||||
if (!pd) return;
|
||||
|
||||
if (pd->point_tree) {
|
||||
BLI_bvhtree_free(pd->point_tree);
|
||||
pd->point_tree = NULL;
|
||||
}
|
||||
|
||||
if (pd->point_data) {
|
||||
MEM_freeN(pd->point_data);
|
||||
pd->point_data = NULL;
|
||||
}
|
||||
pd->totpoints = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void make_pointdensities(Render *re)
|
||||
{
|
||||
Tex *tex;
|
||||
|
||||
if(re->scene->r.scemode & R_PREVIEWBUTS)
|
||||
return;
|
||||
|
||||
re->i.infostr= "Caching Point Densities";
|
||||
re->stats_draw(re->sdh, &re->i);
|
||||
|
||||
for (tex= G.main->tex.first; tex; tex= tex->id.next) {
|
||||
if(tex->id.us && tex->type==TEX_POINTDENSITY) {
|
||||
cache_pointdensity(re, tex);
|
||||
}
|
||||
}
|
||||
|
||||
re->i.infostr= NULL;
|
||||
re->stats_draw(re->sdh, &re->i);
|
||||
}
|
||||
|
||||
void free_pointdensities(Render *re)
|
||||
{
|
||||
Tex *tex;
|
||||
|
||||
if(re->scene->r.scemode & R_PREVIEWBUTS)
|
||||
return;
|
||||
|
||||
for (tex= G.main->tex.first; tex; tex= tex->id.next) {
|
||||
if(tex->id.us && tex->type==TEX_POINTDENSITY) {
|
||||
free_pointdensity(re, tex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct PointDensityRangeData
|
||||
{
|
||||
float *density;
|
||||
float squared_radius;
|
||||
float *point_data;
|
||||
float *vec;
|
||||
float softness;
|
||||
short falloff_type;
|
||||
short noise_influence;
|
||||
float *age;
|
||||
int point_data_used;
|
||||
int offset;
|
||||
} PointDensityRangeData;
|
||||
|
||||
void accum_density(void *userdata, int index, float squared_dist)
|
||||
{
|
||||
PointDensityRangeData *pdr = (PointDensityRangeData *)userdata;
|
||||
const float dist = (pdr->squared_radius - squared_dist) / pdr->squared_radius * 0.5f;
|
||||
float density;
|
||||
|
||||
if (pdr->falloff_type == TEX_PD_FALLOFF_STD)
|
||||
density = dist;
|
||||
else if (pdr->falloff_type == TEX_PD_FALLOFF_SMOOTH)
|
||||
density = 3.0f*dist*dist - 2.0f*dist*dist*dist;
|
||||
else if (pdr->falloff_type == TEX_PD_FALLOFF_SOFT)
|
||||
density = pow(dist, pdr->softness);
|
||||
else if (pdr->falloff_type == TEX_PD_FALLOFF_CONSTANT)
|
||||
density = pdr->squared_radius;
|
||||
else if (pdr->falloff_type == TEX_PD_FALLOFF_ROOT)
|
||||
density = sqrt(dist);
|
||||
|
||||
if (pdr->point_data_used & POINT_DATA_VEL) {
|
||||
pdr->vec[0] += pdr->point_data[index*3 + 0]; //* density;
|
||||
pdr->vec[1] += pdr->point_data[index*3 + 1]; //* density;
|
||||
pdr->vec[2] += pdr->point_data[index*3 + 2]; //* density;
|
||||
}
|
||||
if (pdr->point_data_used & POINT_DATA_LIFE) {
|
||||
*pdr->age += pdr->point_data[pdr->offset + index]; // * density;
|
||||
}
|
||||
|
||||
*pdr->density += density;
|
||||
}
|
||||
|
||||
|
||||
static void init_pointdensityrangedata(PointDensity *pd, PointDensityRangeData *pdr, float *density, float *vec, float *age)
|
||||
{
|
||||
pdr->squared_radius = pd->radius*pd->radius;
|
||||
pdr->density = density;
|
||||
pdr->point_data = pd->point_data;
|
||||
pdr->falloff_type = pd->falloff_type;
|
||||
pdr->vec = vec;
|
||||
pdr->age = age;
|
||||
pdr->softness = pd->falloff_softness;
|
||||
pdr->noise_influence = pd->noise_influence;
|
||||
pdr->point_data_used = point_data_used(pd);
|
||||
pdr->offset = (pdr->point_data_used & POINT_DATA_VEL)?pd->totpoints*3:0;
|
||||
}
|
||||
|
||||
|
||||
int pointdensitytex(Tex *tex, float *texvec, TexResult *texres)
|
||||
{
|
||||
int retval = TEX_INT;
|
||||
PointDensity *pd = tex->pd;
|
||||
PointDensityRangeData pdr;
|
||||
float density=0.0f, age=0.0f, time=0.0f;
|
||||
float vec[3] = {0.0f, 0.0f, 0.0f}, co[3];
|
||||
float col[4];
|
||||
float turb, noise_fac;
|
||||
int num=0;
|
||||
|
||||
texres->tin = 0.0f;
|
||||
|
||||
if ((!pd) || (!pd->point_tree))
|
||||
return 0;
|
||||
|
||||
init_pointdensityrangedata(pd, &pdr, &density, vec, &age);
|
||||
noise_fac = pd->noise_fac * 0.5f; /* better default */
|
||||
|
||||
VECCOPY(co, texvec);
|
||||
|
||||
if (point_data_used(pd)) {
|
||||
/* does a BVH lookup to find accumulated density and additional point data *
|
||||
* stores particle velocity vector in 'vec', and particle lifetime in 'time' */
|
||||
num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr);
|
||||
if (num > 0) {
|
||||
age /= num;
|
||||
VecMulf(vec, 1.0f/num);
|
||||
}
|
||||
|
||||
/* reset */
|
||||
density = vec[0] = vec[1] = vec[2] = 0.0f;
|
||||
}
|
||||
|
||||
if (pd->flag & TEX_PD_TURBULENCE) {
|
||||
|
||||
if (pd->noise_influence == TEX_PD_NOISE_AGE) {
|
||||
turb = BLI_gTurbulence(pd->noise_size, texvec[0]+age, texvec[1]+age, texvec[2]+age, pd->noise_depth, 0, pd->noise_basis);
|
||||
}
|
||||
else if (pd->noise_influence == TEX_PD_NOISE_TIME) {
|
||||
time = R.cfra / (float)R.r.efra;
|
||||
turb = BLI_gTurbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth, 0, pd->noise_basis);
|
||||
//turb = BLI_turbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth);
|
||||
}
|
||||
else {
|
||||
turb = BLI_gTurbulence(pd->noise_size, texvec[0]+vec[0], texvec[1]+vec[1], texvec[2]+vec[2], pd->noise_depth, 0, pd->noise_basis);
|
||||
}
|
||||
|
||||
turb -= 0.5f; /* re-center 0.0-1.0 range around 0 to prevent offsetting result */
|
||||
|
||||
/* now we have an offset coordinate to use for the density lookup */
|
||||
co[0] = texvec[0] + noise_fac * turb;
|
||||
co[1] = texvec[1] + noise_fac * turb;
|
||||
co[2] = texvec[2] + noise_fac * turb;
|
||||
}
|
||||
|
||||
/* BVH query with the potentially perturbed coordinates */
|
||||
num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr);
|
||||
if (num > 0) {
|
||||
age /= num;
|
||||
VecMulf(vec, 1.0f/num);
|
||||
}
|
||||
|
||||
texres->tin = density;
|
||||
BRICONT;
|
||||
|
||||
if (pd->color_source == TEX_PD_COLOR_CONSTANT)
|
||||
return retval;
|
||||
|
||||
retval |= TEX_RGB;
|
||||
|
||||
switch (pd->color_source) {
|
||||
case TEX_PD_COLOR_PARTAGE:
|
||||
if (pd->coba) {
|
||||
if (do_colorband(pd->coba, age, col)) {
|
||||
texres->talpha= 1;
|
||||
VECCOPY(&texres->tr, col);
|
||||
texres->tin *= col[3];
|
||||
texres->ta = texres->tin;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TEX_PD_COLOR_PARTSPEED:
|
||||
{
|
||||
float speed = VecLength(vec) * pd->speed_scale;
|
||||
|
||||
if (pd->coba) {
|
||||
if (do_colorband(pd->coba, speed, col)) {
|
||||
texres->talpha= 1;
|
||||
VECCOPY(&texres->tr, col);
|
||||
texres->tin *= col[3];
|
||||
texres->ta = texres->tin;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TEX_PD_COLOR_PARTVEL:
|
||||
texres->talpha= 1;
|
||||
VecMulf(vec, pd->speed_scale);
|
||||
VECCOPY(&texres->tr, vec);
|
||||
texres->ta = texres->tin;
|
||||
break;
|
||||
case TEX_PD_COLOR_CONSTANT:
|
||||
default:
|
||||
texres->tr = texres->tg = texres->tb = texres->ta = 1.0f;
|
||||
break;
|
||||
}
|
||||
BRICONTRGB;
|
||||
|
||||
return retval;
|
||||
|
||||
/*
|
||||
if (texres->nor!=NULL) {
|
||||
texres->nor[0] = texres->nor[1] = texres->nor[2] = 0.0f;
|
||||
}
|
||||
*/
|
||||
}
|
@ -54,6 +54,7 @@
|
||||
#include "pixelshading.h"
|
||||
#include "shading.h"
|
||||
#include "texture.h"
|
||||
#include "volumetric.h"
|
||||
|
||||
#include "RE_raytrace.h"
|
||||
|
||||
@ -95,6 +96,17 @@ static int vlr_check_intersect(Isect *is, int ob, RayFace *face)
|
||||
return (is->lay & obi->lay);
|
||||
}
|
||||
|
||||
static int vlr_check_intersect_solid(Isect *is, int ob, RayFace *face)
|
||||
{
|
||||
VlakRen *vlr = (VlakRen*)face;
|
||||
|
||||
/* solid material types only */
|
||||
if (vlr->mat->material_type == MA_TYPE_SURFACE)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static float *vlr_get_transform(void *userdata, int i)
|
||||
{
|
||||
ObjectInstanceRen *obi= RAY_OBJECT_GET((Render*)userdata, i);
|
||||
@ -205,7 +217,7 @@ void makeraytree(Render *re)
|
||||
re->stats_draw(re->sdh, &re->i);
|
||||
}
|
||||
|
||||
static void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr)
|
||||
void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr)
|
||||
{
|
||||
VlakRen *vlr= (VlakRen*)is->face;
|
||||
ObjectInstanceRen *obi= RAY_OBJECT_GET(&R, is->ob);
|
||||
@ -260,8 +272,14 @@ static void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr)
|
||||
shade_input_flip_normals(shi);
|
||||
|
||||
shade_input_set_shade_texco(shi);
|
||||
|
||||
if(is->mode==RE_RAY_SHADOW_TRA) {
|
||||
if (shi->mat->material_type == MA_TYPE_VOLUME) {
|
||||
if(ELEM(is->mode, RE_RAY_SHADOW, RE_RAY_SHADOW_TRA)) {
|
||||
shade_volume_shadow(shi, shr, is);
|
||||
} else {
|
||||
shade_volume_outside(shi, shr);
|
||||
}
|
||||
}
|
||||
else if(is->mode==RE_RAY_SHADOW_TRA) {
|
||||
/* temp hack to prevent recursion */
|
||||
if(shi->nodes==0 && shi->mat->nodetree && shi->mat->use_nodes) {
|
||||
ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
|
||||
@ -275,9 +293,20 @@ static void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr)
|
||||
ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
|
||||
shi->mat= vlr->mat; /* shi->mat is being set in nodetree */
|
||||
}
|
||||
else
|
||||
shade_material_loop(shi, shr);
|
||||
|
||||
else {
|
||||
int tempdepth;
|
||||
/* XXX dodgy business here, set ray depth to -1
|
||||
* to ignore raytrace in shade_material_loop()
|
||||
* this could really use a refactor --Matt */
|
||||
if (shi->volume_depth == 0) {
|
||||
tempdepth = shi->depth;
|
||||
shi->depth = -1;
|
||||
shade_material_loop(shi, shr);
|
||||
shi->depth = tempdepth;
|
||||
} else {
|
||||
shade_material_loop(shi, shr);
|
||||
}
|
||||
}
|
||||
/* raytrace likes to separate the spec color */
|
||||
VECSUB(shr->diff, shr->combined, shr->spec);
|
||||
}
|
||||
@ -1302,11 +1331,15 @@ static void ray_trace_shadow_tra(Isect *is, ShadeInput *origshi, int depth, int
|
||||
shi.nodes= origshi->nodes;
|
||||
|
||||
shade_ray(is, &shi, &shr);
|
||||
if (traflag & RAY_TRA)
|
||||
d= shade_by_transmission(is, &shi, &shr);
|
||||
|
||||
/* mix colors based on shadfac (rgb + amount of light factor) */
|
||||
addAlphaLight(is->col, shr.diff, shr.alpha, d*shi.mat->filter);
|
||||
if (shi.mat->material_type == MA_TYPE_SURFACE) {
|
||||
if (traflag & RAY_TRA)
|
||||
d= shade_by_transmission(is, &shi, &shr);
|
||||
|
||||
/* mix colors based on shadfac (rgb + amount of light factor) */
|
||||
addAlphaLight(is->col, shr.diff, shr.alpha, d*shi.mat->filter);
|
||||
} else if (shi.mat->material_type == MA_TYPE_VOLUME) {
|
||||
addAlphaLight(is->col, shr.combined, shr.alpha, 1.0f);
|
||||
}
|
||||
|
||||
if(depth>0 && is->col[3]>0.0f) {
|
||||
|
||||
@ -1607,7 +1640,7 @@ static void ray_ao_qmc(ShadeInput *shi, float *shadfac)
|
||||
|
||||
prev = fac;
|
||||
|
||||
if(RE_ray_tree_intersect(R.raytree, &isec)) {
|
||||
if(RE_ray_tree_intersect_check(R.raytree, &isec, vlr_check_intersect_solid)) {
|
||||
if (R.wrld.aomode & WO_AODIST) fac+= exp(-isec.labda*R.wrld.aodistfac);
|
||||
else fac+= 1.0f;
|
||||
}
|
||||
@ -1732,7 +1765,7 @@ static void ray_ao_spheresamp(ShadeInput *shi, float *shadfac)
|
||||
isec.end[2] = shi->co[2] - maxdist*vec[2];
|
||||
|
||||
/* do the trace */
|
||||
if(RE_ray_tree_intersect(R.raytree, &isec)) {
|
||||
if(RE_ray_tree_intersect_check(R.raytree, &isec, vlr_check_intersect_solid)) {
|
||||
if (R.wrld.aomode & WO_AODIST) sh+= exp(-isec.labda*R.wrld.aodistfac);
|
||||
else sh+= 1.0f;
|
||||
}
|
||||
|
@ -931,7 +931,7 @@ int RE_ray_face_intersection(Isect *is, RayObjectTransformFunc transformfunc, Ra
|
||||
intersection to be detected in its neighbour face */
|
||||
|
||||
if(is->facecontr && is->faceisect); // optimizing, the tests below are not needed
|
||||
else if(is->labda< .1) {
|
||||
else if(is->labda< .1 && is->faceorig) {
|
||||
RayFace *face= is->faceorig;
|
||||
float *origv1, *origv2, *origv3, *origv4;
|
||||
short de= 0;
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "shading.h"
|
||||
#include "strand.h"
|
||||
#include "texture.h"
|
||||
#include "volumetric.h"
|
||||
#include "zbuf.h"
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
@ -166,6 +167,11 @@ void shade_material_loop(ShadeInput *shi, ShadeResult *shr)
|
||||
if((shi->layflag & SCE_LAY_SKY) && (R.r.alphamode==R_ADDSKY))
|
||||
shr->alpha= 1.0f;
|
||||
}
|
||||
|
||||
if(R.r.mode & R_RAYTRACE) {
|
||||
if (R.render_volumes_inside.first)
|
||||
shade_volume_inside(shi, shr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -183,7 +189,12 @@ void shade_input_do_shade(ShadeInput *shi, ShadeResult *shr)
|
||||
/* copy all relevant material vars, note, keep this synced with render_types.h */
|
||||
shade_input_init_material(shi);
|
||||
|
||||
shade_material_loop(shi, shr);
|
||||
if (shi->mat->material_type == MA_TYPE_VOLUME) {
|
||||
if(R.r.mode & R_RAYTRACE)
|
||||
shade_volume_outside(shi, shr);
|
||||
} else { /* MA_TYPE_SURFACE, MA_TYPE_WIRE */
|
||||
shade_material_loop(shi, shr);
|
||||
}
|
||||
}
|
||||
|
||||
/* copy additional passes */
|
||||
@ -210,11 +221,12 @@ void shade_input_do_shade(ShadeInput *shi, ShadeResult *shr)
|
||||
if(shr->alpha!=1.0f || alpha!=1.0f) {
|
||||
float fac= alpha*(shr->alpha);
|
||||
shr->combined[3]= fac;
|
||||
shr->combined[0]*= fac;
|
||||
shr->combined[1]*= fac;
|
||||
shr->combined[2]*= fac;
|
||||
|
||||
if (shi->mat->material_type!= MA_TYPE_VOLUME)
|
||||
VecMulf(shr->combined, fac);
|
||||
}
|
||||
else shr->combined[3]= 1.0f;
|
||||
else
|
||||
shr->combined[3]= 1.0f;
|
||||
|
||||
/* add z */
|
||||
shr->z= -shi->co[2];
|
||||
@ -698,6 +710,10 @@ void shade_input_calc_viewco(ShadeInput *shi, float x, float y, float z, float *
|
||||
}
|
||||
}
|
||||
|
||||
/* set camera coords - for scanline, it's always 0.0,0.0,0.0 (render is in camera space)
|
||||
* however for raytrace it can be different - the position of the last intersection */
|
||||
shi->camera_co[0] = shi->camera_co[1] = shi->camera_co[2] = 0.0f;
|
||||
|
||||
/* cannot normalize earlier, code above needs it at viewplane level */
|
||||
Normalize(view);
|
||||
}
|
||||
|
@ -58,7 +58,7 @@
|
||||
extern struct Render R;
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
static ListBase *get_lights(ShadeInput *shi)
|
||||
ListBase *get_lights(ShadeInput *shi)
|
||||
{
|
||||
|
||||
if(R.r.scemode & R_PREVIEWBUTS)
|
||||
|
@ -65,6 +65,8 @@
|
||||
#include "BKE_ipo.h"
|
||||
|
||||
#include "envmap.h"
|
||||
#include "pointdensity.h"
|
||||
#include "voxeldata.h"
|
||||
#include "renderpipeline.h"
|
||||
#include "render_types.h"
|
||||
#include "rendercore.h"
|
||||
@ -1262,6 +1264,13 @@ static int multitex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex,
|
||||
|
||||
retval= mg_distNoiseTex(tex, tmpvec, texres);
|
||||
break;
|
||||
case TEX_POINTDENSITY:
|
||||
retval= pointdensitytex(tex, texvec, texres);
|
||||
break;
|
||||
case TEX_VOXELDATA:
|
||||
retval= voxeldatatex(tex, texvec, texres);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (tex->flag & TEX_COLORBAND) {
|
||||
@ -1272,7 +1281,7 @@ static int multitex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex,
|
||||
texres->tg= col[1];
|
||||
texres->tb= col[2];
|
||||
texres->ta= col[3];
|
||||
retval |= 1;
|
||||
retval |= TEX_RGB;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
@ -2248,6 +2257,187 @@ void do_material_tex(ShadeInput *shi)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void do_volume_tex(ShadeInput *shi, float *xyz, int mapto_flag, float *col, float *val)
|
||||
{
|
||||
MTex *mtex;
|
||||
Tex *tex;
|
||||
TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
|
||||
int tex_nr, rgbnor= 0;
|
||||
float co[3], texvec[3];
|
||||
float fact, stencilTin=1.0;
|
||||
|
||||
if (R.r.scemode & R_NO_TEX) return;
|
||||
/* here: test flag if there's a tex (todo) */
|
||||
|
||||
for(tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
|
||||
/* separate tex switching */
|
||||
if(shi->mat->septex & (1<<tex_nr)) continue;
|
||||
|
||||
if(shi->mat->mtex[tex_nr]) {
|
||||
mtex= shi->mat->mtex[tex_nr];
|
||||
tex= mtex->tex;
|
||||
if(tex==0) continue;
|
||||
|
||||
/* only process if this texture is mapped
|
||||
* to one that we're interested in */
|
||||
if (!(mtex->mapto & mapto_flag)) continue;
|
||||
|
||||
/* which coords */
|
||||
if(mtex->texco==TEXCO_OBJECT) {
|
||||
Object *ob= mtex->object;
|
||||
ob= mtex->object;
|
||||
if(ob) {
|
||||
VECCOPY(co, xyz);
|
||||
if(mtex->texflag & MTEX_OB_DUPLI_ORIG) {
|
||||
if(shi->obi && shi->obi->duplitexmat)
|
||||
MTC_Mat4MulVecfl(shi->obi->duplitexmat, co);
|
||||
}
|
||||
MTC_Mat4MulVecfl(ob->imat, co);
|
||||
}
|
||||
}
|
||||
/* not really orco, but 'local' */
|
||||
else if(mtex->texco==TEXCO_ORCO) {
|
||||
|
||||
if(mtex->texflag & MTEX_DUPLI_MAPTO) {
|
||||
VECCOPY(co, shi->duplilo);
|
||||
}
|
||||
else {
|
||||
Object *ob= shi->obi->ob;
|
||||
VECCOPY(co, xyz);
|
||||
MTC_Mat4MulVecfl(ob->imat, co);
|
||||
}
|
||||
}
|
||||
else if(mtex->texco==TEXCO_GLOB) {
|
||||
VECCOPY(co, xyz);
|
||||
MTC_Mat4MulVecfl(R.viewinv, co);
|
||||
}
|
||||
else continue; // can happen when texco defines disappear and it renders old files
|
||||
|
||||
texres.nor= NULL;
|
||||
|
||||
if(tex->type==TEX_IMAGE) {
|
||||
continue; /* not supported yet */
|
||||
//do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
|
||||
}
|
||||
else {
|
||||
/* placement */
|
||||
if(mtex->projx) texvec[0]= mtex->size[0]*(co[mtex->projx-1]+mtex->ofs[0]);
|
||||
else texvec[0]= mtex->size[0]*(mtex->ofs[0]);
|
||||
|
||||
if(mtex->projy) texvec[1]= mtex->size[1]*(co[mtex->projy-1]+mtex->ofs[1]);
|
||||
else texvec[1]= mtex->size[1]*(mtex->ofs[1]);
|
||||
|
||||
if(mtex->projz) texvec[2]= mtex->size[2]*(co[mtex->projz-1]+mtex->ofs[2]);
|
||||
else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
|
||||
}
|
||||
|
||||
rgbnor= multitex(tex, texvec, NULL, NULL, 0, &texres, 0, mtex->which_output); /* NULL = dxt/dyt, 0 = shi->osatex - not supported */
|
||||
|
||||
/* texture output */
|
||||
|
||||
if( (rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) {
|
||||
texres.tin= (0.35*texres.tr+0.45*texres.tg+0.2*texres.tb);
|
||||
rgbnor-= TEX_RGB;
|
||||
}
|
||||
if(mtex->texflag & MTEX_NEGATIVE) {
|
||||
if(rgbnor & TEX_RGB) {
|
||||
texres.tr= 1.0-texres.tr;
|
||||
texres.tg= 1.0-texres.tg;
|
||||
texres.tb= 1.0-texres.tb;
|
||||
}
|
||||
texres.tin= 1.0-texres.tin;
|
||||
}
|
||||
if(mtex->texflag & MTEX_STENCIL) {
|
||||
if(rgbnor & TEX_RGB) {
|
||||
fact= texres.ta;
|
||||
texres.ta*= stencilTin;
|
||||
stencilTin*= fact;
|
||||
}
|
||||
else {
|
||||
fact= texres.tin;
|
||||
texres.tin*= stencilTin;
|
||||
stencilTin*= fact;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if((mapto_flag & (MAP_EMISSION_COL+MAP_ABSORPTION_COL)) && (mtex->mapto & (MAP_EMISSION_COL+MAP_ABSORPTION_COL))) {
|
||||
float tcol[3], colfac;
|
||||
|
||||
/* stencil maps on the texture control slider, not texture intensity value */
|
||||
colfac= mtex->colfac*stencilTin;
|
||||
|
||||
if((rgbnor & TEX_RGB)==0) {
|
||||
tcol[0]= mtex->r;
|
||||
tcol[1]= mtex->g;
|
||||
tcol[2]= mtex->b;
|
||||
} else {
|
||||
tcol[0]=texres.tr;
|
||||
tcol[1]=texres.tg;
|
||||
tcol[2]=texres.tb;
|
||||
if(texres.talpha)
|
||||
texres.tin= texres.ta;
|
||||
}
|
||||
|
||||
/* inverse gamma correction */
|
||||
if (R.r.color_mgt_flag & R_COLOR_MANAGEMENT) {
|
||||
color_manage_linearize(tcol, tcol);
|
||||
}
|
||||
|
||||
/* used for emit */
|
||||
if((mapto_flag & MAP_EMISSION_COL) && (mtex->mapto & MAP_EMISSION_COL)) {
|
||||
texture_rgb_blend(col, tcol, col, texres.tin, colfac, mtex->blendtype);
|
||||
}
|
||||
|
||||
/* MAP_COLMIR is abused for absorption colour at the moment */
|
||||
if((mapto_flag & MAP_ABSORPTION_COL) && (mtex->mapto & MAP_ABSORPTION_COL)) {
|
||||
texture_rgb_blend(col, tcol, col, texres.tin, colfac, mtex->blendtype);
|
||||
}
|
||||
}
|
||||
|
||||
if((mapto_flag & MAP_VARS) && (mtex->mapto & MAP_VARS)) {
|
||||
/* stencil maps on the texture control slider, not texture intensity value */
|
||||
float varfac= mtex->varfac*stencilTin;
|
||||
|
||||
/* convert RGB to intensity if intensity info isn't provided */
|
||||
if (!(rgbnor & TEX_INT)) {
|
||||
if (rgbnor & TEX_RGB) {
|
||||
if(texres.talpha) texres.tin= texres.ta;
|
||||
else texres.tin= (0.35*texres.tr+0.45*texres.tg+0.2*texres.tb);
|
||||
}
|
||||
}
|
||||
|
||||
if((mapto_flag & MAP_EMISSION) && (mtex->mapto & MAP_EMISSION)) {
|
||||
int flip= mtex->maptoneg & MAP_EMISSION;
|
||||
|
||||
*val = texture_value_blend(mtex->def_var, *val, texres.tin, varfac, mtex->blendtype, flip);
|
||||
if(*val<0.0) *val= 0.0;
|
||||
}
|
||||
if((mapto_flag & MAP_DENSITY) && (mtex->mapto & MAP_DENSITY)) {
|
||||
int flip= mtex->maptoneg & MAP_DENSITY;
|
||||
|
||||
*val = texture_value_blend(mtex->def_var, *val, texres.tin, varfac, mtex->blendtype, flip);
|
||||
CLAMP(*val, 0.0, 1.0);
|
||||
}
|
||||
if((mapto_flag & MAP_ABSORPTION) && (mtex->mapto & MAP_ABSORPTION)) {
|
||||
int flip= mtex->maptoneg & MAP_ABSORPTION;
|
||||
|
||||
*val = texture_value_blend(mtex->def_var, *val, texres.tin, varfac, mtex->blendtype, flip);
|
||||
CLAMP(*val, 0.0, 1.0);
|
||||
}
|
||||
if((mapto_flag & MAP_SCATTERING) && (mtex->mapto & MAP_SCATTERING)) {
|
||||
int flip= mtex->maptoneg & MAP_SCATTERING;
|
||||
|
||||
*val = texture_value_blend(mtex->def_var, *val, texres.tin, varfac, mtex->blendtype, flip);
|
||||
CLAMP(*val, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void do_halo_tex(HaloRen *har, float xn, float yn, float *colf)
|
||||
|
736
source/blender/render/intern/source/volume_precache.c
Normal file
736
source/blender/render/intern/source/volume_precache.c
Normal file
@ -0,0 +1,736 @@
|
||||
/**
|
||||
*
|
||||
* ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Matt Ebb.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <float.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_arithb.h"
|
||||
#include "BLI_threads.h"
|
||||
#include "BLI_voxel.h"
|
||||
|
||||
#include "PIL_time.h"
|
||||
|
||||
#include "RE_shader_ext.h"
|
||||
#include "RE_raytrace.h"
|
||||
|
||||
#include "DNA_material_types.h"
|
||||
|
||||
#include "render_types.h"
|
||||
#include "renderdatabase.h"
|
||||
#include "volumetric.h"
|
||||
#include "volume_precache.h"
|
||||
|
||||
#if defined( _MSC_VER ) && !defined( __cplusplus )
|
||||
# define inline __inline
|
||||
#endif // defined( _MSC_VER ) && !defined( __cplusplus )
|
||||
|
||||
#include "BKE_global.h"
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
|
||||
/* only to be used here in this file, it's for speed */
|
||||
extern struct Render R;
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
/* *** utility code to set up an individual raytree for objectinstance, for checking inside/outside *** */
|
||||
|
||||
/* Recursive test for intersections, from a point inside the mesh, to outside
|
||||
* Number of intersections (depth) determine if a point is inside or outside the mesh */
|
||||
int intersect_outside_volume(RayTree *tree, Isect *isect, float *offset, int limit, int depth)
|
||||
{
|
||||
if (limit == 0) return depth;
|
||||
|
||||
if (RE_ray_tree_intersect(tree, isect)) {
|
||||
float hitco[3];
|
||||
|
||||
hitco[0] = isect->start[0] + isect->labda*isect->vec[0];
|
||||
hitco[1] = isect->start[1] + isect->labda*isect->vec[1];
|
||||
hitco[2] = isect->start[2] + isect->labda*isect->vec[2];
|
||||
VecAddf(isect->start, hitco, offset);
|
||||
|
||||
return intersect_outside_volume(tree, isect, offset, limit-1, depth+1);
|
||||
} else {
|
||||
return depth;
|
||||
}
|
||||
}
|
||||
|
||||
/* Uses ray tracing to check if a point is inside or outside an ObjectInstanceRen */
|
||||
int point_inside_obi(RayTree *tree, ObjectInstanceRen *obi, float *co)
|
||||
{
|
||||
float maxsize = RE_ray_tree_max_size(tree);
|
||||
Isect isect;
|
||||
float vec[3] = {0.0f,0.0f,1.0f};
|
||||
int final_depth=0, depth=0, limit=20;
|
||||
|
||||
/* set up the isect */
|
||||
memset(&isect, 0, sizeof(isect));
|
||||
VECCOPY(isect.start, co);
|
||||
isect.end[0] = co[0] + vec[0] * maxsize;
|
||||
isect.end[1] = co[1] + vec[1] * maxsize;
|
||||
isect.end[2] = co[2] + vec[2] * maxsize;
|
||||
|
||||
/* and give it a little offset to prevent self-intersections */
|
||||
VecMulf(vec, 1e-5);
|
||||
VecAddf(isect.start, isect.start, vec);
|
||||
|
||||
isect.mode= RE_RAY_MIRROR;
|
||||
isect.face_last= NULL;
|
||||
isect.lay= -1;
|
||||
|
||||
final_depth = intersect_outside_volume(tree, &isect, vec, limit, depth);
|
||||
|
||||
/* even number of intersections: point is outside
|
||||
* odd number: point is inside */
|
||||
if (final_depth % 2 == 0) return 0;
|
||||
else return 1;
|
||||
}
|
||||
|
||||
static int inside_check_func(Isect *is, int ob, RayFace *face)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
static void vlr_face_coords(RayFace *face, float **v1, float **v2, float **v3, float **v4)
|
||||
{
|
||||
VlakRen *vlr= (VlakRen*)face;
|
||||
|
||||
*v1 = (vlr->v1)? vlr->v1->co: NULL;
|
||||
*v2 = (vlr->v2)? vlr->v2->co: NULL;
|
||||
*v3 = (vlr->v3)? vlr->v3->co: NULL;
|
||||
*v4 = (vlr->v4)? vlr->v4->co: NULL;
|
||||
}
|
||||
|
||||
RayTree *create_raytree_obi(ObjectInstanceRen *obi, float *bbmin, float *bbmax)
|
||||
{
|
||||
int v;
|
||||
VlakRen *vlr= NULL;
|
||||
|
||||
/* create empty raytree */
|
||||
RayTree *tree = RE_ray_tree_create(64, obi->obr->totvlak, bbmin, bbmax,
|
||||
vlr_face_coords, inside_check_func, NULL, NULL);
|
||||
|
||||
/* fill it with faces */
|
||||
for(v=0; v<obi->obr->totvlak; v++) {
|
||||
if((v & 255)==0)
|
||||
vlr= obi->obr->vlaknodes[v>>8].vlak;
|
||||
else
|
||||
vlr++;
|
||||
|
||||
RE_ray_tree_add_face(tree, 0, vlr);
|
||||
}
|
||||
|
||||
RE_ray_tree_done(tree);
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
/* *** light cache filtering *** */
|
||||
|
||||
static float get_avg_surrounds(float *cache, int *res, int xx, int yy, int zz)
|
||||
{
|
||||
int x, y, z, x_, y_, z_;
|
||||
int added=0;
|
||||
float tot=0.0f;
|
||||
|
||||
for (z=-1; z <= 1; z++) {
|
||||
z_ = zz+z;
|
||||
if (z_ >= 0 && z_ <= res[2]-1) {
|
||||
|
||||
for (y=-1; y <= 1; y++) {
|
||||
y_ = yy+y;
|
||||
if (y_ >= 0 && y_ <= res[1]-1) {
|
||||
|
||||
for (x=-1; x <= 1; x++) {
|
||||
x_ = xx+x;
|
||||
if (x_ >= 0 && x_ <= res[0]-1) {
|
||||
|
||||
if (cache[ V_I(x_, y_, z_, res) ] > 0.0f) {
|
||||
tot += cache[ V_I(x_, y_, z_, res) ];
|
||||
added++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tot /= added;
|
||||
|
||||
return ((added>0)?tot:0.0f);
|
||||
}
|
||||
|
||||
/* function to filter the edges of the light cache, where there was no volume originally.
|
||||
* For each voxel which was originally external to the mesh, it finds the average values of
|
||||
* the surrounding internal voxels and sets the original external voxel to that average amount.
|
||||
* Works almost a bit like a 'dilate' filter */
|
||||
static void lightcache_filter(VolumePrecache *vp)
|
||||
{
|
||||
int x, y, z;
|
||||
|
||||
for (z=0; z < vp->res[2]; z++) {
|
||||
for (y=0; y < vp->res[1]; y++) {
|
||||
for (x=0; x < vp->res[0]; x++) {
|
||||
/* trigger for outside mesh */
|
||||
if (vp->data_r[ V_I(x, y, z, vp->res) ] < -0.5f)
|
||||
vp->data_r[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_r, vp->res, x, y, z);
|
||||
if (vp->data_g[ V_I(x, y, z, vp->res) ] < -0.5f)
|
||||
vp->data_g[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_g, vp->res, x, y, z);
|
||||
if (vp->data_b[ V_I(x, y, z, vp->res) ] < -0.5f)
|
||||
vp->data_b[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_b, vp->res, x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline int ms_I(int x, int y, int z, int *n) //has a pad of 1 voxel surrounding the core for boundary simulation
|
||||
{
|
||||
return z*(n[1]+2)*(n[0]+2) + y*(n[0]+2) + x;
|
||||
}
|
||||
|
||||
|
||||
/* *** multiple scattering approximation *** */
|
||||
|
||||
/* get the total amount of light energy in the light cache. used to normalise after multiple scattering */
|
||||
static float total_ss_energy(VolumePrecache *vp)
|
||||
{
|
||||
int x, y, z;
|
||||
int *res = vp->res;
|
||||
float energy=0.f;
|
||||
|
||||
for (z=0; z < res[2]; z++) {
|
||||
for (y=0; y < res[1]; y++) {
|
||||
for (x=0; x < res[0]; x++) {
|
||||
if (vp->data_r[ V_I(x, y, z, res) ] > 0.f) energy += vp->data_r[ V_I(x, y, z, res) ];
|
||||
if (vp->data_g[ V_I(x, y, z, res) ] > 0.f) energy += vp->data_g[ V_I(x, y, z, res) ];
|
||||
if (vp->data_b[ V_I(x, y, z, res) ] > 0.f) energy += vp->data_b[ V_I(x, y, z, res) ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return energy;
|
||||
}
|
||||
|
||||
static float total_ms_energy(float *sr, float *sg, float *sb, int *res)
|
||||
{
|
||||
int x, y, z, i;
|
||||
float energy=0.f;
|
||||
|
||||
for (z=1;z<=res[2];z++) {
|
||||
for (y=1;y<=res[1];y++) {
|
||||
for (x=1;x<=res[0];x++) {
|
||||
|
||||
i = ms_I(x,y,z,res);
|
||||
if (sr[i] > 0.f) energy += sr[i];
|
||||
if (sg[i] > 0.f) energy += sg[i];
|
||||
if (sb[i] > 0.f) energy += sb[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return energy;
|
||||
}
|
||||
|
||||
static void ms_diffuse(int b, float* x0, float* x, float diff, int *n)
|
||||
{
|
||||
int i, j, k, l;
|
||||
const float dt = VOL_MS_TIMESTEP;
|
||||
const float a = dt*diff*n[0]*n[1]*n[2];
|
||||
|
||||
for (l=0; l<20; l++)
|
||||
{
|
||||
for (k=1; k<=n[2]; k++)
|
||||
{
|
||||
for (j=1; j<=n[1]; j++)
|
||||
{
|
||||
for (i=1; i<=n[0]; i++)
|
||||
{
|
||||
x[ms_I(i,j,k,n)] = (x0[ms_I(i,j,k,n)] + a*(
|
||||
x[ms_I(i-1,j,k,n)]+x[ms_I(i+1,j,k,n)]+
|
||||
x[ms_I(i,j-1,k,n)]+x[ms_I(i,j+1,k,n)]+
|
||||
x[ms_I(i,j,k-1,n)]+x[ms_I(i,j,k+1,n)]))/(1+6*a);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void multiple_scattering_diffusion(Render *re, VolumePrecache *vp, Material *ma)
|
||||
{
|
||||
const float diff = ma->vol.ms_diff * 0.001f; /* compensate for scaling for a nicer UI range */
|
||||
const float simframes = ma->vol.ms_steps;
|
||||
const int shade_type = ma->vol.shade_type;
|
||||
float fac = ma->vol.ms_intensity;
|
||||
|
||||
int x, y, z, m;
|
||||
int *n = vp->res;
|
||||
const int size = (n[0]+2)*(n[1]+2)*(n[2]+2);
|
||||
double time, lasttime= PIL_check_seconds_timer();
|
||||
float total;
|
||||
float c=1.0f;
|
||||
int i;
|
||||
float origf; /* factor for blending in original light cache */
|
||||
float energy_ss, energy_ms;
|
||||
|
||||
float *sr0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
|
||||
float *sr=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
|
||||
float *sg0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
|
||||
float *sg=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
|
||||
float *sb0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
|
||||
float *sb=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
|
||||
|
||||
total = (float)(n[0]*n[1]*n[2]*simframes);
|
||||
|
||||
energy_ss = total_ss_energy(vp);
|
||||
|
||||
/* Scattering as diffusion pass */
|
||||
for (m=0; m<simframes; m++)
|
||||
{
|
||||
/* add sources */
|
||||
for (z=1; z<=n[2]; z++)
|
||||
{
|
||||
for (y=1; y<=n[1]; y++)
|
||||
{
|
||||
for (x=1; x<=n[0]; x++)
|
||||
{
|
||||
i = V_I((x-1), (y-1), (z-1), n);
|
||||
time= PIL_check_seconds_timer();
|
||||
c++;
|
||||
|
||||
if (vp->data_r[i] > 0.f)
|
||||
sr[ms_I(x,y,z,n)] += vp->data_r[i];
|
||||
if (vp->data_g[i] > 0.f)
|
||||
sg[ms_I(x,y,z,n)] += vp->data_g[i];
|
||||
if (vp->data_b[i] > 0.f)
|
||||
sb[ms_I(x,y,z,n)] += vp->data_b[i];
|
||||
|
||||
/* Displays progress every second */
|
||||
if(time-lasttime>1.0f) {
|
||||
char str[64];
|
||||
sprintf(str, "Simulating multiple scattering: %d%%", (int)
|
||||
(100.0f * (c / total)));
|
||||
re->i.infostr= str;
|
||||
re->stats_draw(re->sdh, &re->i);
|
||||
re->i.infostr= NULL;
|
||||
lasttime= time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SWAP(float *, sr, sr0);
|
||||
SWAP(float *, sg, sg0);
|
||||
SWAP(float *, sb, sb0);
|
||||
|
||||
/* main diffusion simulation */
|
||||
ms_diffuse(0, sr0, sr, diff, n);
|
||||
ms_diffuse(0, sg0, sg, diff, n);
|
||||
ms_diffuse(0, sb0, sb, diff, n);
|
||||
|
||||
if (re->test_break(re->tbh)) break;
|
||||
}
|
||||
|
||||
/* normalisation factor to conserve energy */
|
||||
energy_ms = total_ms_energy(sr, sg, sb, n);
|
||||
fac *= (energy_ss / energy_ms);
|
||||
|
||||
/* blend multiple scattering back in the light cache */
|
||||
if (shade_type == MA_VOL_SHADE_SINGLEPLUSMULTIPLE) {
|
||||
/* conserve energy - half single, half multiple */
|
||||
origf = 0.5f;
|
||||
fac *= 0.5f;
|
||||
} else {
|
||||
origf = 0.0f;
|
||||
}
|
||||
|
||||
for (z=1;z<=n[2];z++)
|
||||
{
|
||||
for (y=1;y<=n[1];y++)
|
||||
{
|
||||
for (x=1;x<=n[0];x++)
|
||||
{
|
||||
int index=(x-1)*n[1]*n[2] + (y-1)*n[2] + z-1;
|
||||
vp->data_r[index] = origf * vp->data_r[index] + fac * sr[ms_I(x,y,z,n)];
|
||||
vp->data_g[index] = origf * vp->data_g[index] + fac * sg[ms_I(x,y,z,n)];
|
||||
vp->data_b[index] = origf * vp->data_b[index] + fac * sb[ms_I(x,y,z,n)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(sr0);
|
||||
MEM_freeN(sr);
|
||||
MEM_freeN(sg0);
|
||||
MEM_freeN(sg);
|
||||
MEM_freeN(sb0);
|
||||
MEM_freeN(sb);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if 0 // debug stuff
|
||||
static void *vol_precache_part_test(void *data)
|
||||
{
|
||||
VolPrecachePart *pa = data;
|
||||
|
||||
printf("part number: %d \n", pa->num);
|
||||
printf("done: %d \n", pa->done);
|
||||
printf("x min: %d x max: %d \n", pa->minx, pa->maxx);
|
||||
printf("y min: %d y max: %d \n", pa->miny, pa->maxy);
|
||||
printf("z min: %d z max: %d \n", pa->minz, pa->maxz);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Iterate over the 3d voxel grid, and fill the voxels with scattering information
|
||||
*
|
||||
* It's stored in memory as 3 big float grids next to each other, one for each RGB channel.
|
||||
* I'm guessing the memory alignment may work out better this way for the purposes
|
||||
* of doing linear interpolation, but I haven't actually tested this theory! :)
|
||||
*/
|
||||
static void *vol_precache_part(void *data)
|
||||
{
|
||||
VolPrecachePart *pa = (VolPrecachePart *)data;
|
||||
ObjectInstanceRen *obi = pa->obi;
|
||||
RayTree *tree = pa->tree;
|
||||
ShadeInput *shi = pa->shi;
|
||||
float density, scatter_col[3] = {0.f, 0.f, 0.f};
|
||||
float co[3];
|
||||
int x, y, z;
|
||||
const int res[3]= {pa->res[0], pa->res[1], pa->res[2]};
|
||||
const float stepsize = vol_get_stepsize(shi, STEPSIZE_VIEW);
|
||||
|
||||
for (z= pa->minz; z < pa->maxz; z++) {
|
||||
co[2] = pa->bbmin[2] + (pa->voxel[2] * z);
|
||||
|
||||
for (y= pa->miny; y < pa->maxy; y++) {
|
||||
co[1] = pa->bbmin[1] + (pa->voxel[1] * y);
|
||||
|
||||
for (x=pa->minx; x < pa->maxx; x++) {
|
||||
co[0] = pa->bbmin[0] + (pa->voxel[0] * x);
|
||||
|
||||
// don't bother if the point is not inside the volume mesh
|
||||
if (!point_inside_obi(tree, obi, co)) {
|
||||
obi->volume_precache->data_r[ V_I(x, y, z, res) ] = -1.0f;
|
||||
obi->volume_precache->data_g[ V_I(x, y, z, res) ] = -1.0f;
|
||||
obi->volume_precache->data_b[ V_I(x, y, z, res) ] = -1.0f;
|
||||
continue;
|
||||
}
|
||||
|
||||
VecCopyf(shi->view, co);
|
||||
Normalize(shi->view);
|
||||
density = vol_get_density(shi, co);
|
||||
vol_get_scattering(shi, scatter_col, co, stepsize, density);
|
||||
|
||||
obi->volume_precache->data_r[ V_I(x, y, z, res) ] = scatter_col[0];
|
||||
obi->volume_precache->data_g[ V_I(x, y, z, res) ] = scatter_col[1];
|
||||
obi->volume_precache->data_b[ V_I(x, y, z, res) ] = scatter_col[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pa->done = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void precache_setup_shadeinput(Render *re, ObjectInstanceRen *obi, Material *ma, ShadeInput *shi)
|
||||
{
|
||||
memset(shi, 0, sizeof(ShadeInput));
|
||||
shi->depth= 1;
|
||||
shi->mask= 1;
|
||||
shi->mat = ma;
|
||||
shi->vlr = NULL;
|
||||
memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); // note, keep this synced with render_types.h
|
||||
shi->har= shi->mat->har;
|
||||
shi->obi= obi;
|
||||
shi->obr= obi->obr;
|
||||
shi->lay = re->scene->lay;
|
||||
}
|
||||
|
||||
static void precache_init_parts(Render *re, RayTree *tree, ShadeInput *shi, ObjectInstanceRen *obi, int totthread, int *parts)
|
||||
{
|
||||
VolumePrecache *vp = obi->volume_precache;
|
||||
int i=0, x, y, z;
|
||||
float voxel[3];
|
||||
int sizex, sizey, sizez;
|
||||
float *bbmin=obi->obr->boundbox[0], *bbmax=obi->obr->boundbox[1];
|
||||
int *res;
|
||||
int minx, maxx;
|
||||
int miny, maxy;
|
||||
int minz, maxz;
|
||||
|
||||
if (!vp) return;
|
||||
|
||||
BLI_freelistN(&re->volume_precache_parts);
|
||||
|
||||
/* currently we just subdivide the box, number of threads per side */
|
||||
parts[0] = parts[1] = parts[2] = totthread;
|
||||
res = vp->res;
|
||||
|
||||
VecSubf(voxel, bbmax, bbmin);
|
||||
if ((voxel[0] < FLT_EPSILON) || (voxel[1] < FLT_EPSILON) || (voxel[2] < FLT_EPSILON))
|
||||
return;
|
||||
voxel[0] /= res[0];
|
||||
voxel[1] /= res[1];
|
||||
voxel[2] /= res[2];
|
||||
|
||||
for (x=0; x < parts[0]; x++) {
|
||||
sizex = ceil(res[0] / (float)parts[0]);
|
||||
minx = x * sizex;
|
||||
maxx = minx + sizex;
|
||||
maxx = (maxx>res[0])?res[0]:maxx;
|
||||
|
||||
for (y=0; y < parts[1]; y++) {
|
||||
sizey = ceil(res[1] / (float)parts[1]);
|
||||
miny = y * sizey;
|
||||
maxy = miny + sizey;
|
||||
maxy = (maxy>res[1])?res[1]:maxy;
|
||||
|
||||
for (z=0; z < parts[2]; z++) {
|
||||
VolPrecachePart *pa= MEM_callocN(sizeof(VolPrecachePart), "new precache part");
|
||||
|
||||
sizez = ceil(res[2] / (float)parts[2]);
|
||||
minz = z * sizez;
|
||||
maxz = minz + sizez;
|
||||
maxz = (maxz>res[2])?res[2]:maxz;
|
||||
|
||||
pa->done = 0;
|
||||
pa->working = 0;
|
||||
|
||||
pa->num = i;
|
||||
pa->tree = tree;
|
||||
pa->shi = shi;
|
||||
pa->obi = obi;
|
||||
VECCOPY(pa->bbmin, bbmin);
|
||||
VECCOPY(pa->voxel, voxel);
|
||||
VECCOPY(pa->res, res);
|
||||
|
||||
pa->minx = minx; pa->maxx = maxx;
|
||||
pa->miny = miny; pa->maxy = maxy;
|
||||
pa->minz = minz; pa->maxz = maxz;
|
||||
|
||||
|
||||
BLI_addtail(&re->volume_precache_parts, pa);
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static VolPrecachePart *precache_get_new_part(Render *re)
|
||||
{
|
||||
VolPrecachePart *pa, *nextpa=NULL;
|
||||
|
||||
for (pa = re->volume_precache_parts.first; pa; pa=pa->next)
|
||||
{
|
||||
if (pa->done==0 && pa->working==0) {
|
||||
nextpa = pa;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return nextpa;
|
||||
}
|
||||
|
||||
static void precache_resolution(VolumePrecache *vp, float *bbmin, float *bbmax, int res)
|
||||
{
|
||||
float dim[3], div;
|
||||
|
||||
VecSubf(dim, bbmax, bbmin);
|
||||
|
||||
div = MAX3(dim[0], dim[1], dim[2]);
|
||||
dim[0] /= div;
|
||||
dim[1] /= div;
|
||||
dim[2] /= div;
|
||||
|
||||
vp->res[0] = dim[0] * (float)res;
|
||||
vp->res[1] = dim[1] * (float)res;
|
||||
vp->res[2] = dim[2] * (float)res;
|
||||
}
|
||||
|
||||
/* Precache a volume into a 3D voxel grid.
|
||||
* The voxel grid is stored in the ObjectInstanceRen,
|
||||
* in camera space, aligned with the ObjectRen's bounding box.
|
||||
* Resolution is defined by the user.
|
||||
*/
|
||||
void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Material *ma)
|
||||
{
|
||||
VolumePrecache *vp;
|
||||
VolPrecachePart *nextpa, *pa;
|
||||
RayTree *tree;
|
||||
ShadeInput shi;
|
||||
ListBase threads;
|
||||
float *bbmin=obi->obr->boundbox[0], *bbmax=obi->obr->boundbox[1];
|
||||
int parts[3], totparts;
|
||||
|
||||
int caching=1, counter=0;
|
||||
int totthread = re->r.threads;
|
||||
|
||||
double time, lasttime= PIL_check_seconds_timer();
|
||||
|
||||
R = *re;
|
||||
|
||||
/* create a raytree with just the faces of the instanced ObjectRen,
|
||||
* used for checking if the cached point is inside or outside. */
|
||||
tree = create_raytree_obi(obi, bbmin, bbmax);
|
||||
if (!tree) return;
|
||||
|
||||
vp = MEM_callocN(sizeof(VolumePrecache), "volume light cache");
|
||||
precache_resolution(vp, bbmin, bbmax, ma->vol.precache_resolution);
|
||||
|
||||
vp->data_r = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data red channel");
|
||||
vp->data_g = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data green channel");
|
||||
vp->data_b = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data blue channel");
|
||||
obi->volume_precache = vp;
|
||||
|
||||
/* Need a shadeinput to calculate scattering */
|
||||
precache_setup_shadeinput(re, obi, ma, &shi);
|
||||
|
||||
precache_init_parts(re, tree, &shi, obi, totthread, parts);
|
||||
totparts = parts[0] * parts[1] * parts[2];
|
||||
|
||||
BLI_init_threads(&threads, vol_precache_part, totthread);
|
||||
|
||||
while(caching) {
|
||||
|
||||
if(BLI_available_threads(&threads) && !(re->test_break(re->tbh))) {
|
||||
nextpa = precache_get_new_part(re);
|
||||
if (nextpa) {
|
||||
nextpa->working = 1;
|
||||
BLI_insert_thread(&threads, nextpa);
|
||||
}
|
||||
}
|
||||
else PIL_sleep_ms(50);
|
||||
|
||||
caching=0;
|
||||
counter=0;
|
||||
for(pa= re->volume_precache_parts.first; pa; pa= pa->next) {
|
||||
|
||||
if(pa->done) {
|
||||
counter++;
|
||||
BLI_remove_thread(&threads, pa);
|
||||
} else
|
||||
caching = 1;
|
||||
}
|
||||
|
||||
if (re->test_break(re->tbh) && BLI_available_threads(&threads)==totthread)
|
||||
caching=0;
|
||||
|
||||
time= PIL_check_seconds_timer();
|
||||
if(time-lasttime>1.0f) {
|
||||
char str[64];
|
||||
sprintf(str, "Precaching volume: %d%%", (int)(100.0f * ((float)counter / (float)totparts)));
|
||||
re->i.infostr= str;
|
||||
re->stats_draw(re->sdh, &re->i);
|
||||
re->i.infostr= NULL;
|
||||
lasttime= time;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_end_threads(&threads);
|
||||
BLI_freelistN(&re->volume_precache_parts);
|
||||
|
||||
if(tree) {
|
||||
RE_ray_tree_free(tree);
|
||||
tree= NULL;
|
||||
}
|
||||
|
||||
lightcache_filter(obi->volume_precache);
|
||||
|
||||
if (ELEM(ma->vol.shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SINGLEPLUSMULTIPLE))
|
||||
{
|
||||
multiple_scattering_diffusion(re, vp, ma);
|
||||
}
|
||||
}
|
||||
|
||||
int using_lightcache(Material *ma)
|
||||
{
|
||||
return (((ma->vol.shadeflag & MA_VOL_PRECACHESHADING) && (ma->vol.shade_type == MA_VOL_SHADE_SINGLE))
|
||||
|| (ELEM(ma->vol.shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SINGLEPLUSMULTIPLE)));
|
||||
}
|
||||
|
||||
/* loop through all objects (and their associated materials)
|
||||
* marked for pre-caching in convertblender.c, and pre-cache them */
|
||||
void volume_precache(Render *re)
|
||||
{
|
||||
ObjectInstanceRen *obi;
|
||||
VolumeOb *vo;
|
||||
|
||||
for(vo= re->volumes.first; vo; vo= vo->next) {
|
||||
if (using_lightcache(vo->ma)) {
|
||||
for(obi= re->instancetable.first; obi; obi= obi->next) {
|
||||
if (obi->obr == vo->obr) {
|
||||
vol_precache_objectinstance_threads(re, obi, vo->ma);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
re->i.infostr= NULL;
|
||||
re->stats_draw(re->sdh, &re->i);
|
||||
}
|
||||
|
||||
void free_volume_precache(Render *re)
|
||||
{
|
||||
ObjectInstanceRen *obi;
|
||||
|
||||
for(obi= re->instancetable.first; obi; obi= obi->next) {
|
||||
if (obi->volume_precache != NULL) {
|
||||
MEM_freeN(obi->volume_precache);
|
||||
MEM_freeN(obi->volume_precache->data_r);
|
||||
MEM_freeN(obi->volume_precache->data_g);
|
||||
MEM_freeN(obi->volume_precache->data_b);
|
||||
}
|
||||
}
|
||||
|
||||
BLI_freelistN(&re->volumes);
|
||||
}
|
||||
|
||||
int point_inside_volume_objectinstance(ObjectInstanceRen *obi, float *co)
|
||||
{
|
||||
RayTree *tree;
|
||||
int inside=0;
|
||||
|
||||
tree = create_raytree_obi(obi, obi->obr->boundbox[0], obi->obr->boundbox[1]);
|
||||
if (!tree) return 0;
|
||||
|
||||
inside = point_inside_obi(tree, obi, co);
|
||||
|
||||
RE_ray_tree_free(tree);
|
||||
tree= NULL;
|
||||
|
||||
return inside;
|
||||
}
|
||||
|
688
source/blender/render/intern/source/volumetric.c
Normal file
688
source/blender/render/intern/source/volumetric.c
Normal file
@ -0,0 +1,688 @@
|
||||
/**
|
||||
*
|
||||
* ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Matt Ebb, Raul Fernandez Hernandez (Farsthary)
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <float.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_arithb.h"
|
||||
#include "BLI_rand.h"
|
||||
#include "BLI_voxel.h"
|
||||
|
||||
#include "RE_shader_ext.h"
|
||||
#include "RE_raytrace.h"
|
||||
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_group_types.h"
|
||||
#include "DNA_lamp_types.h"
|
||||
|
||||
#include "BKE_global.h"
|
||||
|
||||
#include "render_types.h"
|
||||
#include "pixelshading.h"
|
||||
#include "shading.h"
|
||||
#include "texture.h"
|
||||
#include "volumetric.h"
|
||||
#include "volume_precache.h"
|
||||
|
||||
#if defined( _MSC_VER ) && !defined( __cplusplus )
|
||||
# define inline __inline
|
||||
#endif // defined( _MSC_VER ) && !defined( __cplusplus )
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
|
||||
/* only to be used here in this file, it's for speed */
|
||||
extern struct Render R;
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
|
||||
/* tracing */
|
||||
|
||||
static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, Isect *isect, int intersect_type)
|
||||
{
|
||||
float maxsize = RE_ray_tree_max_size(R.raytree);
|
||||
|
||||
/* XXX TODO - get raytrace max distance from object instance's bounding box */
|
||||
/* need to account for scaling only, but keep coords in camera space...
|
||||
* below code is WIP and doesn't work!
|
||||
VecSubf(bb_dim, shi->obi->obr->boundbox[1], shi->obi->obr->boundbox[2]);
|
||||
Mat3MulVecfl(shi->obi->nmat, bb_dim);
|
||||
maxsize = VecLength(bb_dim);
|
||||
*/
|
||||
|
||||
VECCOPY(isect->start, co);
|
||||
isect->end[0] = co[0] + vec[0] * maxsize;
|
||||
isect->end[1] = co[1] + vec[1] * maxsize;
|
||||
isect->end[2] = co[2] + vec[2] * maxsize;
|
||||
|
||||
isect->mode= RE_RAY_MIRROR;
|
||||
isect->oborig= RAY_OBJECT_SET(&R, shi->obi);
|
||||
isect->face_last= NULL;
|
||||
isect->ob_last= 0;
|
||||
isect->lay= -1;
|
||||
|
||||
if (intersect_type == VOL_BOUNDS_DEPTH) isect->faceorig= (RayFace*)shi->vlr;
|
||||
else if (intersect_type == VOL_BOUNDS_SS) isect->faceorig= NULL;
|
||||
|
||||
if(RE_ray_tree_intersect(R.raytree, isect))
|
||||
{
|
||||
hitco[0] = isect->start[0] + isect->labda*isect->vec[0];
|
||||
hitco[1] = isect->start[1] + isect->labda*isect->vec[1];
|
||||
hitco[2] = isect->start[2] + isect->labda*isect->vec[2];
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void shade_intersection(ShadeInput *shi, float *col, Isect *is)
|
||||
{
|
||||
ShadeInput shi_new;
|
||||
ShadeResult shr_new;
|
||||
|
||||
memset(&shi_new, 0, sizeof(ShadeInput));
|
||||
|
||||
shi_new.mask= shi->mask;
|
||||
shi_new.osatex= shi->osatex;
|
||||
shi_new.thread= shi->thread;
|
||||
shi_new.depth = shi->depth + 1;
|
||||
shi_new.volume_depth= shi->volume_depth + 1;
|
||||
shi_new.xs= shi->xs;
|
||||
shi_new.ys= shi->ys;
|
||||
shi_new.lay= shi->lay;
|
||||
shi_new.passflag= SCE_PASS_COMBINED; /* result of tracing needs no pass info */
|
||||
shi_new.combinedflag= 0xFFFFFF; /* ray trace does all options */
|
||||
shi_new.light_override= shi->light_override;
|
||||
shi_new.mat_override= shi->mat_override;
|
||||
|
||||
VECCOPY(shi_new.camera_co, is->start);
|
||||
|
||||
memset(&shr_new, 0, sizeof(ShadeResult));
|
||||
|
||||
/* hardcoded limit of 100 for now - prevents problems in weird geometry */
|
||||
if (shi->volume_depth < 100) {
|
||||
shade_ray(is, &shi_new, &shr_new);
|
||||
}
|
||||
|
||||
VecCopyf(col, shr_new.combined);
|
||||
col[3] = shr_new.alpha;
|
||||
}
|
||||
|
||||
static void vol_trace_behind(ShadeInput *shi, VlakRen *vlr, float *co, float *col)
|
||||
{
|
||||
Isect isect;
|
||||
float maxsize = RE_ray_tree_max_size(R.raytree);
|
||||
|
||||
VECCOPY(isect.start, co);
|
||||
isect.end[0] = isect.start[0] + shi->view[0] * maxsize;
|
||||
isect.end[1] = isect.start[1] + shi->view[1] * maxsize;
|
||||
isect.end[2] = isect.start[2] + shi->view[2] * maxsize;
|
||||
|
||||
isect.faceorig= (RayFace *)vlr;
|
||||
|
||||
isect.mode= RE_RAY_MIRROR;
|
||||
isect.oborig= RAY_OBJECT_SET(&R, shi->obi);
|
||||
isect.face_last= NULL;
|
||||
isect.ob_last= 0;
|
||||
isect.lay= -1;
|
||||
|
||||
/* check to see if there's anything behind the volume, otherwise shade the sky */
|
||||
if(RE_ray_tree_intersect(R.raytree, &isect)) {
|
||||
shade_intersection(shi, col, &isect);
|
||||
} else {
|
||||
shadeSkyView(col, co, shi->view, NULL, shi->thread);
|
||||
shadeSunView(col, shi->view);
|
||||
}
|
||||
}
|
||||
|
||||
/* input shader data */
|
||||
|
||||
float vol_get_stepsize(struct ShadeInput *shi, int context)
|
||||
{
|
||||
if (shi->mat->vol.stepsize_type == MA_VOL_STEP_RANDOMIZED) {
|
||||
/* range between 0.75 and 1.25 */
|
||||
const float rnd = 0.5f * BLI_thread_frand(shi->thread) + 0.75f;
|
||||
|
||||
if (context == STEPSIZE_VIEW)
|
||||
return shi->mat->vol.stepsize * rnd;
|
||||
else if (context == STEPSIZE_SHADE)
|
||||
return shi->mat->vol.shade_stepsize * rnd;
|
||||
}
|
||||
else { // MA_VOL_STEP_CONSTANT
|
||||
|
||||
if (context == STEPSIZE_VIEW)
|
||||
return shi->mat->vol.stepsize;
|
||||
else if (context == STEPSIZE_SHADE)
|
||||
return shi->mat->vol.shade_stepsize;
|
||||
}
|
||||
|
||||
return shi->mat->vol.stepsize;
|
||||
}
|
||||
|
||||
/* trilinear interpolation */
|
||||
static void vol_get_precached_scattering(ShadeInput *shi, float *scatter_col, float *co)
|
||||
{
|
||||
VolumePrecache *vp = shi->obi->volume_precache;
|
||||
float bbmin[3], bbmax[3], dim[3];
|
||||
float sample_co[3];
|
||||
|
||||
if (!vp) return;
|
||||
|
||||
/* convert input coords to 0.0, 1.0 */
|
||||
VECCOPY(bbmin, shi->obi->obr->boundbox[0]);
|
||||
VECCOPY(bbmax, shi->obi->obr->boundbox[1]);
|
||||
VecSubf(dim, bbmax, bbmin);
|
||||
|
||||
sample_co[0] = ((co[0] - bbmin[0]) / dim[0]);
|
||||
sample_co[1] = ((co[1] - bbmin[1]) / dim[1]);
|
||||
sample_co[2] = ((co[2] - bbmin[2]) / dim[2]);
|
||||
|
||||
scatter_col[0] = voxel_sample_trilinear(vp->data_r, vp->res, sample_co);
|
||||
scatter_col[1] = voxel_sample_trilinear(vp->data_g, vp->res, sample_co);
|
||||
scatter_col[2] = voxel_sample_trilinear(vp->data_b, vp->res, sample_co);
|
||||
}
|
||||
|
||||
float vol_get_density(struct ShadeInput *shi, float *co)
|
||||
{
|
||||
float density = shi->mat->vol.density;
|
||||
float density_scale = shi->mat->vol.density_scale;
|
||||
float col[3] = {0.0, 0.0, 0.0};
|
||||
|
||||
do_volume_tex(shi, co, MAP_DENSITY, col, &density);
|
||||
|
||||
return density * density_scale;
|
||||
}
|
||||
|
||||
/* scattering multiplier, values above 1.0 are non-physical,
|
||||
* but can be useful to tweak lighting */
|
||||
float vol_get_scattering_fac(ShadeInput *shi, float *co)
|
||||
{
|
||||
float scatter = shi->mat->vol.scattering;
|
||||
float col[3] = {0.0, 0.0, 0.0};
|
||||
|
||||
do_volume_tex(shi, co, MAP_SCATTERING, col, &scatter);
|
||||
|
||||
return scatter;
|
||||
}
|
||||
|
||||
/* compute emission component, amount of radiance to add per segment
|
||||
* can be textured with 'emit' */
|
||||
void vol_get_emission(ShadeInput *shi, float *emission_col, float *co, float density)
|
||||
{
|
||||
float emission = shi->mat->vol.emission;
|
||||
VECCOPY(emission_col, shi->mat->vol.emission_col);
|
||||
|
||||
do_volume_tex(shi, co, MAP_EMISSION+MAP_EMISSION_COL, emission_col, &emission);
|
||||
|
||||
emission_col[0] = emission_col[0] * emission * density;
|
||||
emission_col[1] = emission_col[1] * emission * density;
|
||||
emission_col[2] = emission_col[2] * emission * density;
|
||||
}
|
||||
|
||||
void vol_get_absorption(ShadeInput *shi, float *absorb_col, float *co)
|
||||
{
|
||||
float absorption = shi->mat->vol.absorption;
|
||||
VECCOPY(absorb_col, shi->mat->vol.absorption_col);
|
||||
|
||||
do_volume_tex(shi, co, MAP_ABSORPTION+MAP_ABSORPTION_COL, absorb_col, &absorption);
|
||||
|
||||
absorb_col[0] = (1.0f - absorb_col[0]) * absorption;
|
||||
absorb_col[1] = (1.0f - absorb_col[1]) * absorption;
|
||||
absorb_col[2] = (1.0f - absorb_col[2]) * absorption;
|
||||
}
|
||||
|
||||
|
||||
/* phase function - determines in which directions the light
|
||||
* is scattered in the volume relative to incoming direction
|
||||
* and view direction */
|
||||
float vol_get_phasefunc(ShadeInput *shi, short phasefunc_type, float g, float *w, float *wp)
|
||||
{
|
||||
const float costheta = Inpf(w, wp);
|
||||
const float scale = M_PI;
|
||||
|
||||
/*
|
||||
* Scale constant is required, since Blender's shading system doesn't normalise for
|
||||
* energy conservation - eg. scaling by 1/pi for a lambert shader.
|
||||
* This makes volumes darker than other solid objects, for the same lighting intensity.
|
||||
* To correct this, scale up the phase function values
|
||||
* until Blender's shading system supports this better. --matt
|
||||
*/
|
||||
|
||||
switch (phasefunc_type) {
|
||||
case MA_VOL_PH_MIEHAZY:
|
||||
return scale * (0.5f + 4.5f * powf(0.5 * (1.f + costheta), 8.f)) / (4.f*M_PI);
|
||||
case MA_VOL_PH_MIEMURKY:
|
||||
return scale * (0.5f + 16.5f * powf(0.5 * (1.f + costheta), 32.f)) / (4.f*M_PI);
|
||||
case MA_VOL_PH_RAYLEIGH:
|
||||
return scale * 3.f/(16.f*M_PI) * (1 + costheta * costheta);
|
||||
case MA_VOL_PH_HG:
|
||||
return scale * (1.f / (4.f * M_PI) * (1.f - g*g) / powf(1.f + g*g - 2.f * g * costheta, 1.5f));
|
||||
case MA_VOL_PH_SCHLICK:
|
||||
{
|
||||
const float k = 1.55f * g - .55f * g * g * g;
|
||||
const float kcostheta = k * costheta;
|
||||
return scale * (1.f / (4.f * M_PI) * (1.f - k*k) / ((1.f - kcostheta) * (1.f - kcostheta)));
|
||||
}
|
||||
case MA_VOL_PH_ISOTROPIC:
|
||||
default:
|
||||
return scale * (1.f / (4.f * M_PI));
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute attenuation, otherwise known as 'optical thickness', extinction, or tau.
|
||||
* Used in the relationship Transmittance = e^(-attenuation)
|
||||
*/
|
||||
void vol_get_attenuation_seg(ShadeInput *shi, float *transmission, float stepsize, float *co, float density)
|
||||
{
|
||||
/* input density = density at co */
|
||||
float tau[3] = {0.f, 0.f, 0.f};
|
||||
float absorb_col[3];
|
||||
|
||||
vol_get_absorption(shi, absorb_col, co);
|
||||
|
||||
/* homogenous volume within the sampled distance */
|
||||
tau[0] = stepsize * density * absorb_col[0];
|
||||
tau[1] = stepsize * density * absorb_col[1];
|
||||
tau[2] = stepsize * density * absorb_col[2];
|
||||
|
||||
transmission[0] *= exp(-tau[0]);
|
||||
transmission[1] *= exp(-tau[1]);
|
||||
transmission[2] *= exp(-tau[2]);
|
||||
}
|
||||
|
||||
/* Compute attenuation, otherwise known as 'optical thickness', extinction, or tau.
|
||||
* Used in the relationship Transmittance = e^(-attenuation)
|
||||
*/
|
||||
void vol_get_attenuation(ShadeInput *shi, float *transmission, float *co, float *endco, float density, float stepsize)
|
||||
{
|
||||
/* input density = density at co */
|
||||
float tau[3] = {0.f, 0.f, 0.f};
|
||||
float absorb_col[3];
|
||||
int s, nsteps;
|
||||
float step_vec[3], step_sta[3], step_end[3];
|
||||
const float dist = VecLenf(co, endco);
|
||||
|
||||
vol_get_absorption(shi, absorb_col, co);
|
||||
|
||||
nsteps = (int)((dist / stepsize) + 0.5);
|
||||
|
||||
VecSubf(step_vec, endco, co);
|
||||
VecMulf(step_vec, 1.0f / nsteps);
|
||||
|
||||
VecCopyf(step_sta, co);
|
||||
VecAddf(step_end, step_sta, step_vec);
|
||||
|
||||
for (s = 0; s < nsteps; s++) {
|
||||
if (s > 0)
|
||||
density = vol_get_density(shi, step_sta);
|
||||
|
||||
tau[0] += stepsize * density;
|
||||
tau[1] += stepsize * density;
|
||||
tau[2] += stepsize * density;
|
||||
|
||||
if (s < nsteps-1) {
|
||||
VecCopyf(step_sta, step_end);
|
||||
VecAddf(step_end, step_end, step_vec);
|
||||
}
|
||||
}
|
||||
VecMulVecf(tau, tau, absorb_col);
|
||||
|
||||
transmission[0] *= exp(-tau[0]);
|
||||
transmission[1] *= exp(-tau[1]);
|
||||
transmission[2] *= exp(-tau[2]);
|
||||
}
|
||||
|
||||
void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float *lacol, float stepsize, float density)
|
||||
{
|
||||
float visifac, lv[3], lampdist;
|
||||
float tr[3]={1.0,1.0,1.0};
|
||||
float hitco[3], *atten_co;
|
||||
float p;
|
||||
float scatter_fac;
|
||||
float shade_stepsize = vol_get_stepsize(shi, STEPSIZE_SHADE);
|
||||
|
||||
if (lar->mode & LA_LAYER) if((lar->lay & shi->obi->lay)==0) return;
|
||||
if ((lar->lay & shi->lay)==0) return;
|
||||
if (lar->energy == 0.0) return;
|
||||
|
||||
if ((visifac= lamp_get_visibility(lar, co, lv, &lampdist)) == 0.f) return;
|
||||
|
||||
VecCopyf(lacol, &lar->r);
|
||||
|
||||
if(lar->mode & LA_TEXTURE) {
|
||||
shi->osatex= 0;
|
||||
do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE);
|
||||
}
|
||||
|
||||
VecMulf(lacol, visifac*lar->energy);
|
||||
|
||||
if (ELEM(lar->type, LA_SUN, LA_HEMI))
|
||||
VECCOPY(lv, lar->vec);
|
||||
VecMulf(lv, -1.0f);
|
||||
|
||||
if (shi->mat->vol.shade_type != MA_VOL_SHADE_NONE) {
|
||||
Isect is;
|
||||
|
||||
/* find minimum of volume bounds, or lamp coord */
|
||||
if (vol_get_bounds(shi, co, lv, hitco, &is, VOL_BOUNDS_SS)) {
|
||||
float dist = VecLenf(co, hitco);
|
||||
VlakRen *vlr = (VlakRen *)is.face;
|
||||
|
||||
/* simple internal shadowing */
|
||||
if (vlr->mat->material_type == MA_TYPE_SURFACE) {
|
||||
lacol[0] = lacol[1] = lacol[2] = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ELEM(lar->type, LA_SUN, LA_HEMI))
|
||||
/* infinite lights, can never be inside volume */
|
||||
atten_co = hitco;
|
||||
else if ( lampdist < dist ) {
|
||||
atten_co = lar->co;
|
||||
} else
|
||||
atten_co = hitco;
|
||||
|
||||
vol_get_attenuation(shi, tr, co, atten_co, density, shade_stepsize);
|
||||
|
||||
VecMulVecf(lacol, lacol, tr);
|
||||
}
|
||||
else {
|
||||
/* Point is on the outside edge of the volume,
|
||||
* therefore no attenuation, full transmission.
|
||||
* Radiance from lamp remains unchanged */
|
||||
}
|
||||
}
|
||||
|
||||
p = vol_get_phasefunc(shi, shi->mat->vol.phasefunc_type, shi->mat->vol.phasefunc_g, shi->view, lv);
|
||||
VecMulf(lacol, p);
|
||||
|
||||
scatter_fac = vol_get_scattering_fac(shi, co);
|
||||
VecMulf(lacol, scatter_fac);
|
||||
}
|
||||
|
||||
/* single scattering only for now */
|
||||
void vol_get_scattering(ShadeInput *shi, float *scatter_col, float *co, float stepsize, float density)
|
||||
{
|
||||
ListBase *lights;
|
||||
GroupObject *go;
|
||||
LampRen *lar;
|
||||
|
||||
scatter_col[0] = scatter_col[1] = scatter_col[2] = 0.f;
|
||||
|
||||
lights= get_lights(shi);
|
||||
for(go=lights->first; go; go= go->next)
|
||||
{
|
||||
float lacol[3] = {0.f, 0.f, 0.f};
|
||||
lar= go->lampren;
|
||||
|
||||
if (lar) {
|
||||
vol_shade_one_lamp(shi, co, lar, lacol, stepsize, density);
|
||||
VecAddf(scatter_col, scatter_col, lacol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
The main volumetric integrator, using an emission/absorption/scattering model.
|
||||
|
||||
Incoming radiance =
|
||||
|
||||
outgoing radiance from behind surface * beam transmittance/attenuation
|
||||
+ added radiance from all points along the ray due to participating media
|
||||
--> radiance for each segment =
|
||||
(radiance added by scattering + radiance added by emission) * beam transmittance/attenuation
|
||||
*/
|
||||
static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float *endco)
|
||||
{
|
||||
float tr[3] = {1.0f, 1.0f, 1.0f};
|
||||
float radiance[3] = {0.f, 0.f, 0.f}, d_radiance[3] = {0.f, 0.f, 0.f};
|
||||
float stepsize = vol_get_stepsize(shi, STEPSIZE_VIEW);
|
||||
int nsteps, s;
|
||||
float emit_col[3], scatter_col[3] = {0.0, 0.0, 0.0};
|
||||
float stepvec[3], step_sta[3], step_end[3], step_mid[3];
|
||||
float density;
|
||||
const float depth_cutoff = shi->mat->vol.depth_cutoff;
|
||||
|
||||
/* ray marching */
|
||||
nsteps = (int)((VecLenf(co, endco) / stepsize) + 0.5);
|
||||
|
||||
VecSubf(stepvec, endco, co);
|
||||
VecMulf(stepvec, 1.0f / nsteps);
|
||||
VecCopyf(step_sta, co);
|
||||
VecAddf(step_end, step_sta, stepvec);
|
||||
|
||||
/* get radiance from all points along the ray due to participating media */
|
||||
for (s = 0; s < nsteps; s++) {
|
||||
|
||||
density = vol_get_density(shi, step_sta);
|
||||
|
||||
/* there's only any use in shading here if there's actually some density to shade! */
|
||||
if (density > 0.01f) {
|
||||
|
||||
/* transmittance component (alpha) */
|
||||
vol_get_attenuation_seg(shi, tr, stepsize, co, density);
|
||||
|
||||
step_mid[0] = step_sta[0] + (stepvec[0] * 0.5);
|
||||
step_mid[1] = step_sta[1] + (stepvec[1] * 0.5);
|
||||
step_mid[2] = step_sta[2] + (stepvec[2] * 0.5);
|
||||
|
||||
/* incoming light via emission or scattering (additive) */
|
||||
vol_get_emission(shi, emit_col, step_mid, density);
|
||||
|
||||
if (using_lightcache(shi->mat)) {
|
||||
vol_get_precached_scattering(shi, scatter_col, step_mid);
|
||||
} else
|
||||
vol_get_scattering(shi, scatter_col, step_mid, stepsize, density);
|
||||
|
||||
VecMulf(scatter_col, density);
|
||||
VecAddf(d_radiance, emit_col, scatter_col);
|
||||
|
||||
/* Lv += Tr * (Lve() + Ld) */
|
||||
VecMulVecf(d_radiance, tr, d_radiance);
|
||||
VecMulf(d_radiance, stepsize);
|
||||
|
||||
VecAddf(radiance, radiance, d_radiance);
|
||||
}
|
||||
|
||||
VecCopyf(step_sta, step_end);
|
||||
VecAddf(step_end, step_end, stepvec);
|
||||
|
||||
/* luminance rec. 709 */
|
||||
if ((0.2126*tr[0] + 0.7152*tr[1] + 0.0722*tr[2]) < depth_cutoff) break;
|
||||
}
|
||||
|
||||
/* multiply original color (behind volume) with beam transmittance over entire distance */
|
||||
VecMulVecf(col, tr, col);
|
||||
VecAddf(col, col, radiance);
|
||||
|
||||
/* alpha <-- transmission luminance */
|
||||
col[3] = 1.0f -(0.2126*tr[0] + 0.7152*tr[1] + 0.0722*tr[2]);
|
||||
}
|
||||
|
||||
/* the main entry point for volume shading */
|
||||
static void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr, int inside_volume)
|
||||
{
|
||||
float hitco[3], col[4] = {0.f,0.f,0.f,0.f};
|
||||
float *startco, *endco;
|
||||
int trace_behind = 1;
|
||||
const int ztransp= ((shi->depth==0) && (shi->mat->mode & MA_TRANSP) && (shi->mat->mode & MA_ZTRANSP));
|
||||
Isect is;
|
||||
|
||||
/* check for shading an internal face a volume object directly */
|
||||
if (inside_volume == VOL_SHADE_INSIDE)
|
||||
trace_behind = 0;
|
||||
else if (inside_volume == VOL_SHADE_OUTSIDE) {
|
||||
if (shi->flippednor)
|
||||
inside_volume = VOL_SHADE_INSIDE;
|
||||
}
|
||||
|
||||
if (ztransp && inside_volume == VOL_SHADE_INSIDE) {
|
||||
MatInside *mi;
|
||||
int render_this=0;
|
||||
|
||||
/* don't render the backfaces of ztransp volume materials.
|
||||
|
||||
* volume shading renders the internal volume from between the
|
||||
* near view intersection of the solid volume to the
|
||||
* intersection on the other side, as part of the shading of
|
||||
* the front face.
|
||||
|
||||
* Because ztransp renders both front and back faces independently
|
||||
* this will double up, so here we prevent rendering the backface as well,
|
||||
* which would otherwise render the volume in between the camera and the backface
|
||||
* --matt */
|
||||
|
||||
for (mi=R.render_volumes_inside.first; mi; mi=mi->next) {
|
||||
/* weak... */
|
||||
if (mi->ma == shi->mat) render_this=1;
|
||||
}
|
||||
if (!render_this) return;
|
||||
}
|
||||
|
||||
|
||||
if (inside_volume == VOL_SHADE_INSIDE)
|
||||
{
|
||||
startco = shi->camera_co;
|
||||
endco = shi->co;
|
||||
|
||||
if (trace_behind) {
|
||||
if (!ztransp)
|
||||
/* trace behind the volume object */
|
||||
vol_trace_behind(shi, shi->vlr, endco, col);
|
||||
} else {
|
||||
/* we're tracing through the volume between the camera
|
||||
* and a solid surface, so use that pre-shaded radiance */
|
||||
QUATCOPY(col, shr->combined);
|
||||
}
|
||||
|
||||
/* shade volume from 'camera' to 1st hit point */
|
||||
volumeintegrate(shi, col, startco, endco);
|
||||
}
|
||||
/* trace to find a backface, the other side bounds of the volume */
|
||||
/* (ray intersect ignores front faces here) */
|
||||
else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH))
|
||||
{
|
||||
VlakRen *vlr = (VlakRen *)is.face;
|
||||
|
||||
startco = shi->co;
|
||||
endco = hitco;
|
||||
|
||||
if (!ztransp) {
|
||||
/* if it's another face in the same material */
|
||||
if (vlr->mat == shi->mat) {
|
||||
/* trace behind the 2nd (raytrace) hit point */
|
||||
vol_trace_behind(shi, (VlakRen *)is.face, endco, col);
|
||||
} else {
|
||||
shade_intersection(shi, col, &is);
|
||||
}
|
||||
}
|
||||
|
||||
/* shade volume from 1st hit point to 2nd hit point */
|
||||
volumeintegrate(shi, col, startco, endco);
|
||||
}
|
||||
|
||||
if (ztransp)
|
||||
col[3] = col[3]>1.f?1.f:col[3];
|
||||
else
|
||||
col[3] = 1.f;
|
||||
|
||||
VecCopyf(shr->combined, col);
|
||||
shr->alpha = col[3];
|
||||
|
||||
VECCOPY(shr->diff, shr->combined);
|
||||
}
|
||||
|
||||
/* Traces a shadow through the object,
|
||||
* pretty much gets the transmission over a ray path */
|
||||
void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is)
|
||||
{
|
||||
float hitco[3];
|
||||
float tr[3] = {1.0,1.0,1.0};
|
||||
Isect is;
|
||||
float shade_stepsize = vol_get_stepsize(shi, STEPSIZE_SHADE);
|
||||
float *startco, *endco;
|
||||
float density=0.f;
|
||||
|
||||
memset(shr, 0, sizeof(ShadeResult));
|
||||
|
||||
/* if 1st hit normal is facing away from the camera,
|
||||
* then we're inside the volume already. */
|
||||
if (shi->flippednor) {
|
||||
startco = last_is->start;
|
||||
endco = shi->co;
|
||||
}
|
||||
/* trace to find a backface, the other side bounds of the volume */
|
||||
/* (ray intersect ignores front faces here) */
|
||||
else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH)) {
|
||||
startco = shi->co;
|
||||
endco = hitco;
|
||||
}
|
||||
else {
|
||||
shr->combined[0] = shr->combined[1] = shr->combined[2] = 0.f;
|
||||
shr->alpha = shr->combined[3] = 1.f;
|
||||
return;
|
||||
}
|
||||
|
||||
density = vol_get_density(shi, startco);
|
||||
vol_get_attenuation(shi, tr, startco, endco, density, shade_stepsize);
|
||||
|
||||
VecCopyf(shr->combined, tr);
|
||||
shr->combined[3] = 1.0f -(0.2126*tr[0] + 0.7152*tr[1] + 0.0722*tr[2]);
|
||||
shr->alpha = shr->combined[3];
|
||||
}
|
||||
|
||||
|
||||
/* delivers a fully filled in ShadeResult, for all passes */
|
||||
void shade_volume_outside(ShadeInput *shi, ShadeResult *shr)
|
||||
{
|
||||
memset(shr, 0, sizeof(ShadeResult));
|
||||
volume_trace(shi, shr, VOL_SHADE_OUTSIDE);
|
||||
}
|
||||
|
||||
|
||||
void shade_volume_inside(ShadeInput *shi, ShadeResult *shr)
|
||||
{
|
||||
MatInside *m;
|
||||
Material *mat_backup;
|
||||
|
||||
//if (BLI_countlist(&R.render_volumes_inside) == 0) return;
|
||||
|
||||
/* XXX: extend to multiple volumes perhaps later */
|
||||
mat_backup = shi->mat;
|
||||
m = R.render_volumes_inside.first;
|
||||
shi->mat = m->ma;
|
||||
|
||||
volume_trace(shi, shr, VOL_SHADE_INSIDE);
|
||||
|
||||
shi->mat = mat_backup;
|
||||
}
|
341
source/blender/render/intern/source/voxeldata.c
Normal file
341
source/blender/render/intern/source/voxeldata.c
Normal file
@ -0,0 +1,341 @@
|
||||
/**
|
||||
*
|
||||
* ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Raul Fernandez Hernandez (Farsthary), Matt Ebb.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_arithb.h"
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_voxel.h"
|
||||
|
||||
#include "IMB_imbuf.h"
|
||||
#include "IMB_imbuf_types.h"
|
||||
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_image.h"
|
||||
#include "BKE_main.h"
|
||||
|
||||
#include "smoke_API.h"
|
||||
|
||||
#include "DNA_texture_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_smoke_types.h"
|
||||
|
||||
|
||||
#include "render_types.h"
|
||||
#include "renderdatabase.h"
|
||||
#include "texture.h"
|
||||
#include "voxeldata.h"
|
||||
|
||||
void load_frame_blendervoxel(FILE *fp, float *F, int size, int frame, int offset)
|
||||
{
|
||||
fseek(fp,frame*size*sizeof(float)+offset,0);
|
||||
fread(F,sizeof(float),size,fp);
|
||||
}
|
||||
|
||||
void load_frame_raw8(FILE *fp, float *F, int size, int frame)
|
||||
{
|
||||
char *tmp;
|
||||
int i;
|
||||
|
||||
tmp = (char *)MEM_mallocN(sizeof(char)*size, "temporary voxel file reading storage");
|
||||
|
||||
fseek(fp,(frame-1)*size*sizeof(char),0);
|
||||
fread(tmp, sizeof(char), size, fp);
|
||||
|
||||
for (i=0; i<size; i++) {
|
||||
F[i] = (float)tmp[i] / 256.f;
|
||||
}
|
||||
MEM_freeN(tmp);
|
||||
}
|
||||
|
||||
void load_frame_image_sequence(Render *re, VoxelData *vd, Tex *tex)
|
||||
{
|
||||
ImBuf *ibuf;
|
||||
Image *ima = tex->ima;
|
||||
ImageUser *iuser = &tex->iuser;
|
||||
int x=0, y=0, z=0;
|
||||
float *rf;
|
||||
|
||||
if (!ima || !iuser) return;
|
||||
|
||||
ima->source = IMA_SRC_SEQUENCE;
|
||||
iuser->framenr = 1 + iuser->offset;
|
||||
|
||||
/* find the first valid ibuf and use it to initialise the resolution of the data set */
|
||||
/* need to do this in advance so we know how much memory to allocate */
|
||||
ibuf= BKE_image_get_ibuf(ima, iuser);
|
||||
while (!ibuf && (iuser->framenr < iuser->frames)) {
|
||||
iuser->framenr++;
|
||||
ibuf= BKE_image_get_ibuf(ima, iuser);
|
||||
}
|
||||
if (!ibuf) return;
|
||||
if (!ibuf->rect_float) IMB_float_from_rect(ibuf);
|
||||
|
||||
vd->flag |= TEX_VD_STILL;
|
||||
vd->resol[0] = ibuf->x;
|
||||
vd->resol[1] = ibuf->y;
|
||||
vd->resol[2] = iuser->frames;
|
||||
vd->dataset = MEM_mapallocN(sizeof(float)*(vd->resol[0])*(vd->resol[1])*(vd->resol[2]), "voxel dataset");
|
||||
|
||||
for (z=0; z < iuser->frames; z++)
|
||||
{
|
||||
/* get a new ibuf for each frame */
|
||||
if (z > 0) {
|
||||
iuser->framenr++;
|
||||
ibuf= BKE_image_get_ibuf(ima, iuser);
|
||||
if (!ibuf) break;
|
||||
if (!ibuf->rect_float) IMB_float_from_rect(ibuf);
|
||||
}
|
||||
rf = ibuf->rect_float;
|
||||
|
||||
for (y=0; y < ibuf->y; y++)
|
||||
{
|
||||
for (x=0; x < ibuf->x; x++)
|
||||
{
|
||||
/* currently converted to monchrome */
|
||||
vd->dataset[ V_I(x, y, z, vd->resol) ] = (rf[0] + rf[1] + rf[2])*0.333f;
|
||||
rf +=4;
|
||||
}
|
||||
}
|
||||
|
||||
BKE_image_free_anim_ibufs(ima, iuser->framenr);
|
||||
}
|
||||
}
|
||||
|
||||
void write_voxeldata_header(struct VoxelDataHeader *h, FILE *fp)
|
||||
{
|
||||
fwrite(h,sizeof(struct VoxelDataHeader),1,fp);
|
||||
}
|
||||
|
||||
void read_voxeldata_header(FILE *fp, struct VoxelData *vd)
|
||||
{
|
||||
VoxelDataHeader *h=(VoxelDataHeader *)MEM_mallocN(sizeof(VoxelDataHeader), "voxel data header");
|
||||
|
||||
rewind(fp);
|
||||
fread(h,sizeof(VoxelDataHeader),1,fp);
|
||||
|
||||
vd->resol[0]=h->resolX;
|
||||
vd->resol[1]=h->resolY;
|
||||
vd->resol[2]=h->resolZ;
|
||||
|
||||
MEM_freeN(h);
|
||||
}
|
||||
|
||||
void init_frame_smoke(Render *re, VoxelData *vd, Tex *tex)
|
||||
{
|
||||
Object *ob;
|
||||
ModifierData *md;
|
||||
|
||||
vd->dataset = NULL;
|
||||
if (vd->object == NULL) return;
|
||||
ob= vd->object;
|
||||
|
||||
/* draw code for smoke */
|
||||
if(md = (ModifierData *)modifiers_findByType(ob, eModifierType_Smoke))
|
||||
{
|
||||
SmokeModifierData *smd = (SmokeModifierData *)md;
|
||||
|
||||
if(smd->domain && smd->domain->fluid) {
|
||||
//int big = (smd->domain->flags & MOD_SMOKE_HIGHRES);
|
||||
int big=0;
|
||||
|
||||
if (big) {
|
||||
//smoke_turbulence_get_res(smd->domain->wt, vd->resol);
|
||||
//vd->dataset = smoke_turbulence_get_density(smd->domain->wt);
|
||||
} else {
|
||||
VECCOPY(vd->resol, smd->domain->res);
|
||||
vd->dataset = smoke_get_density(smd->domain->fluid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cache_voxeldata(struct Render *re,Tex *tex)
|
||||
{
|
||||
VoxelData *vd = tex->vd;
|
||||
FILE *fp;
|
||||
int size;
|
||||
int curframe;
|
||||
|
||||
if (!vd) return;
|
||||
|
||||
/* image sequence gets special treatment */
|
||||
if (vd->file_format == TEX_VD_IMAGE_SEQUENCE) {
|
||||
load_frame_image_sequence(re, vd, tex);
|
||||
return;
|
||||
} else if (vd->file_format == TEX_VD_SMOKE) {
|
||||
init_frame_smoke(re, vd, tex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!BLI_exists(vd->source_path)) return;
|
||||
fp = fopen(vd->source_path,"rb");
|
||||
if (!fp) return;
|
||||
|
||||
if (vd->file_format == TEX_VD_BLENDERVOXEL)
|
||||
read_voxeldata_header(fp, vd);
|
||||
|
||||
size = (vd->resol[0])*(vd->resol[1])*(vd->resol[2]);
|
||||
vd->dataset = MEM_mapallocN(sizeof(float)*size, "voxel dataset");
|
||||
|
||||
if (vd->flag & TEX_VD_STILL) curframe = vd->still_frame;
|
||||
else curframe = re->r.cfra;
|
||||
|
||||
switch(vd->file_format) {
|
||||
case TEX_VD_BLENDERVOXEL:
|
||||
load_frame_blendervoxel(fp, vd->dataset, size, curframe-1, sizeof(VoxelDataHeader));
|
||||
break;
|
||||
case TEX_VD_RAW_8BIT:
|
||||
load_frame_raw8(fp, vd->dataset, size, curframe);
|
||||
break;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void make_voxeldata(struct Render *re)
|
||||
{
|
||||
Tex *tex;
|
||||
|
||||
if(re->scene->r.scemode & R_PREVIEWBUTS)
|
||||
return;
|
||||
|
||||
re->i.infostr= "Loading voxel datasets";
|
||||
re->stats_draw(re->sdh, &re->i);
|
||||
|
||||
/* XXX: should be doing only textures used in this render */
|
||||
for (tex= G.main->tex.first; tex; tex= tex->id.next) {
|
||||
if(tex->id.us && tex->type==TEX_VOXELDATA) {
|
||||
cache_voxeldata(re, tex);
|
||||
}
|
||||
}
|
||||
|
||||
re->i.infostr= NULL;
|
||||
re->stats_draw(re->sdh, &re->i);
|
||||
|
||||
}
|
||||
|
||||
static void free_voxeldata_one(Render *re, Tex *tex)
|
||||
{
|
||||
VoxelData *vd = tex->vd;
|
||||
|
||||
if (vd->dataset) {
|
||||
MEM_freeN(vd->dataset);
|
||||
vd->dataset = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void free_voxeldata(Render *re)
|
||||
{
|
||||
Tex *tex;
|
||||
|
||||
if(re->scene->r.scemode & R_PREVIEWBUTS)
|
||||
return;
|
||||
|
||||
for (tex= G.main->tex.first; tex; tex= tex->id.next) {
|
||||
if(tex->id.us && tex->type==TEX_VOXELDATA) {
|
||||
free_voxeldata_one(re, tex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int voxeldatatex(struct Tex *tex, float *texvec, struct TexResult *texres)
|
||||
{
|
||||
int retval = TEX_INT;
|
||||
VoxelData *vd = tex->vd;
|
||||
float co[3], offset[3] = {0.5, 0.5, 0.5};
|
||||
|
||||
if ((!vd) || (vd->dataset==NULL)) {
|
||||
texres->tin = 0.0f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* scale lookup from 0.0-1.0 (original location) to -1.0, 1.0, consistent with image texture tex coords */
|
||||
/* in implementation this works backwards, bringing sample locations from -1.0, 1.0
|
||||
* to the range 0.0, 1.0, before looking up in the voxel structure. */
|
||||
VecCopyf(co, texvec);
|
||||
VecMulf(co, 0.5f);
|
||||
VecAddf(co, co, offset);
|
||||
|
||||
/* co is now in the range 0.0, 1.0 */
|
||||
switch (tex->extend) {
|
||||
case TEX_CLIP:
|
||||
{
|
||||
if ((co[0] < 0.f || co[0] > 1.f) || (co[1] < 0.f || co[1] > 1.f) || (co[2] < 0.f || co[2] > 1.f)) {
|
||||
texres->tin = 0.f;
|
||||
return retval;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TEX_REPEAT:
|
||||
{
|
||||
co[0] = co[0] - floor(co[0]);
|
||||
co[1] = co[1] - floor(co[1]);
|
||||
co[2] = co[2] - floor(co[2]);
|
||||
break;
|
||||
}
|
||||
case TEX_EXTEND:
|
||||
{
|
||||
CLAMP(co[0], 0.f, 1.f);
|
||||
CLAMP(co[1], 0.f, 1.f);
|
||||
CLAMP(co[2], 0.f, 1.f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (vd->interp_type) {
|
||||
case TEX_VD_NEARESTNEIGHBOR:
|
||||
texres->tin = voxel_sample_nearest(vd->dataset, vd->resol, co);
|
||||
break;
|
||||
case TEX_VD_LINEAR:
|
||||
texres->tin = voxel_sample_trilinear(vd->dataset, vd->resol, co);
|
||||
break;
|
||||
case TEX_VD_TRICUBIC:
|
||||
texres->tin = voxel_sample_tricubic(vd->dataset, vd->resol, co);
|
||||
break;
|
||||
}
|
||||
|
||||
texres->tin *= vd->int_multiplier;
|
||||
BRICONT;
|
||||
|
||||
texres->tr = texres->tin;
|
||||
texres->tg = texres->tin;
|
||||
texres->tb = texres->tin;
|
||||
texres->ta = texres->tin;
|
||||
BRICONTRGB;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user