Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/particle.c')
-rw-r--r--source/blender/blenkernel/intern/particle.c308
1 files changed, 298 insertions, 10 deletions
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 85ac809bf70..32f1795747a 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -295,7 +295,6 @@ void free_keyed_keys(ParticleSystem *psys)
}
void free_child_path_cache(ParticleSystem *psys)
{
-
if(psys->childcache){
if(psys->childcache[0])
MEM_freeN(psys->childcache[0]);
@@ -363,28 +362,98 @@ void psys_free(Object *ob, ParticleSystem * psys)
}
}
-/* these two functions move away particle data and bring it back after
+/* these functions move away particle data and bring it back after
* rendering, to make different render settings possible without
* removing the previous data. this should be solved properly once */
-typedef struct ParticleRenderDataup {
+typedef struct ParticleRenderElem {
+ int curchild, totchild;
+ float lambda, t, scalemin, scalemax;
+} ParticleRenderElem;
+
+typedef struct ParticleRenderData {
ChildParticle *child;
ParticleCacheKey **pathcache;
ParticleCacheKey **childcache;
int totchild, totcached, totchildcache;
DerivedMesh *dm;
int totdmvert, totdmedge, totdmface;
-} ParticleRenderDataup;
-void psys_particles_to_render_backup(Object *ob, ParticleSystem *psys)
+ float mat[4][4];
+ float viewmat[4][4], winmat[4][4];
+ int winx, winy;
+
+ int dosimplify;
+ ParticleRenderElem *elems;
+ int *origindex;
+} ParticleRenderData;
+
+static float psys_render_viewport_falloff(double rate, float dist, float width)
+{
+ return pow(rate, dist/width);
+}
+
+static float psys_render_projected_area(ParticleSystem *psys, float *center, float area, double vprate, float *viewport)
+{
+ ParticleRenderData *data= psys->renderdata;
+ float co[3], view[3], ortho1[3], ortho2[2], w, dx, dy, radius;
+
+ /* transform to view space */
+ VECCOPY(co, center);
+ co[3]= 1.0f;
+ Mat4MulVec4fl(data->viewmat, co);
+
+ /* compute two vectors orthogonal to view vector */
+ VECCOPY(view, co);
+ Normalize(view);
+ VecOrthoBasisf(view, ortho1, ortho2);
+
+ /* compute on screen minification */
+ w= co[2]*data->winmat[2][3] + data->winmat[3][3];
+ dx= data->winx*ortho2[0]*data->winmat[0][0];
+ dy= data->winy*ortho2[1]*data->winmat[1][1];
+ w= sqrt(dx*dx + dy*dy)/w;
+
+ /* w squared because we are working with area */
+ area= area*w*w;
+
+ /* viewport of the screen test */
+
+ /* project point on screen */
+ Mat4MulVec4fl(data->winmat, co);
+ if(co[3] != 0.0f) {
+ co[0]= 0.5f*data->winx*(1.0f + co[0]/co[3]);
+ co[1]= 0.5f*data->winy*(1.0f + co[1]/co[3]);
+ }
+
+ /* screen space radius */
+ radius= sqrt(area/M_PI);
+
+ /* make smaller using fallof once over screen edge */
+ *viewport= 1.0f;
+
+ if(co[0]+radius < 0.0f)
+ *viewport *= psys_render_viewport_falloff(vprate, -(co[0]+radius), data->winx);
+ else if(co[0]-radius > data->winx)
+ *viewport *= psys_render_viewport_falloff(vprate, (co[0]-radius) - data->winx, data->winx);
+
+ if(co[1]+radius < 0.0f)
+ *viewport *= psys_render_viewport_falloff(vprate, -(co[1]+radius), data->winy);
+ else if(co[1]-radius > data->winy)
+ *viewport *= psys_render_viewport_falloff(vprate, (co[1]-radius) - data->winy, data->winy);
+
+ return area;
+}
+
+void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[][4], float winmat[][4], int winx, int winy)
{
- ParticleRenderDataup *data;
+ ParticleRenderData*data;
ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys);
if(!G.rendering)
return;
- data= MEM_callocN(sizeof(ParticleRenderDataup), "ParticleRenderDataup");
+ data= MEM_callocN(sizeof(ParticleRenderData), "ParticleRenderData");
data->child= psys->child;
data->totchild= psys->totchild;
@@ -404,17 +473,26 @@ void psys_particles_to_render_backup(Object *ob, ParticleSystem *psys)
psys->childcache= NULL;
psys->totchild= psys->totcached= psys->totchildcache= 0;
+ Mat4CpyMat4(data->winmat, winmat);
+ Mat4MulMat4(data->viewmat, ob->obmat, viewmat);
+ Mat4MulMat4(data->mat, data->viewmat, winmat);
+ data->winx= winx;
+ data->winy= winy;
+
psys->renderdata= data;
}
-void psys_render_backup_to_particles(Object *ob, ParticleSystem *psys)
+void psys_render_restore(Object *ob, ParticleSystem *psys)
{
- ParticleRenderDataup *data;
+ ParticleRenderData*data;
ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys);
data= psys->renderdata;
if(!data)
return;
+
+ if(data->elems)
+ MEM_freeN(data->elems);
if(psmd->dm) {
psmd->dm->needsFree= 1;
@@ -428,7 +506,7 @@ void psys_render_backup_to_particles(Object *ob, ParticleSystem *psys)
psys->child= 0;
psys->totchild= 0;
}
-
+
psys->child= data->child;
psys->totchild= data->totchild;
psys->pathcache= data->pathcache;
@@ -449,6 +527,211 @@ void psys_render_backup_to_particles(Object *ob, ParticleSystem *psys)
psys->renderdata= NULL;
}
+int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot)
+{
+ DerivedMesh *dm= ctx->dm;
+ Mesh *me= (Mesh*)(ctx->ob->data);
+ MFace *mf, *mface;
+ MVert *mvert;
+ ParticleRenderData *data;
+ ParticleRenderElem *elems, *elem;
+ ParticleSettings *part= ctx->psys->part;
+ float *facearea, (*facecenter)[3], size[3], fac, powrate;
+ float co1[3], co2[3], co3[3], co4[3], lambda, arearatio, t, area, viewport;
+ double vprate;
+ int *origindex, *facetotvert;
+ int a, b, totorigface, totface, newtot, skipped;
+
+ if(part->draw_as!=PART_DRAW_PATH || !(part->draw & PART_DRAW_REN_STRAND))
+ return tot;
+ if(!ctx->psys->renderdata || !(part->simplify_flag & PART_SIMPLIFY_ENABLE))
+ return tot;
+
+ mvert= dm->getVertArray(dm);
+ mface= dm->getFaceArray(dm);
+ origindex= dm->getFaceDataArray(dm, CD_ORIGINDEX);
+ totface= dm->getNumFaces(dm);
+ totorigface= me->totface;
+
+ if(totface == 0 || totorigface == 0 || origindex == NULL)
+ return tot;
+
+ facearea= MEM_callocN(sizeof(float)*totorigface, "SimplifyFaceArea");
+ facecenter= MEM_callocN(sizeof(float[3])*totorigface, "SimplifyFaceCenter");
+ facetotvert= MEM_callocN(sizeof(int)*totorigface, "SimplifyFaceArea");
+ elems= MEM_callocN(sizeof(ParticleRenderElem)*totorigface, "SimplifyFaceElem");
+
+ data= ctx->psys->renderdata;
+ data->dosimplify= 1;
+ data->elems= elems;
+ data->origindex= origindex;
+
+ /* compute number of children per original face */
+ for(a=0; a<tot; a++) {
+ b= origindex[ctx->index[a]];
+ if(b != -1)
+ elems[b].totchild++;
+ }
+
+ /* compute areas and centers of original faces */
+ for(mf=mface, a=0; a<totface; a++, mf++) {
+ b= origindex[a];
+
+ if(b != -1) {
+ VECCOPY(co1, mvert[mf->v1].co);
+ VECCOPY(co2, mvert[mf->v2].co);
+ VECCOPY(co3, mvert[mf->v3].co);
+
+ VECADD(facecenter[b], facecenter[b], co1);
+ VECADD(facecenter[b], facecenter[b], co2);
+ VECADD(facecenter[b], facecenter[b], co3);
+
+ if(mf->v4) {
+ VECCOPY(co4, mvert[mf->v4].co);
+ VECADD(facecenter[b], facecenter[b], co4);
+ facearea[b] += AreaQ3Dfl(co1, co2, co3, co4);
+ facetotvert[b] += 4;
+ }
+ else {
+ facearea[b] += AreaT3Dfl(co1, co2, co3);
+ facetotvert[b] += 3;
+ }
+ }
+ }
+
+ for(a=0; a<totorigface; a++)
+ if(facetotvert[a] > 0)
+ VecMulf(facecenter[a], 1.0f/facetotvert[a]);
+
+ /* for conversion from BU area / pixel area to reference screen size */
+ mesh_get_texspace(me, 0, 0, size);
+ fac= ((size[0] + size[1] + size[2])/3.0f)/part->simplify_refsize;
+ fac= fac*fac;
+
+ powrate= log(0.5f)/log(part->simplify_rate*0.5f);
+ if(part->simplify_flag & PART_SIMPLIFY_VIEWPORT)
+ vprate= pow(1.0 - part->simplify_viewport, 5.0);
+ else
+ vprate= 1.0;
+
+ /* set simplification parameters per original face */
+ for(a=0, elem=elems; a<totorigface; a++, elem++) {
+ area = psys_render_projected_area(ctx->psys, facecenter[a], facearea[a], vprate, &viewport);
+ arearatio= fac*area/facearea[a];
+
+ if(arearatio < 1.0f || viewport < 1.0f) {
+ /* lambda is percentage of elements to keep */
+ lambda= (arearatio < 1.0f)? pow(arearatio, powrate): 1.0f;
+ lambda *= viewport;
+
+ /* compute transition region */
+ t= part->simplify_transition;
+ elem->t= (lambda-t < 0.0f)? lambda: (lambda+t > 1.0f)? 1.0f-lambda: t;
+
+ /* scale at end and beginning of the transition region */
+ elem->scalemax= (lambda+t < 1.0f)? 1.0f/lambda: 1.0f/(1.0f - elem->t*elem->t/t);
+ elem->scalemin= (lambda+t < 1.0f)? 0.0f: elem->scalemax*(1.0f-elem->t/t);
+
+ /* extend lambda to include transition */
+ lambda= lambda + elem->t;
+ if(lambda > 1.0f)
+ lambda= 1.0f;
+ }
+ else {
+ lambda= arearatio;
+
+ elem->scalemax= 1.0f; //sqrt(lambda);
+ elem->scalemin= 1.0f; //sqrt(lambda);
+ }
+
+ elem->lambda= lambda;
+ elem->scalemin= sqrt(elem->scalemin);
+ elem->scalemax= sqrt(elem->scalemax);
+ elem->curchild= 0;
+ }
+
+ MEM_freeN(facearea);
+ MEM_freeN(facecenter);
+ MEM_freeN(facetotvert);
+
+ /* move indices and set random number skipping */
+ ctx->skip= MEM_callocN(sizeof(int)*tot, "SimplificationSkip");
+
+ skipped= 0;
+ for(a=0, newtot=0; a<tot; a++) {
+ b= origindex[ctx->index[a]];
+ if(b != -1) {
+ if(elems[b].curchild++ < ceil(elems[b].lambda*elems[b].totchild)) {
+ ctx->index[newtot]= ctx->index[a];
+ ctx->skip[newtot]= skipped;
+ skipped= 0;
+ newtot++;
+ }
+ else skipped++;
+ }
+ else skipped++;
+ }
+
+ for(a=0, elem=elems; a<totorigface; a++, elem++)
+ elem->curchild= 0;
+
+ return newtot;
+}
+
+int psys_render_simplify_params(ParticleSystem *psys, ChildParticle *cpa, float *params)
+{
+ ParticleRenderData *data;
+ ParticleRenderElem *elem;
+ float x, w, scale, alpha, lambda, t, scalemin, scalemax;
+ int b;
+
+ if(!(psys->renderdata && (psys->part->simplify_flag & PART_SIMPLIFY_ENABLE)))
+ return 0;
+
+ data= psys->renderdata;
+ if(!data->dosimplify)
+ return 0;
+
+ b= data->origindex[cpa->num];
+ if(b == -1)
+ return 0;
+
+ elem= &data->elems[b];
+
+ lambda= elem->lambda;
+ t= elem->t;
+ scalemin= elem->scalemin;
+ scalemax= elem->scalemax;
+
+ if(lambda >= 1.0f) {
+ scale= scalemin;
+ alpha= 1.0f;
+ }
+ else {
+ x= (elem->curchild+0.5f)/elem->totchild;
+ if(x < lambda-t) {
+ scale= scalemax;
+ alpha= 1.0f;
+ }
+ else if(x >= lambda+t) {
+ scale= scalemin;
+ alpha= 0.0f;
+ }
+ else {
+ w= (lambda+t - x)/(2.0f*t);
+ scale= scalemin + (scalemax - scalemin)*w;
+ alpha= w;
+ }
+ }
+
+ params[0]= scale;
+ params[1]= alpha;
+
+ elem->curchild++;
+
+ return 1;
+}
+
/************************************************/
/* Interpolated Particles */
/************************************************/
@@ -2550,6 +2833,11 @@ static void default_particle_settings(ParticleSettings *part)
}
part->ipo = NULL;
+
+ part->simplify_refsize= 1920;
+ part->simplify_rate= 1.0f;
+ part->simplify_transition= 0.1f;
+ part->simplify_viewport= 0.8;
}