Particles

=========

- Normalize strand coordinates over the length of the strand, not
  cut off when with e.g. length texture control.
- Weight paint and particle mode x-mirror now works with deformation
  and shape keys active.
- X-ray is now disabled in particle mode, messed up depth tests.
This commit is contained in:
Brecht Van Lommel 2007-12-06 17:43:47 +00:00
parent ff52c8f2d6
commit 51322964f4
8 changed files with 151 additions and 62 deletions

@ -265,6 +265,7 @@ void psys_vec_rot_to_face(struct DerivedMesh *dm, struct ParticleData *pa, float
//void psys_vec_rot_from_face(struct DerivedMesh *dm, struct ParticleData *pa, float *vec); //void psys_vec_rot_from_face(struct DerivedMesh *dm, struct ParticleData *pa, float *vec);
void psys_mat_hair_to_object(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[][4]); void psys_mat_hair_to_object(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[][4]);
void psys_mat_hair_to_global(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[][4]); void psys_mat_hair_to_global(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[][4]);
void psys_mat_hair_to_orco(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[][4]);
float *psys_cache_vgroup(struct DerivedMesh *dm, struct ParticleSystem *psys, int vgroup); float *psys_cache_vgroup(struct DerivedMesh *dm, struct ParticleSystem *psys, int vgroup);
void psys_get_texture(struct Object *ob, struct Material *ma, struct ParticleSystemModifierData *psmd, struct ParticleSystem *psys, struct ParticleData *pa, struct ParticleTexture *ptex, int event); void psys_get_texture(struct Object *ob, struct Material *ma, struct ParticleSystemModifierData *psmd, struct ParticleSystem *psys, struct ParticleData *pa, struct ParticleTexture *ptex, int event);

@ -2482,7 +2482,7 @@ static void mesh_build_data(Object *ob, CustomDataMask dataMask)
ob->derivedFinal->getMinMax(ob->derivedFinal, min, max); ob->derivedFinal->getMinMax(ob->derivedFinal, min, max);
if(!ob->bb) if(!ob->bb)
ob->bb= MEM_mallocN(sizeof(BoundBox), "bb"); ob->bb= MEM_callocN(sizeof(BoundBox), "bb");
boundbox_set_from_min_max(ob->bb, min, max); boundbox_set_from_min_max(ob->bb, min, max);
ob->derivedFinal->needsFree = 0; ob->derivedFinal->needsFree = 0;
@ -2520,7 +2520,7 @@ static void editmesh_build_data(CustomDataMask dataMask)
em->derivedFinal->getMinMax(em->derivedFinal, min, max); em->derivedFinal->getMinMax(em->derivedFinal, min, max);
if(!G.obedit->bb) if(!G.obedit->bb)
G.obedit->bb= MEM_mallocN(sizeof(BoundBox), "bb"); G.obedit->bb= MEM_callocN(sizeof(BoundBox), "bb");
boundbox_set_from_min_max(G.obedit->bb, min, max); boundbox_set_from_min_max(G.obedit->bb, min, max);
em->derivedFinal->needsFree = 0; em->derivedFinal->needsFree = 0;

@ -2240,33 +2240,52 @@ static void triatomat(float *v1, float *v2, float *v3, float (*uv)[2], float mat
Crossf(mat[0], mat[1], mat[2]); Crossf(mat[0], mat[1], mat[2]);
} }
static void psys_face_mat(DerivedMesh *dm, ParticleData *pa, float mat[][4]) static void psys_face_mat(DerivedMesh *dm, ParticleData *pa, float mat[][4], int orco)
{ {
float v1[3], v2[3], v3[3]; float v1[3], v2[3], v3[3];
MFace *mface; MFace *mface;
OrigSpaceFace *osface; OrigSpaceFace *osface;
float (*orcodata)[3];
int i = pa->num_dmcache==DMCACHE_NOTFOUND ? pa->num : pa->num_dmcache; int i = pa->num_dmcache==DMCACHE_NOTFOUND ? pa->num : pa->num_dmcache;
if (i==-1 || i >= dm->getNumFaces(dm)) { Mat4One(mat); return; } if (i==-1 || i >= dm->getNumFaces(dm)) { Mat4One(mat); return; }
mface=dm->getFaceData(dm,i,CD_MFACE); mface=dm->getFaceData(dm,i,CD_MFACE);
osface=dm->getFaceData(dm,i,CD_ORIGSPACE); osface=dm->getFaceData(dm,i,CD_ORIGSPACE);
dm->getVertCo(dm,mface->v1,v1); if(orco && (orcodata=dm->getVertDataArray(dm, CD_ORCO))) {
dm->getVertCo(dm,mface->v2,v2); VECCOPY(v1, orcodata[mface->v1]);
dm->getVertCo(dm,mface->v3,v3); VECCOPY(v2, orcodata[mface->v2]);
VECCOPY(v3, orcodata[mface->v3]);
}
else {
dm->getVertCo(dm,mface->v1,v1);
dm->getVertCo(dm,mface->v2,v2);
dm->getVertCo(dm,mface->v3,v3);
}
triatomat(v1, v2, v3, (osface)? osface->uv: NULL, mat); triatomat(v1, v2, v3, (osface)? osface->uv: NULL, mat);
} }
void psys_mat_hair_to_object(Object *ob, DerivedMesh *dm, short from, ParticleData *pa, float hairmat[][4]) void psys_mat_hair_to_object(Object *ob, DerivedMesh *dm, short from, ParticleData *pa, float hairmat[][4])
{ {
float vec[3]; float vec[3];
psys_face_mat(dm, pa, hairmat); psys_face_mat(dm, pa, hairmat, 0);
psys_particle_on_dm(ob, dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, 0, 0); psys_particle_on_dm(ob, dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, 0, 0);
VECCOPY(hairmat[3],vec); VECCOPY(hairmat[3],vec);
} }
void psys_mat_hair_to_orco(Object *ob, DerivedMesh *dm, short from, ParticleData *pa, float hairmat[][4])
{
float vec[3], orco[3];
psys_face_mat(dm, pa, hairmat, 1);
psys_particle_on_dm(ob, dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, orco, 0);
VECCOPY(hairmat[3],orco);
}
/* /*
void psys_key_to_geometry(DerivedMesh *dm, ParticleData *pa, ParticleKey *key) void psys_key_to_geometry(DerivedMesh *dm, ParticleData *pa, ParticleKey *key)
{ {
@ -2319,7 +2338,7 @@ void psys_vec_rot_to_face(DerivedMesh *dm, ParticleData *pa, float *vec)//to_geo
{ {
float mat[4][4]; float mat[4][4];
psys_face_mat(dm, pa, mat); psys_face_mat(dm, pa, mat, 0);
Mat4Transp(mat); /* cheap inverse for rotation matrix */ Mat4Transp(mat); /* cheap inverse for rotation matrix */
Mat4Mul3Vecfl(mat, vec); Mat4Mul3Vecfl(mat, vec);
} }

@ -1734,7 +1734,7 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
StrandRen *strand=0; StrandRen *strand=0;
RNG *rng= 0; RNG *rng= 0;
float loc[3],loc1[3],loc0[3],vel[3],mat[4][4],nmat[3][3],co[3],nor[3],time; float loc[3],loc1[3],loc0[3],vel[3],mat[4][4],nmat[3][3],co[3],nor[3],time;
float *orco=0,*surfnor=0,*uvco=0; float *orco=0,*surfnor=0,*uvco=0, strandlen=0.0f, curlen=0.0f;
float hasize, pa_size, pa_time, r_tilt, cfra=bsystem_time(ob,(float)CFRA,0.0); float hasize, pa_size, pa_time, r_tilt, cfra=bsystem_time(ob,(float)CFRA,0.0);
float loc_tex[3], size_tex[3], adapt_angle=0.0, adapt_pix=0.0, random; float loc_tex[3], size_tex[3], adapt_angle=0.0, adapt_pix=0.0, random;
int i, a, k, max_k=0, totpart, totvlako, totverto, totuv=0, override_uv=-1; int i, a, k, max_k=0, totpart, totvlako, totverto, totuv=0, override_uv=-1;
@ -2043,6 +2043,7 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
orco[2] = (orco[2]-loc_tex[2])/size_tex[2]; orco[2] = (orco[2]-loc_tex[2])/size_tex[2];
} }
/* surface normal shading setup */
if(ma->mode_l & MA_STR_SURFDIFF) { if(ma->mode_l & MA_STR_SURFDIFF) {
Mat3MulVecfl(nmat, nor); Mat3MulVecfl(nmat, nor);
surfnor= nor; surfnor= nor;
@ -2050,7 +2051,8 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
else else
surfnor= NULL; surfnor= NULL;
if(strandbuf) { /* strand render */ /* strand render setup */
if(strandbuf) {
strand= RE_findOrAddStrand(re, re->totstrand++); strand= RE_findOrAddStrand(re, re->totstrand++);
strand->buffer= strandbuf; strand->buffer= strandbuf;
strand->vert= svert; strand->vert= svert;
@ -2073,9 +2075,17 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
} }
} }
/* strandco computation setup */
if(path_nbr) {
strandlen= 0.0f;
curlen= 0.0f;
for(k=1; k<=path_nbr; k++)
if(k<=max_k)
strandlen += VecLenf((cache+k-1)->co, (cache+k)->co);
}
for(k=0; k<=path_nbr; k++){ for(k=0; k<=path_nbr; k++){
if(path_nbr){ if(path_nbr){
time=(float)k/(float)path_nbr;
if(k<=max_k){ if(k<=max_k){
//bti->convert_bake_key(bsys,cache+k,0,(void*)&state); //bti->convert_bake_key(bsys,cache+k,0,(void*)&state);
//copy_particle_key(&state,cache+k,0); //copy_particle_key(&state,cache+k,0);
@ -2084,6 +2094,10 @@ static int render_new_particle_system(Render *re, Object *ob, ParticleSystem *ps
} }
else else
continue; continue;
if(k > 0)
curlen += VecLenf((cache+k-1)->co, (cache+k)->co);
time= curlen/strandlen;
} }
else{ else{
time=0.0f; time=0.0f;

@ -548,11 +548,11 @@ float *RE_strandren_get_uv(Render *re, StrandRen *strand, int n, char **name, in
float **uv= node->uv; float **uv= node->uv;
int size= (n+1)*256; int size= (n+1)*256;
node->uv= MEM_callocN(size*sizeof(MCol*), "Strand uv"); node->uv= MEM_callocN(size*sizeof(float*), "Strand uv");
if(uv) { if(uv) {
size= node->totuv*256; size= node->totuv*256;
memcpy(node->uv, uv, size*sizeof(MCol*)); memcpy(node->uv, uv, size*sizeof(float*));
MEM_freeN(uv); MEM_freeN(uv);
} }

@ -4706,10 +4706,13 @@ void draw_object(Base *base, int flag)
/* xray delay? */ /* xray delay? */
if((flag & DRAW_PICKING)==0 && (base->flag & OB_FROMDUPLI)==0) { if((flag & DRAW_PICKING)==0 && (base->flag & OB_FROMDUPLI)==0) {
/* xray and transp are set when it is drawing the 2nd/3rd pass */ /* don't do xray in particle mode, need the z-buffer */
if(!G.vd->xray && !G.vd->transp && (ob->dtx & OB_DRAWXRAY)) { if(!(G.f & G_PARTICLEEDIT)) {
add_view3d_after(G.vd, base, V3D_XRAY); /* xray and transp are set when it is drawing the 2nd/3rd pass */
return; if(!G.vd->xray && !G.vd->transp && (ob->dtx & OB_DRAWXRAY)) {
add_view3d_after(G.vd, base, V3D_XRAY);
return;
}
} }
} }

@ -546,7 +546,7 @@ static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
/* insert particles into kd tree */ /* insert particles into kd tree */
LOOP_PARTICLES(i,pa) { LOOP_PARTICLES(i,pa) {
psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, pa, mat); psys_mat_hair_to_orco(ob, psmd->dm, psys->part->from, pa, mat);
VECCOPY(co, pa->hair[0].co); VECCOPY(co, pa->hair[0].co);
Mat4MulVecfl(mat, co); Mat4MulVecfl(mat, co);
BLI_kdtree_insert(tree, i, co, NULL); BLI_kdtree_insert(tree, i, co, NULL);
@ -559,7 +559,7 @@ static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
edit->mirror_cache= MEM_callocN(sizeof(int)*totpart, "PE mirror cache"); edit->mirror_cache= MEM_callocN(sizeof(int)*totpart, "PE mirror cache");
LOOP_PARTICLES(i,pa) { LOOP_PARTICLES(i,pa) {
psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, pa, mat); psys_mat_hair_to_orco(ob, psmd->dm, psys->part->from, pa, mat);
VECCOPY(co, pa->hair[0].co); VECCOPY(co, pa->hair[0].co);
Mat4MulVecfl(mat, co); Mat4MulVecfl(mat, co);
co[0]= -co[0]; co[0]= -co[0];
@ -628,8 +628,8 @@ static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys
} }
/* mirror positions and tags */ /* mirror positions and tags */
psys_mat_hair_to_object(ob, dm, psys->part->from, pa, mat); psys_mat_hair_to_orco(ob, dm, psys->part->from, pa, mat);
psys_mat_hair_to_object(ob, dm, psys->part->from, mpa, mmat); psys_mat_hair_to_orco(ob, dm, psys->part->from, mpa, mmat);
Mat4Invert(immat, mmat); Mat4Invert(immat, mmat);
hkey=pa->hair; hkey=pa->hair;

@ -686,7 +686,7 @@ static void mesh_octree_add_nodes(MocNode **basetable, float *co, float *offs, f
} }
static long mesh_octree_find_index(MocNode **bt, MVert *mvert, float *co) static long mesh_octree_find_index(MocNode **bt, float (*orco)[3], MVert *mvert, float *co)
{ {
float *vec; float *vec;
int a; int a;
@ -697,7 +697,12 @@ static long mesh_octree_find_index(MocNode **bt, MVert *mvert, float *co)
for(a=0; a<MOC_NODE_RES; a++) { for(a=0; a<MOC_NODE_RES; a++) {
if((*bt)->index[a]) { if((*bt)->index[a]) {
/* does mesh verts and editmode, code looks potential dangerous, octree should really be filled OK! */ /* does mesh verts and editmode, code looks potential dangerous, octree should really be filled OK! */
if(mvert) { if(orco) {
vec= orco[(*bt)->index[a]-1];
if(FloatCompare(vec, co, MOC_THRESH))
return (*bt)->index[a]-1;
}
else if(mvert) {
vec= (mvert+(*bt)->index[a]-1)->co; vec= (mvert+(*bt)->index[a]-1)->co;
if(FloatCompare(vec, co, MOC_THRESH)) if(FloatCompare(vec, co, MOC_THRESH))
return (*bt)->index[a]-1; return (*bt)->index[a]-1;
@ -711,84 +716,116 @@ static long mesh_octree_find_index(MocNode **bt, MVert *mvert, float *co)
else return -1; else return -1;
} }
if( (*bt)->next) if( (*bt)->next)
return mesh_octree_find_index(&(*bt)->next, mvert, co); return mesh_octree_find_index(&(*bt)->next, orco, mvert, co);
return -1; return -1;
} }
static struct {
MocNode **table;
float offs[3], div[3];
float (*orco)[3];
} MeshOctree = {NULL, {0, 0, 0}, {0, 0, 0}, NULL};
/* mode is 's' start, or 'e' end, or 'u' use */ /* mode is 's' start, or 'e' end, or 'u' use */
/* if end, ob can be NULL */ /* if end, ob can be NULL */
long mesh_octree_table(Object *ob, float *co, char mode) long mesh_octree_table(Object *ob, float *co, char mode)
{ {
MocNode **bt; MocNode **bt;
static MocNode **basetable= NULL;
static float offs[3], div[3];
if(mode=='u') { /* use table */ if(mode=='u') { /* use table */
if(basetable==NULL) if(MeshOctree.table==NULL)
mesh_octree_table(ob, NULL, 's'); mesh_octree_table(ob, NULL, 's');
if(basetable) { if(MeshOctree.table) {
Mesh *me= ob->data; Mesh *me= ob->data;
bt= basetable + mesh_octree_get_base_offs(co, offs, div); bt= MeshOctree.table + mesh_octree_get_base_offs(co, MeshOctree.offs, MeshOctree.div);
if(ob==G.obedit) if(ob==G.obedit)
return mesh_octree_find_index(bt, NULL, co); return mesh_octree_find_index(bt, NULL, NULL, co);
else else
return mesh_octree_find_index(bt, me->mvert, co); return mesh_octree_find_index(bt, MeshOctree.orco, me->mvert, co);
} }
return -1; return -1;
} }
else if(mode=='s') { /* start table */ else if(mode=='s') { /* start table */
Mesh *me= ob->data; Mesh *me= ob->data;
BoundBox *bb = mesh_get_bb(ob); float min[3], max[3];
/* we compute own bounding box and don't reuse ob->bb because
* we are using the undeformed coordinates*/
INIT_MINMAX(min, max);
if(ob==G.obedit) {
EditVert *eve;
for(eve= G.editMesh->verts.first; eve; eve= eve->next)
DO_MINMAX(eve->co, min, max)
}
else {
MVert *mvert;
float *co;
int a, totvert;
MeshOctree.orco= mesh_getRefKeyCos(me, &totvert);
for(a=0, mvert= me->mvert; a<me->totvert; a++, mvert++) {
co= (MeshOctree.orco)? MeshOctree.orco[a]: mvert->co;
DO_MINMAX(co, min, max);
}
}
/* for quick unit coordinate calculus */ /* for quick unit coordinate calculus */
VECCOPY(offs, bb->vec[0]); VECCOPY(MeshOctree.offs, min);
offs[0]-= MOC_THRESH; /* we offset it 1 threshold unit extra */ MeshOctree.offs[0]-= MOC_THRESH; /* we offset it 1 threshold unit extra */
offs[1]-= MOC_THRESH; MeshOctree.offs[1]-= MOC_THRESH;
offs[2]-= MOC_THRESH; MeshOctree.offs[2]-= MOC_THRESH;
VecSubf(div, bb->vec[6], bb->vec[0]);
div[0]+= 2*MOC_THRESH; /* and divide with 2 threshold unit more extra (try 8x8 unit grid on paint) */
div[1]+= 2*MOC_THRESH;
div[2]+= 2*MOC_THRESH;
VecMulf(div, 1.0f/MOC_RES); VecSubf(MeshOctree.div, max, min);
if(div[0]==0.0f) div[0]= 1.0f; MeshOctree.div[0]+= 2*MOC_THRESH; /* and divide with 2 threshold unit more extra (try 8x8 unit grid on paint) */
if(div[1]==0.0f) div[1]= 1.0f; MeshOctree.div[1]+= 2*MOC_THRESH;
if(div[2]==0.0f) div[2]= 1.0f; MeshOctree.div[2]+= 2*MOC_THRESH;
VecMulf(MeshOctree.div, 1.0f/MOC_RES);
if(MeshOctree.div[0]==0.0f) MeshOctree.div[0]= 1.0f;
if(MeshOctree.div[1]==0.0f) MeshOctree.div[1]= 1.0f;
if(MeshOctree.div[2]==0.0f) MeshOctree.div[2]= 1.0f;
if(basetable) /* happens when entering this call without ending it */ if(MeshOctree.table) /* happens when entering this call without ending it */
mesh_octree_table(ob, co, 'e'); mesh_octree_table(ob, co, 'e');
basetable= MEM_callocN(MOC_RES*MOC_RES*MOC_RES*sizeof(void *), "sym table"); MeshOctree.table= MEM_callocN(MOC_RES*MOC_RES*MOC_RES*sizeof(void *), "sym table");
if(ob==G.obedit) { if(ob==G.obedit) {
EditVert *eve; EditVert *eve;
for(eve= G.editMesh->verts.first; eve; eve= eve->next) { for(eve= G.editMesh->verts.first; eve; eve= eve->next) {
mesh_octree_add_nodes(basetable, eve->co, offs, div, (long)(eve)); mesh_octree_add_nodes(MeshOctree.table, eve->co, MeshOctree.offs, MeshOctree.div, (long)(eve));
} }
} }
else { else {
MVert *mvert; MVert *mvert;
long a; float *co;
int a;
for(a=1, mvert= me->mvert; a<=me->totvert; a++, mvert++) { for(a=0, mvert= me->mvert; a<me->totvert; a++, mvert++) {
mesh_octree_add_nodes(basetable, mvert->co, offs, div, a); co= (MeshOctree.orco)? MeshOctree.orco[a]: mvert->co;
mesh_octree_add_nodes(MeshOctree.table, co, MeshOctree.offs, MeshOctree.div, a+1);
} }
} }
} }
else if(mode=='e') { /* end table */ else if(mode=='e') { /* end table */
if(basetable) { if(MeshOctree.table) {
int a; int a;
for(a=0, bt=basetable; a<MOC_RES*MOC_RES*MOC_RES; a++, bt++) { for(a=0, bt=MeshOctree.table; a<MOC_RES*MOC_RES*MOC_RES; a++, bt++) {
if(*bt) mesh_octree_free_node(bt); if(*bt) mesh_octree_free_node(bt);
} }
MEM_freeN(basetable); MEM_freeN(MeshOctree.table);
basetable= NULL; MeshOctree.table= NULL;
}
if(MeshOctree.orco) {
MEM_freeN(MeshOctree.orco);
MeshOctree.orco= NULL;
} }
} }
return 0; return 0;
@ -797,12 +834,20 @@ long mesh_octree_table(Object *ob, float *co, char mode)
int mesh_get_x_mirror_vert(Object *ob, int index) int mesh_get_x_mirror_vert(Object *ob, int index)
{ {
Mesh *me= ob->data; Mesh *me= ob->data;
MVert *mvert= me->mvert+index; MVert *mvert;
float vec[3]; float vec[3];
vec[0]= -mvert->co[0]; if(MeshOctree.orco) {
vec[1]= mvert->co[1]; vec[0]= -MeshOctree.orco[index][0];
vec[2]= mvert->co[2]; vec[1]= MeshOctree.orco[index][1];
vec[2]= MeshOctree.orco[index][2];
}
else {
mvert= me->mvert+index;
vec[0]= -mvert->co[0];
vec[1]= mvert->co[1];
vec[2]= mvert->co[2];
}
return mesh_octree_table(ob, vec, 'u'); return mesh_octree_table(ob, vec, 'u');
} }
@ -884,9 +929,16 @@ int *mesh_get_x_mirror_faces(Object *ob)
mesh_octree_table(ob, NULL, 's'); mesh_octree_table(ob, NULL, 's');
for(a=0, mv=mvert; a<me->totvert; a++, mv++) { for(a=0, mv=mvert; a<me->totvert; a++, mv++) {
vec[0]= -mv->co[0]; if(MeshOctree.orco) {
vec[1]= mv->co[1]; vec[0]= -MeshOctree.orco[a][0];
vec[2]= mv->co[2]; vec[1]= MeshOctree.orco[a][1];
vec[2]= MeshOctree.orco[a][2];
}
else {
vec[0]= -mv->co[0];
vec[1]= mv->co[1];
vec[2]= mv->co[2];
}
mirrorverts[a]= mesh_octree_table(ob, vec, 'u'); mirrorverts[a]= mesh_octree_table(ob, vec, 'u');
} }