/*! init triangle divisions */ void calcTriangleDivs(Object *ob, MVert *verts, int numverts, MFace *faces, int numfaces, int numtris, int **tridivs, float cell_len) { // mTriangleDivs1.resize( faces.size() ); // mTriangleDivs2.resize( faces.size() ); // mTriangleDivs3.resize( faces.size() ); size_t i = 0, facecounter = 0; float maxscale[3] = {1,1,1}; // = channelFindMaxVf(mcScale); float maxpart = ABS(maxscale[0]); float scaleFac = 0; float fsTri = 0; if(ABS(maxscale[1])>maxpart) maxpart = ABS(maxscale[1]); if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]); scaleFac = 1.0 / maxpart; // featureSize = mLevel[mMaxRefine].nodeSize fsTri = cell_len * 0.5 * scaleFac; if(*tridivs) MEM_freeN(*tridivs); *tridivs = MEM_callocN(sizeof(int) * numtris * 3, "Smoke_Tridivs"); for(i = 0, facecounter = 0; i < numfaces; i++) { float p0[3], p1[3], p2[3]; float side1[3]; float side2[3]; float side3[3]; int divs1=0, divs2=0, divs3=0; VECCOPY(p0, verts[faces[i].v1].co); Mat4MulVecfl (ob->obmat, p0); VECCOPY(p1, verts[faces[i].v2].co); Mat4MulVecfl (ob->obmat, p1); VECCOPY(p2, verts[faces[i].v3].co); Mat4MulVecfl (ob->obmat, p2); VECSUB(side1, p1, p0); VECSUB(side2, p2, p0); VECSUB(side3, p1, p2); if(INPR(side1, side1) > fsTri*fsTri) { float tmp = Normalize(side1); divs1 = (int)ceil(tmp/fsTri); } if(INPR(side2, side2) > fsTri*fsTri) { float tmp = Normalize(side2); divs2 = (int)ceil(tmp/fsTri); /* // debug if(i==0) printf("b tmp: %f, fsTri: %f, divs2: %d\n", tmp, fsTri, divs2); */ } (*tridivs)[3 * facecounter + 0] = divs1; (*tridivs)[3 * facecounter + 1] = divs2; (*tridivs)[3 * facecounter + 2] = divs3; // TODO quad case if(faces[i].v4) { divs1=0, divs2=0, divs3=0; facecounter++; VECCOPY(p0, verts[faces[i].v3].co); Mat4MulVecfl (ob->obmat, p0); VECCOPY(p1, verts[faces[i].v4].co); Mat4MulVecfl (ob->obmat, p1); VECCOPY(p2, verts[faces[i].v1].co); Mat4MulVecfl (ob->obmat, p2); VECSUB(side1, p1, p0); VECSUB(side2, p2, p0); VECSUB(side3, p1, p2); if(INPR(side1, side1) > fsTri*fsTri) { float tmp = Normalize(side1); divs1 = (int)ceil(tmp/fsTri); } if(INPR(side2, side2) > fsTri*fsTri) { float tmp = Normalize(side2); divs2 = (int)ceil(tmp/fsTri); } (*tridivs)[3 * facecounter + 0] = divs1; (*tridivs)[3 * facecounter + 1] = divs2; (*tridivs)[3 * facecounter + 2] = divs3; } facecounter++; } }
static void traverse_octree(ScatterTree *tree, ScatterNode *node, float *co, int self, ScatterResult *result) { float sub[3], dist; int i, index = 0; if(node->totpoint > 0) { /* leaf - add radiance from all samples */ for(i=0; i<node->totpoint; i++) { ScatterPoint *p= &node->points[i]; VECSUB(sub, co, p->co); dist= INPR(sub, sub); if(p->back) add_radiance(tree, NULL, p->rad, 0.0f, p->area, dist, result); else add_radiance(tree, p->rad, NULL, p->area, 0.0f, dist, result); } } else { /* branch */ if (self) index = SUBNODE_INDEX(co, node->split); for(i=0; i<8; i++) { if(node->child[i]) { ScatterNode *subnode= node->child[i]; if(self && index == i) { /* always traverse node containing the point */ traverse_octree(tree, subnode, co, 1, result); } else { /* decide subnode traversal based on maximum solid angle */ VECSUB(sub, co, subnode->co); dist= INPR(sub, sub); /* actually area/dist > error, but this avoids division */ if(subnode->area+subnode->backarea>tree->error*dist) { traverse_octree(tree, subnode, co, 0, result); } else { add_radiance(tree, subnode->rad, subnode->backrad, subnode->area, subnode->backarea, dist, result); } } } } } }
/* generates normal, does dot product */ static void node_composit_exec_normal(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out) { bNodeSocket *sock= node->outputs.first; float *nor= ((bNodeSocketValueVector*)sock->default_value)->value; /* stack order input: normal */ /* stack order output: normal, value */ /* input no image? then only vector op */ if(in[0]->data==NULL) { VECCOPY(out[0]->vec, nor); /* render normals point inside... the widget points outside */ out[1]->vec[0]= -INPR(out[0]->vec, in[0]->vec); } else if(out[1]->hasoutput) { /* make output size of input image */ CompBuf *cbuf= in[0]->data; CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); /* allocs */ composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_normal, CB_VEC3); out[1]->data= stackbuf; } }
static void do_normal(bNode *node, float *out, float *in) { bNodeSocket *sock= node->outputs.first; float *nor= ((bNodeSocketValueVector*)sock->default_value)->value; /* render normals point inside... the widget points outside */ out[0]= -INPR(nor, in); }
static int convex(float *p0, float *up, float *a, float *b) { // Vec3 va = a-p0, vb = b-p0; float va[3], vb[3], tmp[3]; VECSUB(va, a, p0); VECSUB(vb, b, p0); cross_v3_v3v3(tmp, va, vb); return INPR(up, tmp) >= 0; }
/* generates normal, does dot product */ static void node_shader_exec_normal(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out) { bNodeSocket *sock= node->outputs.first; float vec[3]; /* stack order input: normal */ /* stack order output: normal, value */ nodestack_get_vec(vec, SOCK_VECTOR, in[0]); copy_v3_v3(out[0]->vec, ((bNodeSocketValueVector*)sock->default_value)->value); /* render normals point inside... the widget points outside */ out[1]->vec[0]= -INPR(out[0]->vec, vec); }
/* generates normal, does dot product */ static void node_shader_exec_normal(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { bNodeSocket *sock= node->outputs.first; float vec[3]; /* stack order input: normal */ /* stack order output: normal, value */ nodestack_get_vec(vec, SOCK_VECTOR, in[0]); VECCOPY(out[0]->vec, sock->ns.vec); /* render normals point inside... the widget points outside */ out[1]->vec[0]= -INPR(out[0]->vec, vec); }
/* our own triangle intersection, so we can fully control the epsilons and * prevent corner case from going wrong*/ static int meshdeform_tri_intersect(float orig[3], float end[3], float vert0[3], float vert1[3], float vert2[3], float *isectco, float *uvw) { float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; float det,inv_det, u, v, dir[3], isectdir[3]; sub_v3_v3v3(dir, end, orig); /* find vectors for two edges sharing vert0 */ sub_v3_v3v3(edge1, vert1, vert0); sub_v3_v3v3(edge2, vert2, vert0); /* begin calculating determinant - also used to calculate U parameter */ cross_v3_v3v3(pvec, dir, edge2); /* if determinant is near zero, ray lies in plane of triangle */ det = INPR(edge1, pvec); if (det == 0.0f) return 0; inv_det = 1.0f / det; /* calculate distance from vert0 to ray origin */ sub_v3_v3v3(tvec, orig, vert0); /* calculate U parameter and test bounds */ u = INPR(tvec, pvec) * inv_det; if (u < -EPSILON || u > 1.0f+EPSILON) return 0; /* prepare to test V parameter */ cross_v3_v3v3(qvec, tvec, edge1); /* calculate V parameter and test bounds */ v = INPR(dir, qvec) * inv_det; if (v < -EPSILON || u + v > 1.0f+EPSILON) return 0; isectco[0]= (1.0f - u - v)*vert0[0] + u*vert1[0] + v*vert2[0]; isectco[1]= (1.0f - u - v)*vert0[1] + u*vert1[1] + v*vert2[1]; isectco[2]= (1.0f - u - v)*vert0[2] + u*vert1[2] + v*vert2[2]; uvw[0]= 1.0f - u - v; uvw[1]= u; uvw[2]= v; /* check if it is within the length of the line segment */ sub_v3_v3v3(isectdir, isectco, orig); if(INPR(dir, isectdir) < -EPSILON) return 0; if(INPR(dir, dir) + EPSILON < INPR(isectdir, isectdir)) return 0; return 1; }
static int meshdeform_intersect(MeshDeformBind *mdb, MeshDeformIsect *isec) { MFace *mface; float face[4][3], co[3], uvw[3], len, nor[3], end[3]; int f, hit, is= 0, totface; isec->labda= 1e10; mface= mdb->cagedm->getFaceArray(mdb->cagedm); totface= mdb->cagedm->getNumFaces(mdb->cagedm); add_v3_v3v3(end, isec->start, isec->vec); for(f=0; f<totface; f++, mface++) { copy_v3_v3(face[0], mdb->cagecos[mface->v1]); copy_v3_v3(face[1], mdb->cagecos[mface->v2]); copy_v3_v3(face[2], mdb->cagecos[mface->v3]); if(mface->v4) { copy_v3_v3(face[3], mdb->cagecos[mface->v4]); hit = meshdeform_tri_intersect(isec->start, end, face[0], face[1], face[2], co, uvw); if(hit) { normal_tri_v3( nor,face[0], face[1], face[2]); } else { hit= meshdeform_tri_intersect(isec->start, end, face[0], face[2], face[3], co, uvw); normal_tri_v3( nor,face[0], face[2], face[3]); } } else { hit= meshdeform_tri_intersect(isec->start, end, face[0], face[1], face[2], co, uvw); normal_tri_v3( nor,face[0], face[1], face[2]); } if(hit) { len= len_v3v3(isec->start, co)/len_v3v3(isec->start, end); if(len < isec->labda) { isec->labda= len; isec->face = mface; isec->isect= (INPR(isec->vec, nor) <= 0.0f); is= 1; } } } return is; }
static float heat_source_distance(LaplacianSystem *sys, int vertex, int source) { float closest[3], d[3], dist, cosine; /* compute euclidian distance */ if(sys->heat.root) /* bone */ closest_to_line_segment_v3(closest, sys->heat.verts[vertex], sys->heat.root[source], sys->heat.tip[source]); else /* vertex */ copy_v3_v3(closest, sys->heat.source[source]); sub_v3_v3v3(d, sys->heat.verts[vertex], closest); dist= normalize_v3(d); /* if the vertex normal does not point along the bone, increase distance */ cosine= INPR(d, sys->heat.vnors[vertex]); return dist/(0.5f*(cosine + 1.001f)); }
static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) { Cloth *cloth = clmd->clothObject; ClothSpring *spring = NULL, *tspring = NULL, *tspring2 = NULL; unsigned int struct_springs = 0, shear_springs=0, bend_springs = 0; unsigned int i = 0; unsigned int numverts = (unsigned int)dm->getNumVerts ( dm ); unsigned int numedges = (unsigned int)dm->getNumEdges ( dm ); unsigned int numfaces = (unsigned int)dm->getNumFaces ( dm ); MEdge *medge = dm->getEdgeArray ( dm ); MFace *mface = dm->getFaceArray ( dm ); int index2 = 0; // our second vertex index LinkNode **edgelist = NULL; EdgeHash *edgehash = NULL; LinkNode *search = NULL, *search2 = NULL; float temp[3]; // error handling if ( numedges==0 ) return 0; cloth->springs = NULL; edgelist = MEM_callocN ( sizeof ( LinkNode * ) * numverts, "cloth_edgelist_alloc" ); if(!edgelist) return 0; for ( i = 0; i < numverts; i++ ) { edgelist[i] = NULL; } if ( cloth->springs ) MEM_freeN ( cloth->springs ); // create spring network hash edgehash = BLI_edgehash_new(); // structural springs for ( i = 0; i < numedges; i++ ) { spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if ( spring ) { spring->ij = MIN2(medge[i].v1, medge[i].v2); spring->kl = MAX2(medge[i].v2, medge[i].v1); VECSUB ( temp, cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest ); spring->restlen = sqrt ( INPR ( temp, temp ) ); clmd->sim_parms->avg_spring_len += spring->restlen; cloth->verts[spring->ij].avg_spring_len += spring->restlen; cloth->verts[spring->kl].avg_spring_len += spring->restlen; cloth->verts[spring->ij].spring_count++; cloth->verts[spring->kl].spring_count++; spring->type = CLOTH_SPRING_TYPE_STRUCTURAL; spring->flags = 0; spring->stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0; struct_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } else { cloth_free_errorsprings(cloth, edgehash, edgelist); return 0; } } if(struct_springs > 0) clmd->sim_parms->avg_spring_len /= struct_springs; for(i = 0; i < numverts; i++) { cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49 / ((float)cloth->verts[i].spring_count); } // shear springs for ( i = 0; i < numfaces; i++ ) { // triangle faces already have shear springs due to structural geometry if ( !mface[i].v4 ) continue; spring = ( ClothSpring *) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if(!spring) { cloth_free_errorsprings(cloth, edgehash, edgelist); return 0; } spring->ij = MIN2(mface[i].v1, mface[i].v3); spring->kl = MAX2(mface[i].v3, mface[i].v1); VECSUB ( temp, cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest ); spring->restlen = sqrt ( INPR ( temp, temp ) ); spring->type = CLOTH_SPRING_TYPE_SHEAR; spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0; BLI_linklist_append ( &edgelist[spring->ij], spring ); BLI_linklist_append ( &edgelist[spring->kl], spring ); shear_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); // if ( mface[i].v4 ) --> Quad face spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if(!spring) { cloth_free_errorsprings(cloth, edgehash, edgelist); return 0; } spring->ij = MIN2(mface[i].v2, mface[i].v4); spring->kl = MAX2(mface[i].v4, mface[i].v2); VECSUB ( temp, cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest ); spring->restlen = sqrt ( INPR ( temp, temp ) ); spring->type = CLOTH_SPRING_TYPE_SHEAR; spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0; BLI_linklist_append ( &edgelist[spring->ij], spring ); BLI_linklist_append ( &edgelist[spring->kl], spring ); shear_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } if(numfaces) { // bending springs search2 = cloth->springs; for ( i = struct_springs; i < struct_springs+shear_springs; i++ ) { if ( !search2 ) break; tspring2 = search2->link; search = edgelist[tspring2->kl]; while ( search ) { tspring = search->link; index2 = ( ( tspring->ij==tspring2->kl ) ? ( tspring->kl ) : ( tspring->ij ) ); // check for existing spring // check also if startpoint is equal to endpoint if ( !BLI_edgehash_haskey ( edgehash, MIN2(tspring2->ij, index2), MAX2(tspring2->ij, index2) ) && ( index2!=tspring2->ij ) ) { spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if(!spring) { cloth_free_errorsprings(cloth, edgehash, edgelist); return 0; } spring->ij = MIN2(tspring2->ij, index2); spring->kl = MAX2(tspring2->ij, index2); VECSUB ( temp, cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest ); spring->restlen = sqrt ( INPR ( temp, temp ) ); spring->type = CLOTH_SPRING_TYPE_BENDING; spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0; BLI_edgehash_insert ( edgehash, spring->ij, spring->kl, NULL ); bend_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } search = search->next; } search2 = search2->next; } } else if(struct_springs > 2) { /* bending springs for hair strands */ /* The current algorightm only goes through the edges in order of the mesh edges list */ /* and makes springs between the outer vert of edges sharing a vertice. This works just */ /* fine for hair, but not for user generated string meshes. This could/should be later */ /* extended to work with non-ordered edges so that it can be used for general "rope */ /* dynamics" without the need for the vertices or edges to be ordered through the length*/ /* of the strands. -jahka */ search = cloth->springs; search2 = search->next; while(search && search2) { tspring = search->link; tspring2 = search2->link; if(tspring->ij == tspring2->kl) { spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if(!spring) { cloth_free_errorsprings(cloth, edgehash, edgelist); return 0; } spring->ij = tspring2->ij; spring->kl = tspring->kl; VECSUB ( temp, cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest ); spring->restlen = sqrt ( INPR ( temp, temp ) ); spring->type = CLOTH_SPRING_TYPE_BENDING; spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0; bend_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } search = search->next; search2 = search2->next; } } /* insert other near springs in edgehash AFTER bending springs are calculated (for selfcolls) */ for ( i = 0; i < numedges; i++ ) // struct springs BLI_edgehash_insert ( edgehash, MIN2(medge[i].v1, medge[i].v2), MAX2(medge[i].v2, medge[i].v1), NULL ); for ( i = 0; i < numfaces; i++ ) // edge springs { if(mface[i].v4) { BLI_edgehash_insert ( edgehash, MIN2(mface[i].v1, mface[i].v3), MAX2(mface[i].v3, mface[i].v1), NULL ); BLI_edgehash_insert ( edgehash, MIN2(mface[i].v2, mface[i].v4), MAX2(mface[i].v2, mface[i].v4), NULL ); } } cloth->numsprings = struct_springs + shear_springs + bend_springs; if ( edgelist ) { for ( i = 0; i < numverts; i++ ) { BLI_linklist_free ( edgelist[i],NULL ); } MEM_freeN ( edgelist ); } cloth->edgehash = edgehash; if(G.rt>0) printf("avg_len: %f\n",clmd->sim_parms->avg_spring_len); return 1; } /* cloth_build_springs */
void draw_volume(ARegion *ar, GPUTexture *tex, float *min, float *max, int res[3], float dx, GPUTexture *tex_shadow) { RegionView3D *rv3d= ar->regiondata; float viewnormal[3]; int i, j, n, good_index; float d, d0, dd, ds; float *points = NULL; int numpoints = 0; float cor[3] = {1.,1.,1.}; int gl_depth = 0, gl_blend = 0; /* draw slices of smoke is adapted from c++ code authored by: Johannes Schmid and Ingemar Rask, 2006, [email protected] */ float cv[][3] = { {1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, {1.0f, -1.0f, 1.0f}, {1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}, {1.0f, -1.0f, -1.0f} }; // edges have the form edges[n][0][xyz] + t*edges[n][1][xyz] float edges[12][2][3] = { {{1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}}, {{-1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}}, {{-1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}}, {{1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}}, {{-1.0f, 1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}}, {{-1.0f, -1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}}, {{-1.0f, -1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}}, {{-1.0f, 1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}} }; /* Fragment program to calculate the view3d of smoke */ /* using 2 textures, density and shadow */ const char *text = "!!ARBfp1.0\n" "PARAM dx = program.local[0];\n" "PARAM darkness = program.local[1];\n" "PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01};\n" "TEMP temp, shadow, value;\n" "TEX temp, fragment.texcoord[0], texture[0], 3D;\n" "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n" "MUL value, temp, darkness;\n" "MUL value, value, dx;\n" "MUL value, value, f;\n" "EX2 temp, -value.r;\n" "SUB temp.a, 1.0, temp.r;\n" "MUL temp.r, temp.r, shadow.r;\n" "MUL temp.g, temp.g, shadow.r;\n" "MUL temp.b, temp.b, shadow.r;\n" "MOV result.color, temp;\n" "END\n"; GLuint prog; float size[3]; if(!tex) { printf("Could not allocate 3D texture for 3D View smoke drawing.\n"); return; } tstart(); VECSUB(size, max, min); // maxx, maxy, maxz cv[0][0] = max[0]; cv[0][1] = max[1]; cv[0][2] = max[2]; // minx, maxy, maxz cv[1][0] = min[0]; cv[1][1] = max[1]; cv[1][2] = max[2]; // minx, miny, maxz cv[2][0] = min[0]; cv[2][1] = min[1]; cv[2][2] = max[2]; // maxx, miny, maxz cv[3][0] = max[0]; cv[3][1] = min[1]; cv[3][2] = max[2]; // maxx, maxy, minz cv[4][0] = max[0]; cv[4][1] = max[1]; cv[4][2] = min[2]; // minx, maxy, minz cv[5][0] = min[0]; cv[5][1] = max[1]; cv[5][2] = min[2]; // minx, miny, minz cv[6][0] = min[0]; cv[6][1] = min[1]; cv[6][2] = min[2]; // maxx, miny, minz cv[7][0] = max[0]; cv[7][1] = min[1]; cv[7][2] = min[2]; VECCOPY(edges[0][0], cv[4]); // maxx, maxy, minz VECCOPY(edges[1][0], cv[5]); // minx, maxy, minz VECCOPY(edges[2][0], cv[6]); // minx, miny, minz VECCOPY(edges[3][0], cv[7]); // maxx, miny, minz VECCOPY(edges[4][0], cv[3]); // maxx, miny, maxz VECCOPY(edges[5][0], cv[2]); // minx, miny, maxz VECCOPY(edges[6][0], cv[6]); // minx, miny, minz VECCOPY(edges[7][0], cv[7]); // maxx, miny, minz VECCOPY(edges[8][0], cv[1]); // minx, maxy, maxz VECCOPY(edges[9][0], cv[2]); // minx, miny, maxz VECCOPY(edges[10][0], cv[6]); // minx, miny, minz VECCOPY(edges[11][0], cv[5]); // minx, maxy, minz // printf("size x: %f, y: %f, z: %f\n", size[0], size[1], size[2]); // printf("min[2]: %f, max[2]: %f\n", min[2], max[2]); edges[0][1][2] = size[2]; edges[1][1][2] = size[2]; edges[2][1][2] = size[2]; edges[3][1][2] = size[2]; edges[4][1][1] = size[1]; edges[5][1][1] = size[1]; edges[6][1][1] = size[1]; edges[7][1][1] = size[1]; edges[8][1][0] = size[0]; edges[9][1][0] = size[0]; edges[10][1][0] = size[0]; edges[11][1][0] = size[0]; glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend); glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth); glLoadMatrixf(rv3d->viewmat); // glMultMatrixf(ob->obmat); glDepthMask(GL_FALSE); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /* printf("Viewinv:\n"); printf("%f, %f, %f\n", rv3d->viewinv[0][0], rv3d->viewinv[0][1], rv3d->viewinv[0][2]); printf("%f, %f, %f\n", rv3d->viewinv[1][0], rv3d->viewinv[1][1], rv3d->viewinv[1][2]); printf("%f, %f, %f\n", rv3d->viewinv[2][0], rv3d->viewinv[2][1], rv3d->viewinv[2][2]); */ // get view vector VECCOPY(viewnormal, rv3d->viewinv[2]); normalize_v3(viewnormal); // find cube vertex that is closest to the viewer for (i=0; i<8; i++) { float x,y,z; x = cv[i][0] - viewnormal[0]; y = cv[i][1] - viewnormal[1]; z = cv[i][2] - viewnormal[2]; if ((x>=min[0])&&(x<=max[0]) &&(y>=min[1])&&(y<=max[1]) &&(z>=min[2])&&(z<=max[2])) { break; } } if(i >= 8) { /* fallback, avoid using buffer over-run */ i= 0; } // printf("i: %d\n", i); // printf("point %f, %f, %f\n", cv[i][0], cv[i][1], cv[i][2]); if (GL_TRUE == glewIsSupported("GL_ARB_fragment_program")) { glEnable(GL_FRAGMENT_PROGRAM_ARB); glGenProgramsARB(1, &prog); glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, prog); glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(text), text); // cell spacing glProgramLocalParameter4fARB (GL_FRAGMENT_PROGRAM_ARB, 0, dx, dx, dx, 1.0); // custom parameter for smoke style (higher = thicker) glProgramLocalParameter4fARB (GL_FRAGMENT_PROGRAM_ARB, 1, 7.0, 7.0, 7.0, 1.0); } else printf("Your gfx card does not support 3D View smoke drawing.\n"); GPU_texture_bind(tex, 0); if(tex_shadow) GPU_texture_bind(tex_shadow, 1); else printf("No volume shadow\n"); if (!GPU_non_power_of_two_support()) { cor[0] = (float)res[0]/(float)larger_pow2(res[0]); cor[1] = (float)res[1]/(float)larger_pow2(res[1]); cor[2] = (float)res[2]/(float)larger_pow2(res[2]); } // our slices are defined by the plane equation a*x + b*y +c*z + d = 0 // (a,b,c), the plane normal, are given by viewdir // d is the parameter along the view direction. the first d is given by // inserting previously found vertex into the plane equation d0 = (viewnormal[0]*cv[i][0] + viewnormal[1]*cv[i][1] + viewnormal[2]*cv[i][2]); ds = (ABS(viewnormal[0])*size[0] + ABS(viewnormal[1])*size[1] + ABS(viewnormal[2])*size[2]); dd = 0.05; // ds/512.0f; n = 0; good_index = i; // printf("d0: %f, dd: %f, ds: %f\n\n", d0, dd, ds); points = MEM_callocN(sizeof(float)*12*3, "smoke_points_preview"); while(1) { float p0[3]; float tmp_point[3], tmp_point2[3]; if(dd*(float)n > ds) break; VECCOPY(tmp_point, viewnormal); mul_v3_fl(tmp_point, -dd*((ds/dd)-(float)n)); VECADD(tmp_point2, cv[good_index], tmp_point); d = INPR(tmp_point2, viewnormal); // printf("my d: %f\n", d); // intersect_edges returns the intersection points of all cube edges with // the given plane that lie within the cube numpoints = intersect_edges(points, viewnormal[0], viewnormal[1], viewnormal[2], -d, edges); // printf("points: %d\n", numpoints); if (numpoints > 2) { VECCOPY(p0, points); // sort points to get a convex polygon for(i = 1; i < numpoints - 1; i++) { for(j = i + 1; j < numpoints; j++) { if(!convex(p0, viewnormal, &points[j * 3], &points[i * 3])) { float tmp2[3]; VECCOPY(tmp2, &points[j * 3]); VECCOPY(&points[j * 3], &points[i * 3]); VECCOPY(&points[i * 3], tmp2); } } } // printf("numpoints: %d\n", numpoints); glBegin(GL_POLYGON); glColor3f(1.0, 1.0, 1.0); for (i = 0; i < numpoints; i++) { glTexCoord3d((points[i * 3 + 0] - min[0] )*cor[0]/size[0], (points[i * 3 + 1] - min[1])*cor[1]/size[1], (points[i * 3 + 2] - min[2])*cor[2]/size[2]); glVertex3f(points[i * 3 + 0], points[i * 3 + 1], points[i * 3 + 2]); } glEnd(); } n++; } tend(); // printf ( "Draw Time: %f\n",( float ) tval() ); if(tex_shadow) GPU_texture_unbind(tex_shadow); GPU_texture_unbind(tex); if(GLEW_ARB_fragment_program) { glDisable(GL_FRAGMENT_PROGRAM_ARB); glDeleteProgramsARB(1, &prog); } MEM_freeN(points); if(!gl_blend) glDisable(GL_BLEND); if(gl_depth) { glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); } }
/* * Function adapted from David Eberly's distance tools (LGPL) * http://www.geometrictools.com/LibFoundation/Distance/Distance.html */ static float nearest_point_in_tri_surface(const float *v0,const float *v1,const float *v2,const float *p, int *v, int *e, float *nearest ) { float diff[3]; float e0[3]; float e1[3]; float A00; float A01; float A11; float B0; float B1; float C; float Det; float S; float T; float sqrDist; int lv = -1, le = -1; VECSUB(diff, v0, p); VECSUB(e0, v1, v0); VECSUB(e1, v2, v0); A00 = INPR ( e0, e0 ); A01 = INPR( e0, e1 ); A11 = INPR ( e1, e1 ); B0 = INPR( diff, e0 ); B1 = INPR( diff, e1 ); C = INPR( diff, diff ); Det = fabs( A00 * A11 - A01 * A01 ); S = A01 * B1 - A11 * B0; T = A01 * B0 - A00 * B1; if ( S + T <= Det ) { if ( S < 0.0f ) { if ( T < 0.0f ) // Region 4 { if ( B0 < 0.0f ) { T = 0.0f; if ( -B0 >= A00 ) { S = (float)1.0; sqrDist = A00 + 2.0f * B0 + C; lv = 1; } else { if(fabsf(A00) > FLT_EPSILON) S = -B0/A00; else S = 0.0f; sqrDist = B0 * S + C; le = 0; } } else { S = 0.0f; if ( B1 >= 0.0f ) { T = 0.0f; sqrDist = C; lv = 0; } else if ( -B1 >= A11 ) { T = 1.0f; sqrDist = A11 + 2.0f * B1 + C; lv = 2; } else { if(fabsf(A11) > FLT_EPSILON) T = -B1 / A11; else T = 0.0f; sqrDist = B1 * T + C; le = 1; } } } else // Region 3 { S = 0.0f; if ( B1 >= 0.0f ) { T = 0.0f; sqrDist = C; lv = 0; } else if ( -B1 >= A11 ) { T = 1.0f; sqrDist = A11 + 2.0f * B1 + C; lv = 2; } else { if(fabsf(A11) > FLT_EPSILON) T = -B1 / A11; else T = 0.0; sqrDist = B1 * T + C; le = 1; } } } else if ( T < 0.0f ) // Region 5 { T = 0.0f; if ( B0 >= 0.0f ) { S = 0.0f; sqrDist = C; lv = 0; } else if ( -B0 >= A00 ) { S = 1.0f; sqrDist = A00 + 2.0f * B0 + C; lv = 1; } else { if(fabsf(A00) > FLT_EPSILON) S = -B0 / A00; else S = 0.0f; sqrDist = B0 * S + C; le = 0; } } else // Region 0 { // Minimum at interior lv float invDet; if(fabsf(Det) > FLT_EPSILON) invDet = 1.0f / Det; else invDet = 0.0f; S *= invDet; T *= invDet; sqrDist = S * ( A00 * S + A01 * T + 2.0f * B0) + T * ( A01 * S + A11 * T + 2.0f * B1 ) + C; } } else { float tmp0, tmp1, numer, denom; if ( S < 0.0f ) // Region 2 { tmp0 = A01 + B0; tmp1 = A11 + B1; if ( tmp1 > tmp0 ) { numer = tmp1 - tmp0; denom = A00 - 2.0f * A01 + A11; if ( numer >= denom ) { S = 1.0f; T = 0.0f; sqrDist = A00 + 2.0f * B0 + C; lv = 1; } else { if(fabsf(denom) > FLT_EPSILON) S = numer / denom; else S = 0.0f; T = 1.0f - S; sqrDist = S * ( A00 * S + A01 * T + 2.0f * B0 ) + T * ( A01 * S + A11 * T + 2.0f * B1 ) + C; le = 2; } } else { S = 0.0f; if ( tmp1 <= 0.0f ) { T = 1.0f; sqrDist = A11 + 2.0f * B1 + C; lv = 2; } else if ( B1 >= 0.0f ) { T = 0.0f; sqrDist = C; lv = 0; } else { if(fabsf(A11) > FLT_EPSILON) T = -B1 / A11; else T = 0.0f; sqrDist = B1 * T + C; le = 1; } } } else if ( T < 0.0f ) // Region 6 { tmp0 = A01 + B1; tmp1 = A00 + B0; if ( tmp1 > tmp0 ) { numer = tmp1 - tmp0; denom = A00 - 2.0f * A01 + A11; if ( numer >= denom ) { T = 1.0f; S = 0.0f; sqrDist = A11 + 2.0f * B1 + C; lv = 2; } else { if(fabsf(denom) > FLT_EPSILON) T = numer / denom; else T = 0.0f; S = 1.0f - T; sqrDist = S * ( A00 * S + A01 * T + 2.0f * B0 ) + T * ( A01 * S + A11 * T + 2.0f * B1 ) + C; le = 2; } } else { T = 0.0f; if ( tmp1 <= 0.0f ) { S = 1.0f; sqrDist = A00 + 2.0f * B0 + C; lv = 1; } else if ( B0 >= 0.0f ) { S = 0.0f; sqrDist = C; lv = 0; } else { if(fabsf(A00) > FLT_EPSILON) S = -B0 / A00; else S = 0.0f; sqrDist = B0 * S + C; le = 0; } } } else // Region 1 { numer = A11 + B1 - A01 - B0; if ( numer <= 0.0f ) { S = 0.0f; T = 1.0f; sqrDist = A11 + 2.0f * B1 + C; lv = 2; } else { denom = A00 - 2.0f * A01 + A11; if ( numer >= denom ) { S = 1.0f; T = 0.0f; sqrDist = A00 + 2.0f * B0 + C; lv = 1; } else { if(fabsf(denom) > FLT_EPSILON) S = numer / denom; else S = 0.0f; T = 1.0f - S; sqrDist = S * ( A00 * S + A01 * T + 2.0f * B0 ) + T * ( A01 * S + A11 * T + 2.0f * B1 ) + C; le = 2; } } } } // Account for numerical round-off error if ( sqrDist < FLT_EPSILON ) sqrDist = 0.0f; { float w[3], x[3], y[3], z[3]; VECCOPY(w, v0); VECCOPY(x, e0); mul_v3_fl(x, S); VECCOPY(y, e1); mul_v3_fl(y, T); VECADD(z, w, x); VECADD(z, z, y); //VECSUB(d, p, z); VECCOPY(nearest, z); // d = p - ( v0 + S * e0 + T * e1 ); } *v = lv; *e = le; return sqrDist; }