Commit: 5f6d9e301efc5f9627941c71ba0f464901e71a4e Author: Lukas Tönne Date: Fri Aug 21 15:13:17 2015 +0200 Branches: strand_gpu https://developer.blender.org/rB5f6d9e301efc5f9627941c71ba0f464901e71a4e
Implementation of Volume Sampling on meshes. Based on the ray casting technique described here: http://www.joesfer.com/?p=84 Volume samples currently are not bound to mesh deformation in any way, they are simple object-space locations. Potentially a harmonic weight approach as in mesh cages could be used. =================================================================== M source/blender/blenkernel/BKE_mesh_sample.h M source/blender/blenkernel/intern/mesh_sample.c M source/blender/makesdna/DNA_meshdata_types.h M source/blender/makesrna/intern/CMakeLists.txt M source/blender/makesrna/intern/makesrna.c M source/blender/makesrna/intern/rna_internal.h D source/blender/makesrna/intern/rna_mesh_sample.c =================================================================== diff --git a/source/blender/blenkernel/BKE_mesh_sample.h b/source/blender/blenkernel/BKE_mesh_sample.h index 9e34441..3b2e1e1 100644 --- a/source/blender/blenkernel/BKE_mesh_sample.h +++ b/source/blender/blenkernel/BKE_mesh_sample.h @@ -28,32 +28,37 @@ struct DerivedMesh; struct Key; struct KeyBlock; +struct MFace; +struct MVert; -struct MSurfaceSample; +struct MeshSample; +struct MeshSampleGenerator; + +typedef struct MeshSampleGenerator MeshSampleGenerator; +typedef float (*MeshSampleVertexWeightFp)(struct DerivedMesh *dm, struct MVert *vert, unsigned int index, void *userdata); +typedef bool (*MeshSampleRayFp)(void *userdata, float ray_start[3], float ray_end[3]); /* ==== Evaluate ==== */ -bool BKE_mesh_sample_eval(struct DerivedMesh *dm, const struct MSurfaceSample *sample, float loc[3], float nor[3]); -bool BKE_mesh_sample_shapekey(struct Key *key, struct KeyBlock *kb, const struct MSurfaceSample *sample, float loc[3]); +bool BKE_mesh_sample_is_volume_sample(const struct MeshSample *sample); + +bool BKE_mesh_sample_eval(struct DerivedMesh *dm, const struct MeshSample *sample, float loc[3], float nor[3], float tang[3]); +bool BKE_mesh_sample_shapekey(struct Key *key, struct KeyBlock *kb, const struct MeshSample *sample, float loc[3]); /* ==== Sampling ==== */ -/* Storage descriptor to allow generic data storage by arbitrary algorithms */ -typedef struct MSurfaceSampleStorage { - bool (*store_sample)(void *data, int capacity, int index, const struct MSurfaceSample *sample); - void *data; - int capacity; - int free_data; -} MSurfaceSampleStorage; +/* face_weights is optional */ +struct MeshSampleGenerator *BKE_mesh_sample_gen_surface_random(struct DerivedMesh *dm, unsigned int seed); +struct MeshSampleGenerator *BKE_mesh_sample_gen_surface_random_ex(struct DerivedMesh *dm, unsigned int seed, + MeshSampleVertexWeightFp vertex_weight_cb, void *userdata, bool use_facearea); + +struct MeshSampleGenerator *BKE_mesh_sample_gen_surface_raycast(struct DerivedMesh *dm, MeshSampleRayFp ray_cb, void *userdata); -void BKE_mesh_sample_storage_single(struct MSurfaceSampleStorage *storage, struct MSurfaceSample *sample); -void BKE_mesh_sample_storage_array(struct MSurfaceSampleStorage *storage, struct MSurfaceSample *samples, int capacity); -void BKE_mesh_sample_storage_release(struct MSurfaceSampleStorage *storage); +struct MeshSampleGenerator *BKE_mesh_sample_gen_volume_random_bbray(struct DerivedMesh *dm, unsigned int seed, float density); -int BKE_mesh_sample_generate_random(struct MSurfaceSampleStorage *dst, struct DerivedMesh *dm, unsigned int seed, int totsample); +void BKE_mesh_sample_free_generator(struct MeshSampleGenerator *gen); -typedef bool (*MeshSampleRayCallback)(void *userdata, float ray_start[3], float ray_end[3]); -int BKE_mesh_sample_generate_raycast(struct MSurfaceSampleStorage *dst, struct DerivedMesh *dm, MeshSampleRayCallback ray_cb, void *userdata, int totsample); +bool BKE_mesh_sample_generate(struct MeshSampleGenerator *gen, struct MeshSample *sample); #endif /* __BKE_MESH_SAMPLE_H__ */ diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c index ae49668..537b565 100644 --- a/source/blender/blenkernel/intern/mesh_sample.c +++ b/source/blender/blenkernel/intern/mesh_sample.c @@ -43,45 +43,80 @@ /* ==== Evaluate ==== */ -bool BKE_mesh_sample_eval(DerivedMesh *dm, const MSurfaceSample *sample, float loc[3], float nor[3]) +bool BKE_mesh_sample_is_volume_sample(const MeshSample *sample) +{ + return sample->orig_verts[0] == 0 && sample->orig_verts[1] == 0; +} + +bool BKE_mesh_sample_eval(DerivedMesh *dm, const MeshSample *sample, float loc[3], float nor[3], float tang[3]) { MVert *mverts = dm->getVertArray(dm); unsigned int totverts = (unsigned int)dm->getNumVerts(dm); MVert *v1, *v2, *v3; - float vnor[3]; zero_v3(loc); zero_v3(nor); + zero_v3(tang); - if (sample->orig_verts[0] >= totverts || - sample->orig_verts[1] >= totverts || - sample->orig_verts[2] >= totverts) - return false; - - v1 = &mverts[sample->orig_verts[0]]; - v2 = &mverts[sample->orig_verts[1]]; - v3 = &mverts[sample->orig_verts[2]]; - - madd_v3_v3fl(loc, v1->co, sample->orig_weights[0]); - madd_v3_v3fl(loc, v2->co, sample->orig_weights[1]); - madd_v3_v3fl(loc, v3->co, sample->orig_weights[2]); - - normal_short_to_float_v3(vnor, v1->no); - madd_v3_v3fl(nor, vnor, sample->orig_weights[0]); - normal_short_to_float_v3(vnor, v2->no); - madd_v3_v3fl(nor, vnor, sample->orig_weights[1]); - normal_short_to_float_v3(vnor, v3->no); - madd_v3_v3fl(nor, vnor, sample->orig_weights[2]); - - normalize_v3(nor); + if (BKE_mesh_sample_is_volume_sample(sample)) { + /* VOLUME SAMPLE */ + copy_v3_v3(loc, sample->orig_weights); + } + else { + /* SURFACE SAMPLE */ + if (sample->orig_verts[0] >= totverts || + sample->orig_verts[1] >= totverts || + sample->orig_verts[2] >= totverts) + return false; + + v1 = &mverts[sample->orig_verts[0]]; + v2 = &mverts[sample->orig_verts[1]]; + v3 = &mverts[sample->orig_verts[2]]; + + { /* location */ + madd_v3_v3fl(loc, v1->co, sample->orig_weights[0]); + madd_v3_v3fl(loc, v2->co, sample->orig_weights[1]); + madd_v3_v3fl(loc, v3->co, sample->orig_weights[2]); + } + + { /* normal */ + float vnor[3]; + + normal_short_to_float_v3(vnor, v1->no); + madd_v3_v3fl(nor, vnor, sample->orig_weights[0]); + normal_short_to_float_v3(vnor, v2->no); + madd_v3_v3fl(nor, vnor, sample->orig_weights[1]); + normal_short_to_float_v3(vnor, v3->no); + madd_v3_v3fl(nor, vnor, sample->orig_weights[2]); + + normalize_v3(nor); + } + + { /* tangent */ + float edge[3]; + + /* XXX simply using the v1-v2 edge as a tangent vector for now ... + * Eventually mikktspace generated tangents (CD_TANGENT tessface layer) + * should be used for consistency, but requires well-defined tessface + * indices for the mesh surface samples. + */ + + sub_v3_v3v3(edge, v2->co, v1->co); + /* make edge orthogonal to nor */ + madd_v3_v3fl(edge, nor, -dot_v3v3(edge, nor)); + normalize_v3_v3(tang, edge); + } + } return true; } -bool BKE_mesh_sample_shapekey(Key *key, KeyBlock *kb, const MSurfaceSample *sample, float loc[3]) +bool BKE_mesh_sample_shapekey(Key *key, KeyBlock *kb, const MeshSample *sample, float loc[3]) { float *v1, *v2, *v3; - + + (void)key; /* Unused in release builds. */ + BLI_assert(key->elemsize == 3 * sizeof(float)); BLI_assert(sample->orig_verts[0] < (unsigned int)kb->totelem); BLI_assert(sample->orig_verts[1] < (unsigned int)kb->totelem); @@ -103,7 +138,7 @@ bool BKE_mesh_sample_shapekey(Key *key, KeyBlock *kb, const MSurfaceSample *samp /* ==== Sampling Utilities ==== */ -BLI_INLINE void mesh_sample_weights_from_loc(MSurfaceSample *sample, DerivedMesh *dm, int face_index, const float loc[3]) +BLI_INLINE void mesh_sample_weights_from_loc(MeshSample *sample, DerivedMesh *dm, int face_index, const float loc[3]) { MFace *face = &dm->getTessFaceArray(dm)[face_index]; unsigned int index[4] = { face->v1, face->v2, face->v3, face->v4 }; @@ -128,108 +163,278 @@ BLI_INLINE void mesh_sample_weights_from_loc(MSurfaceSample *sample, DerivedMesh /* ==== Sampling ==== */ -static bool mesh_sample_store_array_sample(void *vdata, int capacity, int index, const MSurfaceSample *sample) +typedef void (*GeneratorFreeFp)(struct MeshSampleGenerator *gen); +typedef bool (*GeneratorMakeSampleFp)(struct MeshSampleGenerator *gen, struct MeshSample *sample); + +typedef struct MeshSampleGenerator { - MSurfaceSample *data = vdata; - if (index >= capacity) - return false; - - data[index] = *sample; - return true; -} + GeneratorFreeFp free; + GeneratorMakeSampleFp make_sample; +} MeshSampleGenerator; -void BKE_mesh_sample_storage_single(MSurfaceSampleStorage *storage, MSurfaceSample *sample) +static void sample_generator_init(MeshSampleGenerator *gen, GeneratorFreeFp free, GeneratorMakeSampleFp make_sample) { - /* handled as just a special array case with capacity = 1 */ - storage->store_sample = mesh_sample_store_array_sample; - storage->capacity = 1; - storage->data = sample; - storage->free_data = false; + gen->free = free; + gen->make_sample = make_sample; } -void BKE_mesh_sample_storage_array(MSurfaceSampleStorage *storage, MSurfaceSample *samples, int capacity) +/* ------------------------------------------------------------------------- */ + +//#define USE_DEBUG_COUNT + +typedef struct MSurfaceSampleGenerator_Random { + MeshSampleGenerator base; + + DerivedMesh *dm; + RNG *rng; + float *face_weights; + float *vertex_weights; + +#ifdef USE_DEBUG_COUNT + int *debug_count; +#endif +} MSurfaceSampleGenerator_Random; + +static void generator_random_free(MSurfaceSampleGenerator_Random *gen) { - storage->store_sample = mesh_sample_store_array_sample; - storage->capacity = capacity; - storage->data = samples; - storage->free_data = false; +#ifdef USE_DEBUG_COUNT + if (gen->debug_count) { + if (gen->face_weights) { + int num = gen->dm->getNumTessFaces(gen->dm); + int i; + int totsamples = 0; + + printf("Surface Sampling (n=%d):\n", num); + for (i = 0; i < num; ++i) + totsamples += gen->debug_count[i]; + + for (i = 0; i < num; ++i) { + float weight = i > 0 ? gen->face_weights[i] - gen->face_weights[i-1] : gen->face_weights[i]; + int samples = gen->debug_count[i]; + printf(" %d: W = %f, N = %d/%d = %f\n", i, weight, samples, totsamples, (float)samples / (float)totsamples); + } + } + MEM_freeN(gen->debug_count); + } +#endif + if (gen->face_weights) + MEM_freeN(gen->face_weights); + if (gen->vertex_weights) + MEM_freeN(gen->vertex_weights); + if (gen->rng) + BLI_rng_free(gen->rng); + MEM_freeN(gen); } -void BKE_mesh_sample_storage_release(MSurfaceSampleStorage *storage) +/* Find the index in "sum" array before "value" is crossed. */ +BLI_INLINE int weight_array_binary_search(const float *sum, int size, float value) { - if (storage->free_data) - MEM_freeN(storage->data); + int mid, low = 0, high = size - 1; + + if (value <= 0.0f) + return 0; + + while (low < high) { + mid = @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list [email protected] https://lists.blender.org/mailman/listinfo/bf-blender-cvs
