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
path: root/source
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2007-12-20 19:35:27 +0300
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2007-12-20 19:35:27 +0300
commit0f2b2e3c60173e85e137df71392d867576e65ac1 (patch)
treef06099e4ef4a673b622a9f61902cb7b57692780a /source
parent2e48a4af57759e61a1afd89edb19a4dc92ced728 (diff)
Strand Render Simplification
============================ - Strand render now has options to remove child strands as the object's faces becomes smaller, in the Simplification particle panel. - "Reference Size" is the approximate size of the object on screen, after which simplification starts. - "Rate" is how fast strands are removed. - "Transition" is the percentage of strands being faded out as they are removed. - Another "Viewport" option removes strands on faces that are outside of the viewport. "Rate" again controls how fast these are removed. - Strand render in Blender Units now has an adjustable minimum width. Below this minimum width, strands start fading out instead of getting smaller.
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_particle.h10
-rw-r--r--source/blender/blenkernel/intern/particle.c308
-rw-r--r--source/blender/blenkernel/intern/particle_system.c103
-rw-r--r--source/blender/blenloader/intern/readfile.c16
-rw-r--r--source/blender/makesdna/DNA_material_types.h1
-rw-r--r--source/blender/makesdna/DNA_particle_types.h9
-rw-r--r--source/blender/render/intern/include/render_types.h2
-rw-r--r--source/blender/render/intern/include/renderdatabase.h2
-rw-r--r--source/blender/render/intern/include/strand.h3
-rw-r--r--source/blender/render/intern/source/convertblender.c45
-rw-r--r--source/blender/render/intern/source/renderdatabase.c18
-rw-r--r--source/blender/render/intern/source/strand.c49
-rw-r--r--source/blender/src/buttons_object.c44
-rw-r--r--source/blender/src/buttons_shading.c34
14 files changed, 545 insertions, 99 deletions
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index 1c69fe613c7..a1ac97406e1 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -112,8 +112,8 @@ typedef struct ParticleSeam{
typedef struct ParticleCacheKey{
float co[3];
float vel[3];
- float rot[4];
float col[3];
+ float rot[4];
int steps;
} ParticleCacheKey;
@@ -165,7 +165,7 @@ typedef struct ParticleThreadContext {
float *jit, *jitoff, *weight;
float maxweight;
- int *index, jitlevel;
+ int *index, *skip, jitlevel;
int from, cfrom, distr;
@@ -214,8 +214,10 @@ void free_hair(struct ParticleSystem *psys);
void free_keyed_keys(struct ParticleSystem *psys);
void psys_free(struct Object * ob, struct ParticleSystem * psys);
-void psys_particles_to_render_backup(struct Object *ob, struct ParticleSystem *psys);
-void psys_render_backup_to_particles(struct Object *ob, struct ParticleSystem *psys);
+void psys_render_set(struct Object *ob, struct ParticleSystem *psys, float viewmat[][4], float winmat[][4], int winx, int winy);
+void psys_render_restore(struct Object *ob, struct ParticleSystem *psys);
+int psys_render_simplify_distribution(struct ParticleThreadContext *ctx, int tot);
+int psys_render_simplify_params(struct ParticleSystem *psys, struct ChildParticle *cpa, float *params);
void clear_particles_from_cache(struct Object *ob, struct ParticleSystem *psys, int cfra);
//void psys_remove_from_particle_list(struct Object *ob, short nbr, struct ParticleSystem *psys);
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;
}
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index af1db36b648..a8ccd12874e 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -105,13 +105,13 @@ static int get_current_display_percentage(ParticleSystem *psys)
return psys->part->disp;
}
-static void alloc_particles(ParticleSystem *psys, int new_totpart)
+static void alloc_particles(Object *ob, ParticleSystem *psys, int new_totpart)
{
ParticleData *newpars = 0, *pa;
- int i, child_nbr, totpart, totsaved = 0;
+ int i, totpart, totsaved = 0;
- if(new_totpart<0){
- if(psys->part->distr==PART_DISTR_GRID){
+ if(new_totpart<0) {
+ if(psys->part->distr==PART_DISTR_GRID) {
totpart= psys->part->grid_res;
totpart*=totpart*totpart;
}
@@ -123,7 +123,7 @@ static void alloc_particles(ParticleSystem *psys, int new_totpart)
if(totpart)
newpars= MEM_callocN(totpart*sizeof(ParticleData), "particles");
- if(psys->particles){
+ if(psys->particles) {
totsaved=MIN2(psys->totpart,totpart);
/*save old pars*/
if(totsaved)
@@ -136,16 +136,7 @@ static void alloc_particles(ParticleSystem *psys, int new_totpart)
}
psys->particles=newpars;
- child_nbr= (psys->renderdata)? psys->part->ren_child_nbr: psys->part->child_nbr;
- if(child_nbr && psys->part->childtype){
- if(psys->child)
- MEM_freeN(psys->child);
- psys->child = NULL;
- if(totpart)
- psys->child= MEM_callocN(totpart*child_nbr*sizeof(ChildParticle), "child_particles");
- psys->totchild=totpart*child_nbr;
- }
- else if(psys->child){
+ if(psys->child) {
MEM_freeN(psys->child);
psys->child=0;
psys->totchild=0;
@@ -154,6 +145,32 @@ static void alloc_particles(ParticleSystem *psys, int new_totpart)
psys->totpart=totpart;
}
+static int get_alloc_child_particles_tot(ParticleSystem *psys)
+{
+ int child_nbr;
+
+ if(!psys->part->childtype)
+ return 0;
+
+ child_nbr= (psys->renderdata)? psys->part->ren_child_nbr: psys->part->child_nbr;
+ return psys->totpart*child_nbr;
+}
+
+static void alloc_child_particles(ParticleSystem *psys, int tot)
+{
+ if(psys->child){
+ MEM_freeN(psys->child);
+ psys->child=0;
+ psys->totchild=0;
+ }
+
+ if(psys->part->childtype) {
+ psys->totchild= tot;
+ if(psys->totchild)
+ psys->child= MEM_callocN(psys->totchild*sizeof(ChildParticle), "child_particles");
+ }
+}
+
/* only run this if from == PART_FROM_FACE */
void psys_calc_dmfaces(Object *ob, DerivedMesh *dm, ParticleSystem *psys)
{
@@ -607,7 +624,7 @@ void psys_thread_distribute_particle(ParticleThread *thread, ParticleData *pa, C
}
mf= dm->getFaceData(dm, ctx->index[p], CD_MFACE);
-
+
//switch(distr){
// case PART_DISTR_JIT:
// i=index[p];
@@ -741,12 +758,16 @@ void *exec_distribution(void *data)
if(thread->ctx->from == PART_FROM_CHILD) {
totpart= psys->totchild;
- cpa= psys->child + thread->num;
+ cpa= psys->child;
- rng_skip(thread->rng, 5*thread->num);
- for(p=thread->num; p<totpart; p+=thread->tot, cpa+=thread->tot) {
- psys_thread_distribute_particle(thread, NULL, cpa, p);
- rng_skip(thread->rng, 5*(thread->tot-1));
+ for(p=0; p<totpart; p++, cpa++) {
+ if(thread->ctx->skip) /* simplification skip */
+ rng_skip(thread->rng, 5*thread->ctx->skip[p]);
+
+ if((p+thread->num) % thread->tot == 0)
+ psys_thread_distribute_particle(thread, NULL, cpa, p);
+ else /* thread skip */
+ rng_skip(thread->rng, 5);
}
}
else {
@@ -757,7 +778,7 @@ void *exec_distribution(void *data)
}
return 0;
-}
+}
/* creates a distribution of coordinates on a DerivedMesh */
/* */
@@ -813,7 +834,6 @@ int psys_threads_init_distribution(ParticleThread *threads, DerivedMesh *finaldm
if(from==PART_FROM_CHILD){
distr=PART_DISTR_RAND;
- cpa=psys->child;
if(part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES){
dm= finaldm;
children=1;
@@ -828,7 +848,7 @@ int psys_threads_init_distribution(ParticleThread *threads, DerivedMesh *finaldm
BLI_kdtree_balance(tree);
- totpart=psys->totchild;
+ totpart=get_alloc_child_particles_tot(psys);
cfrom=from=PART_FROM_FACE;
if(part->flag&PART_CHILD_SEAMS){
@@ -879,6 +899,8 @@ int psys_threads_init_distribution(ParticleThread *threads, DerivedMesh *finaldm
/* no need to figure out distribution */
int child_nbr= (psys->renderdata)? part->ren_child_nbr: part->child_nbr;
+ alloc_child_particles(psys, 1.0f);
+ cpa=psys->child;
for(i=0; i<child_nbr; i++){
for(p=0; p<psys->totpart; p++,cpa++){
float length=2.0;
@@ -1100,7 +1122,7 @@ int psys_threads_init_distribution(ParticleThread *threads, DerivedMesh *finaldm
sum[0]= 0.0f;
for(i=0;i<tot; i++)
sum[i+1]= sum[i]+weight[i]*totweight;
-
+
if(part->flag&PART_TRAND){
float pos;
@@ -1156,9 +1178,6 @@ int psys_threads_init_distribution(ParticleThread *threads, DerivedMesh *finaldm
}
/* 5. */
- if(children)
- from=PART_FROM_CHILD;
-
ctx->tree= tree;
ctx->seams= seams;
ctx->totseam= totseam;
@@ -1169,17 +1188,21 @@ int psys_threads_init_distribution(ParticleThread *threads, DerivedMesh *finaldm
ctx->jitoff= jitoff;
ctx->weight= weight;
ctx->maxweight= maxweight;
- ctx->from= from;
+ ctx->from= (children)? PART_FROM_CHILD: from;
ctx->cfrom= cfrom;
ctx->distr= distr;
ctx->dm= dm;
ctx->tpars= tpars;
- seed= 31415926 + ctx->psys->seed;
+ if(children) {
+ totpart= psys_render_simplify_distribution(ctx, totpart);
+ alloc_child_particles(psys, totpart);
+ }
- if(from!=PART_FROM_CHILD || psys->totchild < 10000)
+ if(!children || psys->totchild < 10000)
totthread= 1;
+ seed= 31415926 + ctx->psys->seed;
for(i=0; i<totthread; i++) {
threads[i].rng= rng_new(seed);
threads[i].tot= totthread;
@@ -1323,6 +1346,7 @@ void psys_threads_free(ParticleThread *threads)
if(ctx->jitoff) MEM_freeN(ctx->jitoff);
if(ctx->weight) MEM_freeN(ctx->weight);
if(ctx->index) MEM_freeN(ctx->index);
+ if(ctx->skip) MEM_freeN(ctx->skip);
if(ctx->seams) MEM_freeN(ctx->seams);
//if(ctx->vertpart) MEM_freeN(ctx->vertpart);
BLI_kdtree_free(ctx->tree);
@@ -4188,13 +4212,16 @@ static void psys_update_path_cache(Object *ob, ParticleSystemModifierData *psmd,
if(distr){
if(alloc)
- alloc_particles(psys,psys->totpart);
+ alloc_particles(ob,psys,psys->totpart);
- if(psys->totchild && part->childtype){
- distribute_particles(ob,psys,PART_FROM_CHILD);
+ if(get_alloc_child_particles_tot(psys)) {
+ /* don't generate children while computing the hair keys */
+ if(!(psys->part->type == PART_HAIR) || (psys->flag & PSYS_HAIR_DONE)) {
+ distribute_particles(ob,psys,PART_FROM_CHILD);
- if(part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES && part->parents!=0.0)
- psys_find_parents(ob,psmd,psys);
+ if(part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES && part->parents!=0.0)
+ psys_find_parents(ob,psmd,psys);
+ }
}
}
@@ -4413,11 +4440,11 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier
if(init) {
if(distr) {
if(alloc)
- alloc_particles(psys, totpart);
+ alloc_particles(ob, psys, totpart);
distribute_particles(ob, psys, part->from);
- if(psys->totchild && part->childtype)
+ if(get_alloc_child_particles_tot(psys))
distribute_particles(ob, psys, PART_FROM_CHILD);
}
initialize_all_particles(ob, psys, psmd);
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index cf71d9ab41e..8bbcc7016c1 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -6826,7 +6826,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
for(ma=main->mat.first; ma; ma= ma->id.next) {
- if (ma->samp_gloss_mir == 0) {
+ if(ma->samp_gloss_mir == 0) {
ma->gloss_mir = ma->gloss_tra= 1.0;
ma->aniso_gloss_mir = 1.0;
ma->samp_gloss_mir = ma->samp_gloss_tra= 18;
@@ -6834,11 +6834,23 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
ma->dist_mir = 0.0;
ma->fadeto_mir = MA_RAYMIR_FADETOSKY;
}
+
+ if(ma->strand_min == 0.0f)
+ ma->strand_min= 1.0f;
}
- for(part=main->particle.first; part; part=part->id.next)
+ for(part=main->particle.first; part; part=part->id.next) {
if(part->ren_child_nbr==0)
part->ren_child_nbr= part->child_nbr;
+
+ if(part->simplify_refsize==0) {
+ part->simplify_refsize= 1920;
+ part->simplify_rate= 1.0f;
+ part->simplify_transition= 0.1f;
+ part->simplify_viewport= 0.8f;
+ }
+ }
+
if (main->versionfile < 245 || main->subversionfile < 12)
{
/* initialize skeleton generation toolsettings */
diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h
index 22585e59c7b..f0b06585f27 100644
--- a/source/blender/makesdna/DNA_material_types.h
+++ b/source/blender/makesdna/DNA_material_types.h
@@ -85,6 +85,7 @@ typedef struct Material {
short flarec, starc, linec, ringc;
float hasize, flaresize, subsize, flareboost;
float strand_sta, strand_end, strand_ease, strand_surfnor;
+ float strand_min, strand_pad;
char strand_uvname[32];
float sbias; /* shadow bias */
diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h
index a00d7d484d9..942c837df97 100644
--- a/source/blender/makesdna/DNA_particle_types.h
+++ b/source/blender/makesdna/DNA_particle_types.h
@@ -121,6 +121,11 @@ typedef struct ParticleSettings {
short bb_align, bb_uv_split, bb_anim, bb_split_offset;
float bb_tilt, bb_rand_tilt, bb_offset[2];
+ /* simplification */
+ short simplify_flag, simplify_refsize;
+ float simplify_rate, simplify_transition;
+ float simplify_viewport;
+
/* general values */
float sta, end, lifetime, randlife;
float timetweak, jitfac, keyed_time;
@@ -307,6 +312,10 @@ typedef struct ParticleSystem{
#define PART_DRAW_WHOLE_GR (1<<14)
#define PART_DRAW_REN_STRAND (1<<15)
+/* part->simplify_flag */
+#define PART_SIMPLIFY_ENABLE 1
+#define PART_SIMPLIFY_VIEWPORT 2
+
/* part->bb_align */
#define PART_BB_X 0
#define PART_BB_Y 1
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
index 4a731878ffb..7fbbd0f5abc 100644
--- a/source/blender/render/intern/include/render_types.h
+++ b/source/blender/render/intern/include/render_types.h
@@ -343,7 +343,7 @@ typedef struct StrandBuffer {
unsigned int lay;
int overrideuv;
int flag, maxdepth;
- float adaptcos;
+ float adaptcos, minwidth;
float winmat[4][4];
int winx, winy;
diff --git a/source/blender/render/intern/include/renderdatabase.h b/source/blender/render/intern/include/renderdatabase.h
index 0346f2d6413..c919a54008e 100644
--- a/source/blender/render/intern/include/renderdatabase.h
+++ b/source/blender/render/intern/include/renderdatabase.h
@@ -69,6 +69,7 @@ typedef struct StrandTableNode {
struct StrandRen *strand;
float *winspeed;
float *surfnor;
+ float *simplify;
struct MCol *mcol;
float *uv;
int totuv, totmcol;
@@ -112,6 +113,7 @@ int RE_vlakren_get_normal(struct Render *re, struct ObjectInstanceRen *obi, stru
float *RE_strandren_get_surfnor(struct ObjectRen *obr, struct StrandRen *strand, int verify);
float *RE_strandren_get_uv(struct ObjectRen *obr, struct StrandRen *strand, int n, char **name, int verify);
struct MCol *RE_strandren_get_mcol(struct ObjectRen *obr, struct StrandRen *strand, int n, char **name, int verify);
+float *RE_strandren_get_simplify(struct ObjectRen *obr, struct StrandRen *strand, int verify);
float *RE_strandren_get_winspeed(struct ObjectInstanceRen *obi, struct StrandRen *strand, int verify);
struct VertRen *RE_vertren_copy(struct ObjectRen *obr, struct VertRen *ver);
diff --git a/source/blender/render/intern/include/strand.h b/source/blender/render/intern/include/strand.h
index 7f37317d4d5..34a147c1933 100644
--- a/source/blender/render/intern/include/strand.h
+++ b/source/blender/render/intern/include/strand.h
@@ -68,6 +68,9 @@ typedef struct StrandPoint {
/* screen space */
float hoco[4];
float x, y;
+
+ /* simplification */
+ float alpha;
} StrandPoint;
typedef struct StrandSegment {
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index de3bd6079a4..eb5bb3f2f71 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -983,7 +983,7 @@ static void static_particle_strand(Render *re, ObjectRen *obr, Material *ma, flo
{
static VertRen *v1= NULL, *v2= NULL;
VlakRen *vlr;
- float nor[3], cross[3], w, dx, dy, width;
+ float nor[3], cross[3], crosslen, w, dx, dy, width;
static float anor[3], avec[3];
int flag, i;
static int second=0;
@@ -992,14 +992,11 @@ static void static_particle_strand(Render *re, ObjectRen *obr, Material *ma, flo
Normalize(nor); // nor needed as tangent
Crossf(cross, vec, nor);
- if(ma->mode&MA_STR_B_UNITS)
- Normalize(cross);
-
/* turn cross in pixelsize */
w= vec[2]*re->winmat[2][3] + re->winmat[3][3];
- dx= re->winx*cross[0]*re->winmat[0][0]/w;
- dy= re->winy*cross[1]*re->winmat[1][1]/w;
- w= sqrt(dx*dx + dy*dy);
+ dx= re->winx*cross[0]*re->winmat[0][0];
+ dy= re->winy*cross[1]*re->winmat[1][1];
+ w= sqrt(dx*dx + dy*dy)/w;
if(w!=0.0f) {
float fac;
@@ -1013,12 +1010,16 @@ static void static_particle_strand(Render *re, ObjectRen *obr, Material *ma, flo
width= ((1.0f-fac)*ma->strand_sta + (fac)*ma->strand_end);
- /* use actual Blender units for strand width and fall back to min 1px */
+ /* use actual Blender units for strand width and fall back to minimum width */
if(ma->mode & MA_STR_B_UNITS){
- if(width < 1.0f/w)
- width= 1.0f/w;
+ crosslen= VecLength(cross);
+ w= 2.0f*crosslen*ma->strand_min/w;
+
+ if(width < w)
+ width= w;
+
/*cross is the radius of the strand so we want it to be half of full width */
- VecMulf(cross,0.5);
+ VecMulf(cross,0.5/crosslen);
}
else
width/=w;
@@ -1496,7 +1497,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
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 loc_tex[3], size_tex[3], adapt_angle=0.0, adapt_pix=0.0, random;
- int i, a, k, max_k=0, totpart, totuv=0, override_uv=-1;
+ float simplify[2];
+ int i, a, k, max_k=0, totpart, totuv=0, override_uv=-1, dosimplify = 0;
int path_possible=0, keys_possible=0, baked_keys=0, totchild=psys->totchild;
int seed, path_nbr=0, path=0, orco1=0, adapt=0, uv[3]={0,0,0};
char **uv_name=0;
@@ -1639,9 +1641,10 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
Mat4CpyMat4(strandbuf->winmat, re->winmat);
strandbuf->winx= re->winx;
strandbuf->winy= re->winy;
- strandbuf->maxdepth= 2; /* TODO */
+ strandbuf->maxdepth= 2;
strandbuf->adaptcos= cos((float)part->adapt_angle*(float)(M_PI/180.0));
strandbuf->overrideuv= override_uv;
+ strandbuf->minwidth= ma->strand_min;
if(part->flag & PART_HAIR_BSPLINE)
strandbuf->flag |= R_STRAND_BSPLINE;
@@ -1720,7 +1723,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
if(totchild && (part->draw&PART_DRAW_PARENT)==0) continue;
}
- else{
+ else {
ChildParticle *cpa= psys->child+a-totpart;
pa_time=psys_get_child_time(psys, cpa, cfra);
@@ -1778,6 +1781,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
}
}
+ dosimplify= psys_render_simplify_params(psys, cpa, simplify);
+
if(path_nbr) {
cache = psys->childcache[a-totpart];
max_k = (int)cache->steps;
@@ -1805,6 +1810,12 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
strand->vert= svert;
VECCOPY(strand->orco, orco);
+ if(dosimplify) {
+ float *ssimplify= RE_strandren_get_simplify(obr, strand, 1);
+ ssimplify[0]= simplify[0];
+ ssimplify[1]= simplify[1];
+ }
+
if(surfnor) {
float *snor= RE_strandren_get_surfnor(obr, strand, 1);
VECCOPY(snor, surfnor);
@@ -3886,7 +3897,7 @@ static void add_render_object(Render *re, Object *ob, Object *par, int index, in
show_emitter= 0;
for(psys=ob->particlesystem.first; psys; psys=psys->next) {
show_emitter += psys->part->draw & PART_DRAW_EMITTER;
- psys_particles_to_render_backup(ob, psys);
+ psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy);
}
/* if no psys has "show emitter" selected don't render emitter */
@@ -3910,7 +3921,7 @@ static void add_render_object(Render *re, Object *ob, Object *par, int index, in
for(psys=ob->particlesystem.first; psys; psys=psys->next, psysindex++) {
obr= RE_addRenderObject(re, ob, par, index, psysindex);
init_render_object_data(re, obr, only_verts);
- psys_render_backup_to_particles(ob, psys);
+ psys_render_restore(ob, psys);
/* only add instance for objects that have not been used for dupli */
if(!(ob->transflag & OB_RENDER_DUPLI))
@@ -4666,7 +4677,7 @@ void RE_Database_FromScene_Vectors(Render *re, Scene *sce)
} else {
/* check if both have same amounts of vertices */
if(obi->totvector!=oldobi->totvector) {
- printf("Warning: object %s has different amount of vertices on other frame\n", obi->ob->id.name+2);
+ printf("Warning: object %s has different amount of vertices or strands on other frame\n", obi->ob->id.name+2);
continue;
}
diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c
index 3906b1fc001..79c87252fc2 100644
--- a/source/blender/render/intern/source/renderdatabase.c
+++ b/source/blender/render/intern/source/renderdatabase.c
@@ -104,6 +104,7 @@
#define RE_MCOL_ELEMS 4
#define RE_UV_ELEMS 2
#define RE_SURFNOR_ELEMS 3
+#define RE_SIMPLIFY_ELEMS 2
float *RE_vertren_get_sticky(ObjectRen *obr, VertRen *ver, int verify)
{
@@ -590,6 +591,21 @@ MCol *RE_strandren_get_mcol(ObjectRen *obr, StrandRen *strand, int n, char **nam
return node->mcol + index*RE_MCOL_ELEMS;
}
+float *RE_strandren_get_simplify(struct ObjectRen *obr, struct StrandRen *strand, int verify)
+{
+ float *simplify;
+ int nr= strand->index>>8;
+
+ simplify= obr->strandnodes[nr].simplify;
+ if(simplify==NULL) {
+ if(verify)
+ simplify= obr->strandnodes[nr].simplify= MEM_callocN(256*RE_SIMPLIFY_ELEMS*sizeof(float), "simplify table");
+ else
+ return NULL;
+ }
+ return simplify + (strand->index & 255)*RE_SIMPLIFY_ELEMS;
+}
+
/* winspeed is exception, it is stored per instance */
float *RE_strandren_get_winspeed(ObjectInstanceRen *obi, StrandRen *strand, int verify)
{
@@ -743,6 +759,8 @@ void free_renderdata_strandnodes(StrandTableNode *strandnodes)
MEM_freeN(strandnodes[a].winspeed);
if(strandnodes[a].surfnor)
MEM_freeN(strandnodes[a].surfnor);
+ if(strandnodes[a].simplify)
+ MEM_freeN(strandnodes[a].simplify);
}
MEM_freeN(strandnodes);
diff --git a/source/blender/render/intern/source/strand.c b/source/blender/render/intern/source/strand.c
index 42c6d559f65..4f0e9764a43 100644
--- a/source/blender/render/intern/source/strand.c
+++ b/source/blender/render/intern/source/strand.c
@@ -321,7 +321,8 @@ void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint)
{
Material *ma;
StrandBuffer *strandbuf;
- float p[4][3], data[4], cross[3], w, dx, dy, t;
+ float *simplify;
+ float p[4][3], data[4], cross[3], crosslen, w, dx, dy, t;
int type;
strandbuf= sseg->buffer;
@@ -378,25 +379,34 @@ void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint)
Normalize(spoint->nor);
spoint->width= strand_eval_width(ma, spoint->strandco);
+
+ /* simplification */
+ simplify= RE_strandren_get_simplify(strandbuf->obr, sseg->strand, 0);
+ spoint->alpha= (simplify)? simplify[1]: 1.0f;
/* outer points */
Crossf(cross, spoint->co, spoint->tan);
- if(strandbuf->flag & R_STRAND_B_UNITS)
- Normalize(cross);
-
w= spoint->co[2]*strandbuf->winmat[2][3] + strandbuf->winmat[3][3];
- dx= strandbuf->winx*cross[0]*strandbuf->winmat[0][0]/w;
- dy= strandbuf->winy*cross[1]*strandbuf->winmat[1][1]/w;
- w= sqrt(dx*dx + dy*dy);
+ dx= strandbuf->winx*cross[0]*strandbuf->winmat[0][0];
+ dy= strandbuf->winy*cross[1]*strandbuf->winmat[1][1];
+ w= sqrt(dx*dx + dy*dy)/w;
if(w > 0.0f) {
if(strandbuf->flag & R_STRAND_B_UNITS) {
- w= 1.0f/w;
+ crosslen= VecLength(cross);
+ w= 2.0f*crosslen*strandbuf->minwidth/w;
- if(spoint->width < w)
+ if(spoint->width < w) {
+ spoint->alpha= spoint->width/w;
spoint->width= w;
- VecMulf(cross, spoint->width*0.5f);
+ }
+
+ if(simplify)
+ /* squared because we only change width, not length */
+ spoint->width *= simplify[0]*simplify[0];
+
+ VecMulf(cross, spoint->width*0.5f/crosslen);
}
else
VecMulf(cross, spoint->width/w);
@@ -528,7 +538,7 @@ static void strand_project_point(float winmat[][4], float winx, float winy, Stra
}
#include "BLI_rand.h"
-void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *sseg, StrandPoint *spoint);
+static void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *sseg, StrandPoint *spoint);
static void strand_shade_get(StrandPart *spart, int lookup, ShadeSample *ssamp, StrandPoint *spoint, StrandVert *svert, StrandSegment *sseg)
{
@@ -653,7 +663,7 @@ static int strand_test_clip(float winmat[][4], ZSpan *zspan, float *bounds, floa
return clipflag;
}
-void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *sseg, StrandPoint *spoint)
+static void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *sseg, StrandPoint *spoint)
{
ShadeInput *shi= ssamp->shi;
ShadeResult *shr= ssamp->shr;
@@ -685,6 +695,21 @@ void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *sseg, Str
shade_samples_do_AO(ssamp);
shade_input_do_shade(shi, shr);
+ /* apply simplification */
+ if(spoint->alpha < 1.0f) {
+ shr->combined[0] *= spoint->alpha;
+ shr->combined[1] *= spoint->alpha;
+ shr->combined[2] *= spoint->alpha;
+ shr->combined[3] *= spoint->alpha;
+
+ shr->col[0] *= spoint->alpha;
+ shr->col[1] *= spoint->alpha;
+ shr->col[2] *= spoint->alpha;
+ shr->col[3] *= spoint->alpha;
+
+ shr->alpha *= spoint->alpha;
+ }
+
/* include lamphalos for strand, since halo layer was added already */
if(re->flag & R_LAMPHALO)
if(shi->layflag & SCE_LAY_HALO)
diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c
index 3c2969e77bf..e5bb4dd8a10 100644
--- a/source/blender/src/buttons_object.c
+++ b/source/blender/src/buttons_object.c
@@ -3610,8 +3610,8 @@ static void object_panel_particle_children(Object *ob)
if(part==NULL) return;
block= uiNewBlock(&curarea->uiblocks, "object_panel_particle_child", UI_EMBOSS, UI_HELV, curarea->win);
- uiNewPanelTabbed("Extras", "Particle");
if(uiNewPanel(curarea, block, "Children", "Particle", 1300, 0, 318, 204)==0) return;
+ uiNewPanelTabbed("Extras", "Particle");
uiDefButS(block, MENU, B_PART_ALLOC_CHILD, "Children from:%t|Faces%x2|Particles%x1|None%x0", butx,buty,butw,buth, &part->childtype, 14.0, 0.0, 0, 0, "Create child particles");
@@ -3957,6 +3957,47 @@ static void object_panel_particle_visual(Object *ob)
}
uiBlockEndAlign(block);
}
+static void object_panel_particle_simplification(Object *ob)
+{
+ uiBlock *block;
+ ParticleSystem *psys=psys_get_current(ob);
+ ParticleSettings *part;
+ short butx=0, buty=160, butw=150, buth=20;
+
+ if (psys==NULL) return;
+ part=psys->part;
+ if(part==NULL) return;
+
+ if(part->draw_as!=PART_DRAW_PATH || !(part->draw & PART_DRAW_REN_STRAND))
+ return;
+ if(part->childtype!=PART_CHILD_FACES)
+ return;
+
+ block= uiNewBlock(&curarea->uiblocks, "object_panel_particle_simplification", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Visualization", "Particle");
+ if(uiNewPanel(curarea, block, "Simplification", "Particle", 640, 0, 318, 204)==0) return;
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, PART_SIMPLIFY_ENABLE, B_PART_REDRAW, "Child Simplification", butx,buty-=buth,butw,buth, &part->simplify_flag, 0, 0, 0, 0, "Remove child strands as the object becomes smaller on the screen");
+ uiBlockEndAlign(block);
+ if(part->simplify_flag & PART_SIMPLIFY_ENABLE) {
+ buty -= 10;
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUM, B_NOP, "Reference Size:", butx,(buty-=buth),butw,buth, &part->simplify_refsize, 1.0, 32768.0, 0, 0, "Reference size size in pixels, after which simplification begins");
+ uiDefButF(block, NUM, B_NOP, "Rate:", butx,(buty-=buth),butw,buth, &part->simplify_rate, 0.0, 1.0, 0, 0, "Speed of simplification");
+ uiDefButF(block, NUM, B_NOP, "Transition:", butx,(buty-=buth),butw,buth, &part->simplify_transition, 0.0, 1.0, 0, 0, "Transition period for fading out strands");
+ uiBlockEndAlign(block);
+
+ buty -= 10;
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, PART_SIMPLIFY_VIEWPORT, B_PART_REDRAW, "Viewport", butx,buty-=buth,butw,buth, &part->simplify_flag, 0, 0, 0, 0, "Remove child strands as the object goes outside the viewport");
+ uiDefButF(block, NUM, B_NOP, "Rate:", butx,(buty-=buth),butw,buth, &part->simplify_viewport, 0.0, 0.999, 0, 0, "Speed of simplification");
+ uiBlockEndAlign(block);
+ }
+ uiBlockEndAlign(block);
+}
static void boidrule_moveDown(void *part_v, void *rule_v)
{
ParticleSettings *part = part_v;
@@ -4700,6 +4741,7 @@ void particle_panels()
if(psys){
object_panel_particle_physics(ob);
object_panel_particle_visual(ob);
+ object_panel_particle_simplification(ob);
object_panel_particle_extra(ob);
object_panel_particle_children(ob);
}
diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c
index dafd156524f..ad1afcc0608 100644
--- a/source/blender/src/buttons_shading.c
+++ b/source/blender/src/buttons_shading.c
@@ -3852,31 +3852,37 @@ static uiBlock *strand_menu(void *mat_v)
{
Material *ma= mat_v;
uiBlock *block;
+ int buth=20, butw=230, butx=10, buty=160;
block= uiNewBlock(&curarea->uiblocks, "strand menu", UI_EMBOSS, UI_HELV, curarea->win);
-
+
+ if(ma->mode & MA_STR_B_UNITS)
+ buty += buth;
+
/* use this for a fake extra empy space around the buttons */
- uiDefBut(block, LABEL, 0, "", 0, 0, 250, 170, NULL, 0, 0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, "", 0, 0, butw+20, buty+10, NULL, 0, 0, 0, 0, "");
+ /* event return 0, to prevent menu to close */
uiBlockBeginAlign(block);
- /* event return 0, to prevent menu to close */
-
- uiDefButBitI(block, TOG, MA_TANGENT_STR, 0, "Use Tangent Shading", 10,140,230,20, &(ma->mode), 0, 0, 0, 0, "Uses direction of strands as normal for tangent-shading");
- uiDefButBitI(block, TOG, MA_STR_SURFDIFF, 0, "Surface Diffuse", 10,120,115,20, &(ma->mode), 0, 0, 0, 0, "Make diffuse shading more similar to shading the surface");
- uiDefButF(block, NUM, 0, "Dist", 125,120,115,20, &ma->strand_surfnor, 0.0f, 10.0f, 2, 0, "Distance in Blender units over which to blend in the surface normal");
+ uiDefButBitI(block, TOG, MA_TANGENT_STR, 0, "Use Tangent Shading", butx,buty-=buth,butw,buth, &(ma->mode), 0, 0, 0, 0, "Uses direction of strands as normal for tangent-shading");
+ uiDefButBitI(block, TOG, MA_STR_SURFDIFF, 0, "Surface Diffuse", butx,buty-=buth,butw/2,buth, &(ma->mode), 0, 0, 0, 0, "Make diffuse shading more similar to shading the surface");
+ uiDefButF(block, NUM, 0, "Dist", butx+butw/2,buty,butw/2,buth, &ma->strand_surfnor, 0.0f, 10.0f, 2, 0, "Distance in Blender units over which to blend in the surface normal");
+
+ buty -= 5;
uiBlockBeginAlign(block);
- uiDefButBitI(block, TOG, MA_STR_B_UNITS, 0, "Use Blender Units", 10,95,230,20, &(ma->mode), 0, 0, 0, 0, "Use actual Blender units for widths instead of pixels");
+ uiDefButBitI(block, TOG, MA_STR_B_UNITS, 0, "Use Blender Units", butx,buty-=buth,butw,buth, &(ma->mode), 0, 0, 0, 0, "Use actual Blender units for widths instead of pixels");
if(ma->mode & MA_STR_B_UNITS){
- uiDefButF(block, NUMSLI, 0, "Start ", 10, 75, 230,20, &ma->strand_sta, 0.0001, 2.0, 2, 0, "Start size of strands in Blender units");
- uiDefButF(block, NUMSLI, 0, "End ", 10, 55, 230,20, &ma->strand_end, 0.0001, 1.0, 2, 0, "End size of strands in Blender units");
+ uiDefButF(block, NUMSLI, 0, "Start ", butx,buty-=buth, butw,buth, &ma->strand_sta, 0.0001, 2.0, 2, 0, "Start size of strands in Blender units");
+ uiDefButF(block, NUMSLI, 0, "End ", butx,buty-=buth, butw,buth, &ma->strand_end, 0.0001, 1.0, 2, 0, "End size of strands in Blender units");
+ uiDefButF(block, NUMSLI, 0, "Minimum ", butx,buty-=buth, butw,buth, &ma->strand_min, 0.001, 10.0, 0, 0, "Minimum size of strands in pixels");
}
else{
- uiDefButF(block, NUMSLI, 0, "Start ", 10, 75, 230,20, &ma->strand_sta, 0.25, 20.0, 2, 0, "Start size of strands in pixels");
- uiDefButF(block, NUMSLI, 0, "End ", 10, 55, 230,20, &ma->strand_end, 0.25, 10.0, 2, 0, "End size of strands in pixels");
+ uiDefButF(block, NUMSLI, 0, "Start ", butx,buty-=buth, butw,buth, &ma->strand_sta, 0.25, 20.0, 2, 0, "Start size of strands in pixels");
+ uiDefButF(block, NUMSLI, 0, "End ", butx,buty-=buth, butw,buth, &ma->strand_end, 0.25, 10.0, 2, 0, "End size of strands in pixels");
}
- uiDefButF(block, NUMSLI, 0, "Shape ", 10, 35, 230,20, &ma->strand_ease, -0.9, 0.9, 2, 0, "Shape of strands, positive value makes it rounder, negative makes it spiky");
- uiDefBut(block, TEX, B_MATPRV, "UV:", 10,10,230,20, ma->strand_uvname, 0, 31, 0, 0, "Set name of UV layer to override");
+ uiDefButF(block, NUMSLI, 0, "Shape ", butx,buty-=buth, butw,buth, &ma->strand_ease, -0.9, 0.9, 2, 0, "Shape of strands, positive value makes it rounder, negative makes it spiky");
+ uiDefBut(block, TEX, B_MATPRV, "UV:", butx,buty-=buth,butw,buth, ma->strand_uvname, 0, 31, 0, 0, "Set name of UV layer to override");
uiBlockSetDirection(block, UI_TOP);
BIF_preview_changed(ID_MA);