/* note: this function could be optimized by some spatial structure */ static PyObject *M_Geometry_points_in_planes(PyObject *UNUSED(self), PyObject *args) { PyObject *py_planes; float (*planes)[4]; unsigned int planes_len; if (!PyArg_ParseTuple(args, "O:points_in_planes", &py_planes)) { return NULL; } if ((planes_len = mathutils_array_parse_alloc_v((float **)&planes, 4, py_planes, "points_in_planes")) == -1) { return NULL; } else { /* note, this could be refactored into plain C easy - py bits are noted */ const float eps = 0.0001f; const unsigned int len = (unsigned int)planes_len; unsigned int i, j, k, l; float n1n2[3], n2n3[3], n3n1[3]; float potentialVertex[3]; char *planes_used = MEM_callocN(sizeof(char) * len, __func__); /* python */ PyObject *py_verts = PyList_New(0); PyObject *py_plene_index = PyList_New(0); for (i = 0; i < len; i++) { const float *N1 = planes[i]; for (j = i + 1; j < len; j++) { const float *N2 = planes[j]; cross_v3_v3v3(n1n2, N1, N2); if (len_squared_v3(n1n2) > eps) { for (k = j + 1; k < len; k++) { const float *N3 = planes[k]; cross_v3_v3v3(n2n3, N2, N3); if (len_squared_v3(n2n3) > eps) { cross_v3_v3v3(n3n1, N3, N1); if (len_squared_v3(n3n1) > eps) { const float quotient = dot_v3v3(N1, n2n3); if (fabsf(quotient) > eps) { /* potentialVertex = (n2n3 * N1[3] + n3n1 * N2[3] + n1n2 * N3[3]) * (-1.0 / quotient); */ const float quotient_ninv = -1.0f / quotient; potentialVertex[0] = ((n2n3[0] * N1[3]) + (n3n1[0] * N2[3]) + (n1n2[0] * N3[3])) * quotient_ninv; potentialVertex[1] = ((n2n3[1] * N1[3]) + (n3n1[1] * N2[3]) + (n1n2[1] * N3[3])) * quotient_ninv; potentialVertex[2] = ((n2n3[2] * N1[3]) + (n3n1[2] * N2[3]) + (n1n2[2] * N3[3])) * quotient_ninv; for (l = 0; l < len; l++) { const float *NP = planes[l]; if ((dot_v3v3(NP, potentialVertex) + NP[3]) > 0.000001f) { break; } } if (l == len) { /* ok */ /* python */ PyObject *item = Vector_CreatePyObject(potentialVertex, 3, Py_NEW, NULL); PyList_Append(py_verts, item); Py_DECREF(item); planes_used[i] = planes_used[j] = planes_used[k] = TRUE; } } } } } } } } PyMem_Free(planes); /* now make a list of used planes */ for (i = 0; i < len; i++) { if (planes_used[i]) { PyObject *item = PyLong_FromLong(i); PyList_Append(py_plene_index, item); Py_DECREF(item); } } MEM_freeN(planes_used); { PyObject *ret = PyTuple_New(2); PyTuple_SET_ITEM(ret, 0, py_verts); PyTuple_SET_ITEM(ret, 1, py_plene_index); return ret; } } }
/** * Makes an NGon from an un-ordered set of verts * * assumes... * - that verts are only once in the list. * - that the verts have roughly planer bounds * - that the verts are roughly circular * there can be concave areas but overlapping folds from the center point will fail. * * a brief explanation of the method used * - find the center point * - find the normal of the vcloud * - order the verts around the face based on their angle to the normal vector at the center point. * * \note Since this is a vcloud there is no direction. */ void BM_verts_sort_radial_plane(BMVert **vert_arr, int len) { struct SortIntByFloat *vang = BLI_array_alloca(vang, len); BMVert **vert_arr_map = BLI_array_alloca(vert_arr_map, len); float totv_inv = 1.0f / (float)len; int i = 0; float cent[3], nor[3]; const float *far = NULL, *far_cross = NULL; float far_vec[3]; float far_cross_vec[3]; float sign_vec[3]; /* work out if we are pos/neg angle */ float far_dist_sq, far_dist_max_sq; float far_cross_dist, far_cross_best = 0.0f; /* get the center point and collect vector array since we loop over these a lot */ zero_v3(cent); for (i = 0; i < len; i++) { madd_v3_v3fl(cent, vert_arr[i]->co, totv_inv); } /* find the far point from cent */ far_dist_max_sq = 0.0f; for (i = 0; i < len; i++) { far_dist_sq = len_squared_v3v3(vert_arr[i]->co, cent); if (far_dist_sq > far_dist_max_sq || far == NULL) { far = vert_arr[i]->co; far_dist_max_sq = far_dist_sq; } } sub_v3_v3v3(far_vec, far, cent); // far_dist = len_v3(far_vec); /* real dist */ /* UNUSED */ /* --- */ /* find a point 90deg about to compare with */ far_cross_best = 0.0f; for (i = 0; i < len; i++) { if (far == vert_arr[i]->co) { continue; } sub_v3_v3v3(far_cross_vec, vert_arr[i]->co, cent); far_cross_dist = normalize_v3(far_cross_vec); /* more of a weight then a distance */ far_cross_dist = (/* first we want to have a value close to zero mapped to 1 */ 1.0f - fabsf(dot_v3v3(far_vec, far_cross_vec)) * /* second we multiply by the distance * so points close to the center are not preferred */ far_cross_dist); if (far_cross_dist > far_cross_best || far_cross == NULL) { far_cross = vert_arr[i]->co; far_cross_best = far_cross_dist; } } sub_v3_v3v3(far_cross_vec, far_cross, cent); /* --- */ /* now we have 2 vectors we can have a cross product */ cross_v3_v3v3(nor, far_vec, far_cross_vec); normalize_v3(nor); cross_v3_v3v3(sign_vec, far_vec, nor); /* this vector should match 'far_cross_vec' closely */ /* --- */ /* now calculate every points angle around the normal (signed) */ for (i = 0; i < len; i++) { vang[i].sort_value = angle_signed_on_axis_v3v3v3_v3(far, cent, vert_arr[i]->co, nor); vang[i].data = i; vert_arr_map[i] = vert_arr[i]; } /* sort by angle and magic! - we have our ngon */ qsort(vang, len, sizeof(*vang), BLI_sortutil_cmp_float); /* --- */ for (i = 0; i < len; i++) { vert_arr[i] = vert_arr_map[vang[i].data]; } }
int nextLengthSubdivision(ToolSettings *toolsettings, BArcIterator *iter, int start, int end, float head[3], float p[3]) { float lengthLimit = toolsettings->skgen_length_limit; int same = 1; int i; i = start + 1; while (i <= end) { float *vec0; float *vec1; IT_peek(iter, i - 1); vec0 = iter->p; IT_peek(iter, i); vec1 = iter->p; /* If lengthLimit hits the current segment */ if (len_v3v3(vec1, head) > lengthLimit) { if (same == 0) { float dv[3], off[3]; float a, b, c, f; /* Solve quadratic distance equation */ sub_v3_v3v3(dv, vec1, vec0); a = dot_v3v3(dv, dv); sub_v3_v3v3(off, vec0, head); b = 2 * dot_v3v3(dv, off); c = dot_v3v3(off, off) - (lengthLimit * lengthLimit); f = (-b + (float)sqrt(b * b - 4 * a * c)) / (2 * a); //printf("a %f, b %f, c %f, f %f\n", a, b, c, f); if (isnan(f) == 0 && f < 1.0f) { VECCOPY(p, dv); mul_v3_fl(p, f); add_v3_v3(p, vec0); } else { VECCOPY(p, vec1); } } else { float dv[3]; sub_v3_v3v3(dv, vec1, vec0); normalize_v3(dv); VECCOPY(p, dv); mul_v3_fl(p, lengthLimit); add_v3_v3(p, head); } return i - 1; /* restart at lower bound */ } else { i++; same = 0; // Reset same } } return -1; }
/* * Function adapted from David Eberly's distance tools (LGPL) * http://www.geometrictools.com/LibFoundation/Distance/Distance.html */ float nearest_point_in_tri_surface(const float v0[3], const float v1[3], const float v2[3], const float p[3], int *v, int *e, float nearest[3]) { 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; sub_v3_v3v3(diff, v0, p); sub_v3_v3v3(e0, v1, v0); sub_v3_v3v3(e1, v2, v0); A00 = dot_v3v3(e0, e0); A01 = dot_v3v3(e0, e1); A11 = dot_v3v3(e1, e1); B0 = dot_v3v3(diff, e0); B1 = dot_v3v3(diff, e1); C = dot_v3v3(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 = 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 { 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]; copy_v3_v3(w, v0); copy_v3_v3(x, e0); mul_v3_fl(x, S); copy_v3_v3(y, e1); mul_v3_fl(y, T); add_v3_v3v3(z, w, x); add_v3_v3v3(z, z, y); //sub_v3_v3v3(d, p, z); copy_v3_v3(nearest, z); //d = p - ( v0 + S * e0 + T * e1 ); } *v = lv; *e = le; return sqrDist; }
static void axisProjection(TransInfo *t, float axis[3], float in[3], float out[3]) { float norm[3], vec[3], factor, angle; float t_con_center[3]; if(in[0]==0.0f && in[1]==0.0f && in[2]==0.0f) return; copy_v3_v3(t_con_center, t->con.center); /* checks for center being too close to the view center */ viewAxisCorrectCenter(t, t_con_center); angle = fabsf(angle_v3v3(axis, t->viewinv[2])); if (angle > (float)M_PI / 2.0f) { angle = (float)M_PI - angle; } angle = RAD2DEGF(angle); /* For when view is parallel to constraint... will cause NaNs otherwise So we take vertical motion in 3D space and apply it to the constraint axis. Nice for camera grab + MMB */ if(angle < 5.0f) { project_v3_v3v3(vec, in, t->viewinv[1]); factor = dot_v3v3(t->viewinv[1], vec) * 2.0f; /* since camera distance is quite relative, use quadratic relationship. holding shift can compensate */ if(factor<0.0f) factor*= -factor; else factor*= factor; VECCOPY(out, axis); normalize_v3(out); mul_v3_fl(out, -factor); /* -factor makes move down going backwards */ } else { float v[3], i1[3], i2[3]; float v2[3], v4[3]; float norm_center[3]; float plane[3]; getViewVector(t, t_con_center, norm_center); cross_v3_v3v3(plane, norm_center, axis); project_v3_v3v3(vec, in, plane); sub_v3_v3v3(vec, in, vec); add_v3_v3v3(v, vec, t_con_center); getViewVector(t, v, norm); /* give arbitrary large value if projection is impossible */ factor = dot_v3v3(axis, norm); if (1.0f - fabsf(factor) < 0.0002f) { VECCOPY(out, axis); if (factor > 0) { mul_v3_fl(out, 1000000000.0f); } else { mul_v3_fl(out, -1000000000.0f); } } else { add_v3_v3v3(v2, t_con_center, axis); add_v3_v3v3(v4, v, norm); isect_line_line_v3(t_con_center, v2, v, v4, i1, i2); sub_v3_v3v3(v, i2, v); sub_v3_v3v3(out, i1, t_con_center); /* possible some values become nan when * viewpoint and object are both zero */ if(!finite(out[0])) out[0]= 0.0f; if(!finite(out[1])) out[1]= 0.0f; if(!finite(out[2])) out[2]= 0.0f; } } }
static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa) { BoidRuleAvoidCollision *acbr = (BoidRuleAvoidCollision*) rule; KDTreeNearest *ptn = NULL; ParticleTarget *pt; BoidParticle *bpa = pa->boid; ColliderCache *coll; float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f}; float co1[3], vel1[3], co2[3], vel2[3]; float len, t, inp, t_min = 2.0f; int n, neighbors = 0, nearest = 0; int ret = 0; //check deflector objects first if (acbr->options & BRULE_ACOLL_WITH_DEFLECTORS && bbd->sim->colliders) { ParticleCollision col; BVHTreeRayHit hit; float radius = val->personal_space * pa->size, ray_dir[3]; memset(&col, 0, sizeof(ParticleCollision)); copy_v3_v3(col.co1, pa->prev_state.co); add_v3_v3v3(col.co2, pa->prev_state.co, pa->prev_state.vel); sub_v3_v3v3(ray_dir, col.co2, col.co1); mul_v3_fl(ray_dir, acbr->look_ahead); col.f = 0.0f; hit.index = -1; hit.dist = col.original_ray_length = len_v3(ray_dir); /* find out closest deflector object */ for (coll = bbd->sim->colliders->first; coll; coll=coll->next) { /* don't check with current ground object */ if (coll->ob == bpa->ground) continue; col.current = coll->ob; col.md = coll->collmd; if (col.md && col.md->bvhtree) BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, BKE_psys_collision_neartest_cb, &col); } /* then avoid that object */ if (hit.index>=0) { t = hit.dist/col.original_ray_length; /* avoid head-on collision */ if (dot_v3v3(col.pce.nor, pa->prev_state.ave) < -0.99f) { /* don't know why, but uneven range [0.0, 1.0] */ /* works much better than even [-1.0, 1.0] */ bbd->wanted_co[0] = BLI_rng_get_float(bbd->rng); bbd->wanted_co[1] = BLI_rng_get_float(bbd->rng); bbd->wanted_co[2] = BLI_rng_get_float(bbd->rng); } else { copy_v3_v3(bbd->wanted_co, col.pce.nor); } mul_v3_fl(bbd->wanted_co, (1.0f - t) * val->personal_space * pa->size); bbd->wanted_speed = sqrtf(t) * len_v3(pa->prev_state.vel); bbd->wanted_speed = MAX2(bbd->wanted_speed, val->min_speed); return 1; } } //check boids in own system if (acbr->options & BRULE_ACOLL_WITH_BOIDS) { neighbors = BLI_kdtree_range_search__normal( bbd->sim->psys->tree, pa->prev_state.co, pa->prev_state.ave, &ptn, acbr->look_ahead * len_v3(pa->prev_state.vel)); if (neighbors > 1) for (n=1; n<neighbors; n++) { copy_v3_v3(co1, pa->prev_state.co); copy_v3_v3(vel1, pa->prev_state.vel); copy_v3_v3(co2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.co); copy_v3_v3(vel2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.vel); sub_v3_v3v3(loc, co1, co2); sub_v3_v3v3(vec, vel1, vel2); inp = dot_v3v3(vec, vec); /* velocities not parallel */ if (inp != 0.0f) { t = -dot_v3v3(loc, vec)/inp; /* cpa is not too far in the future so investigate further */ if (t > 0.0f && t < t_min) { madd_v3_v3fl(co1, vel1, t); madd_v3_v3fl(co2, vel2, t); sub_v3_v3v3(vec, co2, co1); len = normalize_v3(vec); /* distance of cpa is close enough */ if (len < 2.0f * val->personal_space * pa->size) { t_min = t; mul_v3_fl(vec, len_v3(vel1)); mul_v3_fl(vec, (2.0f - t)/2.0f); sub_v3_v3v3(bbd->wanted_co, vel1, vec); bbd->wanted_speed = len_v3(bbd->wanted_co); ret = 1; } } } } } if (ptn) { MEM_freeN(ptn); ptn=NULL; } /* check boids in other systems */ for (pt=bbd->sim->psys->targets.first; pt; pt=pt->next) { ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt); if (epsys) { neighbors = BLI_kdtree_range_search__normal( epsys->tree, pa->prev_state.co, pa->prev_state.ave, &ptn, acbr->look_ahead * len_v3(pa->prev_state.vel)); if (neighbors > 0) for (n=0; n<neighbors; n++) { copy_v3_v3(co1, pa->prev_state.co); copy_v3_v3(vel1, pa->prev_state.vel); copy_v3_v3(co2, (epsys->particles + ptn[n].index)->prev_state.co); copy_v3_v3(vel2, (epsys->particles + ptn[n].index)->prev_state.vel); sub_v3_v3v3(loc, co1, co2); sub_v3_v3v3(vec, vel1, vel2); inp = dot_v3v3(vec, vec); /* velocities not parallel */ if (inp != 0.0f) { t = -dot_v3v3(loc, vec)/inp; /* cpa is not too far in the future so investigate further */ if (t > 0.0f && t < t_min) { madd_v3_v3fl(co1, vel1, t); madd_v3_v3fl(co2, vel2, t); sub_v3_v3v3(vec, co2, co1); len = normalize_v3(vec); /* distance of cpa is close enough */ if (len < 2.0f * val->personal_space * pa->size) { t_min = t; mul_v3_fl(vec, len_v3(vel1)); mul_v3_fl(vec, (2.0f - t)/2.0f); sub_v3_v3v3(bbd->wanted_co, vel1, vec); bbd->wanted_speed = len_v3(bbd->wanted_co); ret = 1; } } } } if (ptn) { MEM_freeN(ptn); ptn=NULL; } } } if (ptn && nearest==0) MEM_freeN(ptn); return ret; }
static int rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa) { BoidRuleFight *fbr = (BoidRuleFight*)rule; KDTreeNearest *ptn = NULL; ParticleTarget *pt; ParticleData *epars; ParticleData *enemy_pa = NULL; BoidParticle *bpa; /* friends & enemies */ float closest_enemy[3] = {0.0f, 0.0f, 0.0f}; float closest_dist = fbr->distance + 1.0f; float f_strength = 0.0f, e_strength = 0.0f; float health = 0.0f; int n, ret = 0; /* calculate own group strength */ int neighbors = BLI_kdtree_range_search( bbd->sim->psys->tree, pa->prev_state.co, &ptn, fbr->distance); for (n=0; n<neighbors; n++) { bpa = bbd->sim->psys->particles[ptn[n].index].boid; health += bpa->data.health; } f_strength += bbd->part->boids->strength * health; if (ptn) { MEM_freeN(ptn); ptn=NULL; } /* add other friendlies and calculate enemy strength and find closest enemy */ for (pt=bbd->sim->psys->targets.first; pt; pt=pt->next) { ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt); if (epsys) { epars = epsys->particles; neighbors = BLI_kdtree_range_search( epsys->tree, pa->prev_state.co, &ptn, fbr->distance); health = 0.0f; for (n=0; n<neighbors; n++) { bpa = epars[ptn[n].index].boid; health += bpa->data.health; if (n==0 && pt->mode==PTARGET_MODE_ENEMY && ptn[n].dist < closest_dist) { copy_v3_v3(closest_enemy, ptn[n].co); closest_dist = ptn[n].dist; enemy_pa = epars + ptn[n].index; } } if (pt->mode==PTARGET_MODE_ENEMY) e_strength += epsys->part->boids->strength * health; else if (pt->mode==PTARGET_MODE_FRIEND) f_strength += epsys->part->boids->strength * health; if (ptn) { MEM_freeN(ptn); ptn=NULL; } } } /* decide action if enemy presence found */ if (e_strength > 0.0f) { sub_v3_v3v3(bbd->wanted_co, closest_enemy, pa->prev_state.co); /* attack if in range */ if (closest_dist <= bbd->part->boids->range + pa->size + enemy_pa->size) { float damage = BLI_rng_get_float(bbd->rng); float enemy_dir[3]; normalize_v3_v3(enemy_dir, bbd->wanted_co); /* fight mode */ bbd->wanted_speed = 0.0f; /* must face enemy to fight */ if (dot_v3v3(pa->prev_state.ave, enemy_dir)>0.5f) { bpa = enemy_pa->boid; bpa->data.health -= bbd->part->boids->strength * bbd->timestep * ((1.0f-bbd->part->boids->accuracy)*damage + bbd->part->boids->accuracy); } } else { /* approach mode */ bbd->wanted_speed = val->max_speed; } /* check if boid doesn't want to fight */ bpa = pa->boid; if (bpa->data.health/bbd->part->boids->health * bbd->part->boids->aggression < e_strength / f_strength) { /* decide to flee */ if (closest_dist < fbr->flee_distance * fbr->distance) { negate_v3(bbd->wanted_co); bbd->wanted_speed = val->max_speed; } else { /* wait for better odds */ bbd->wanted_speed = 0.0f; } } ret = 1; } return ret; }
void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, GPUTexture *tex, float min[3], float max[3], int res[3], float dx, float UNUSED(base_scale), float viewnormal[3], GPUTexture *tex_shadow, GPUTexture *tex_flame) { int i, j, k, n, good_index; float d /*, d0 */ /* UNUSED */, dd, ds; float *points = NULL; int numpoints = 0; float cor[3] = {1.0f, 1.0f, 1.0f}; 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}} }; unsigned char *spec_data; float *spec_pixels; GPUTexture *tex_spec; /* Fragment program to calculate the view3d of smoke */ /* using 4 textures, density, shadow, flame and flame spectrum */ const char *shader_basic = "!!ARBfp1.0\n" "PARAM dx = program.local[0];\n" "PARAM darkness = program.local[1];\n" "PARAM render = program.local[2];\n" "PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01};\n" "TEMP temp, shadow, flame, spec, value;\n" "TEX temp, fragment.texcoord[0], texture[0], 3D;\n" "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n" "TEX flame, fragment.texcoord[0], texture[2], 3D;\n" "TEX spec, flame.r, texture[3], 1D;\n" /* calculate shading factor from density */ "MUL value.r, temp.a, darkness.a;\n" "MUL value.r, value.r, dx.r;\n" "MUL value.r, value.r, f.r;\n" "EX2 temp, -value.r;\n" /* alpha */ "SUB temp.a, 1.0, temp.r;\n" /* shade colors */ "MUL temp.r, temp.r, shadow.r;\n" "MUL temp.g, temp.g, shadow.r;\n" "MUL temp.b, temp.b, shadow.r;\n" "MUL temp.r, temp.r, darkness.r;\n" "MUL temp.g, temp.g, darkness.g;\n" "MUL temp.b, temp.b, darkness.b;\n" /* for now this just replace smoke shading if rendering fire */ "CMP result.color, render.r, temp, spec;\n" "END\n"; /* color shader */ const char *shader_color = "!!ARBfp1.0\n" "PARAM dx = program.local[0];\n" "PARAM darkness = program.local[1];\n" "PARAM render = program.local[2];\n" "PARAM f = {1.442695041, 1.442695041, 1.442695041, 1.442695041};\n" "TEMP temp, shadow, flame, spec, value;\n" "TEX temp, fragment.texcoord[0], texture[0], 3D;\n" "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n" "TEX flame, fragment.texcoord[0], texture[2], 3D;\n" "TEX spec, flame.r, texture[3], 1D;\n" /* unpremultiply volume texture */ "RCP value.r, temp.a;\n" "MUL temp.r, temp.r, value.r;\n" "MUL temp.g, temp.g, value.r;\n" "MUL temp.b, temp.b, value.r;\n" /* calculate shading factor from density */ "MUL value.r, temp.a, darkness.a;\n" "MUL value.r, value.r, dx.r;\n" "MUL value.r, value.r, f.r;\n" "EX2 value.r, -value.r;\n" /* alpha */ "SUB temp.a, 1.0, value.r;\n" /* shade colors */ "MUL temp.r, temp.r, shadow.r;\n" "MUL temp.g, temp.g, shadow.r;\n" "MUL temp.b, temp.b, shadow.r;\n" "MUL temp.r, temp.r, value.r;\n" "MUL temp.g, temp.g, value.r;\n" "MUL temp.b, temp.b, value.r;\n" /* for now this just replace smoke shading if rendering fire */ "CMP result.color, render.r, temp, spec;\n" "END\n"; GLuint prog; float size[3]; if (!tex) { printf("Could not allocate 3D texture for 3D View smoke drawing.\n"); return; } #ifdef DEBUG_DRAW_TIME TIMEIT_START(draw); #endif /* generate flame spectrum texture */ #define SPEC_WIDTH 256 #define FIRE_THRESH 7 #define MAX_FIRE_ALPHA 0.06f #define FULL_ON_FIRE 100 spec_data = malloc(SPEC_WIDTH * 4 * sizeof(unsigned char)); flame_get_spectrum(spec_data, SPEC_WIDTH, 1500, 3000); spec_pixels = malloc(SPEC_WIDTH * 4 * 16 * 16 * sizeof(float)); for (i = 0; i < 16; i++) { for (j = 0; j < 16; j++) { for (k = 0; k < SPEC_WIDTH; k++) { int index = (j * SPEC_WIDTH * 16 + i * SPEC_WIDTH + k) * 4; if (k >= FIRE_THRESH) { spec_pixels[index] = ((float)spec_data[k * 4]) / 255.0f; spec_pixels[index + 1] = ((float)spec_data[k * 4 + 1]) / 255.0f; spec_pixels[index + 2] = ((float)spec_data[k * 4 + 2]) / 255.0f; spec_pixels[index + 3] = MAX_FIRE_ALPHA * ( (k > FULL_ON_FIRE) ? 1.0f : (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH)); } else { spec_pixels[index] = spec_pixels[index + 1] = spec_pixels[index + 2] = spec_pixels[index + 3] = 0.0f; } } } } tex_spec = GPU_texture_create_1D(SPEC_WIDTH, spec_pixels, NULL); sub_v3_v3v3(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]; copy_v3_v3(edges[0][0], cv[4]); /* maxx, maxy, minz */ copy_v3_v3(edges[1][0], cv[5]); /* minx, maxy, minz */ copy_v3_v3(edges[2][0], cv[6]); /* minx, miny, minz */ copy_v3_v3(edges[3][0], cv[7]); /* maxx, miny, minz */ copy_v3_v3(edges[4][0], cv[3]); /* maxx, miny, maxz */ copy_v3_v3(edges[5][0], cv[2]); /* minx, miny, maxz */ copy_v3_v3(edges[6][0], cv[6]); /* minx, miny, minz */ copy_v3_v3(edges[7][0], cv[7]); /* maxx, miny, minz */ copy_v3_v3(edges[8][0], cv[1]); /* minx, maxy, maxz */ copy_v3_v3(edges[9][0], cv[2]); /* minx, miny, maxz */ copy_v3_v3(edges[10][0], cv[6]); /* minx, miny, minz */ copy_v3_v3(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); glDepthMask(GL_FALSE); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); /* 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] * size[0] * 0.5f; y = cv[i][1] - viewnormal[1] * size[1] * 0.5f; z = cv[i][2] - viewnormal[2] * size[2] * 0.5f; 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); /* set shader */ if (sds->active_fields & SM_ACTIVE_COLORS) glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_color), shader_color); else glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_basic), shader_basic); /* cell spacing */ glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, dx, dx, dx, 1.0); /* custom parameter for smoke style (higher = thicker) */ if (sds->active_fields & SM_ACTIVE_COLORS) glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, 1.0, 1.0, 1.0, 10.0); else glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, sds->active_color[0], sds->active_color[1], sds->active_color[2], 10.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 (tex_flame) { GPU_texture_bind(tex_flame, 2); GPU_texture_bind(tex_spec, 3); } if (!GPU_non_power_of_two_support()) { cor[0] = (float)res[0] / (float)power_of_2_max_i(res[0]); cor[1] = (float)res[1] / (float)power_of_2_max_i(res[1]); cor[2] = (float)res[2] / (float)power_of_2_max_i(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]); */ /* UNUSED */ ds = (fabsf(viewnormal[0]) * size[0] + fabsf(viewnormal[1]) * size[1] + fabsf(viewnormal[2]) * size[2]); dd = max_fff(sds->global_size[0], sds->global_size[1], sds->global_size[2]) / 128.f; 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; copy_v3_v3(tmp_point, viewnormal); mul_v3_fl(tmp_point, -dd * ((ds / dd) - (float)n)); add_v3_v3v3(tmp_point2, cv[good_index], tmp_point); d = dot_v3v3(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) { copy_v3_v3(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]; copy_v3_v3(tmp2, &points[j * 3]); copy_v3_v3(&points[j * 3], &points[i * 3]); copy_v3_v3(&points[i * 3], tmp2); } } } /* render fire slice */ glBlendFunc(GL_SRC_ALPHA, GL_ONE); glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, 1.0, 0.0, 0.0, 0.0); 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] / fabsf(ob->size[0]), points[i * 3 + 1] / fabsf(ob->size[1]), points[i * 3 + 2] / fabsf(ob->size[2])); } glEnd(); /* render smoke slice */ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, -1.0, 0.0, 0.0, 0.0); 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] / fabsf(ob->size[0]), points[i * 3 + 1] / fabsf(ob->size[1]), points[i * 3 + 2] / fabsf(ob->size[2])); } glEnd(); } n++; } #ifdef DEBUG_DRAW_TIME printf("Draw Time: %f\n", (float)TIMEIT_VALUE(draw)); TIMEIT_END(draw); #endif if (tex_shadow) GPU_texture_unbind(tex_shadow); GPU_texture_unbind(tex); if (tex_flame) { GPU_texture_unbind(tex_flame); GPU_texture_unbind(tex_spec); } GPU_texture_free(tex_spec); free(spec_data); free(spec_pixels); 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); } }
static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event) { ViewContext vc; EditVert *eve; float min[3], max[3]; int done= 0; short use_proj; em_setup_viewcontext(C, &vc); use_proj= (vc.scene->toolsettings->snap_flag & SCE_SNAP) && (vc.scene->toolsettings->snap_mode==SCE_SNAP_MODE_FACE); invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); INIT_MINMAX(min, max); for(eve= vc.em->verts.first; eve; eve= eve->next) { if(eve->f & SELECT) { DO_MINMAX(eve->co, min, max); done= 1; } } /* call extrude? */ if(done) { const short rot_src= RNA_boolean_get(op->ptr, "rotate_source"); EditEdge *eed; float vec[3], cent[3], mat[3][3]; float nor[3]= {0.0, 0.0, 0.0}; /* 2D normal calc */ float mval_f[2]; mval_f[0]= (float)event->mval[0]; mval_f[1]= (float)event->mval[1]; done= 0; /* calculate the normal for selected edges */ for(eed= vc.em->edges.first; eed; eed= eed->next) { if(eed->f & SELECT) { float co1[3], co2[3]; mul_v3_m4v3(co1, vc.obedit->obmat, eed->v1->co); mul_v3_m4v3(co2, vc.obedit->obmat, eed->v2->co); project_float_noclip(vc.ar, co1, co1); project_float_noclip(vc.ar, co2, co2); /* 2D rotate by 90d while adding. * (x, y) = (y, -x) * * accumulate the screenspace normal in 2D, * with screenspace edge length weighting the result. */ if(line_point_side_v2(co1, co2, mval_f) >= 0.0f) { nor[0] += (co1[1] - co2[1]); nor[1] += -(co1[0] - co2[0]); } else { nor[0] += (co2[1] - co1[1]); nor[1] += -(co2[0] - co1[0]); } done= 1; } } if(done) { float view_vec[3], cross[3]; /* convert the 2D nomal into 3D */ mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* worldspace */ mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */ /* correct the normal to be aligned on the view plane */ copy_v3_v3(view_vec, vc.rv3d->viewinv[2]); mul_mat3_m4_v3(vc.obedit->imat, view_vec); cross_v3_v3v3(cross, nor, view_vec); cross_v3_v3v3(nor, view_vec, cross); normalize_v3(nor); } /* center */ mid_v3_v3v3(cent, min, max); copy_v3_v3(min, cent); mul_m4_v3(vc.obedit->obmat, min); // view space view3d_get_view_aligned_coordinate(&vc, min, event->mval, TRUE); mul_m4_v3(vc.obedit->imat, min); // back in object space sub_v3_v3(min, cent); /* calculate rotation */ unit_m3(mat); if(done) { float dot; copy_v3_v3(vec, min); normalize_v3(vec); dot= dot_v3v3(vec, nor); if( fabs(dot)<0.999) { float cross[3], si, q1[4]; cross_v3_v3v3(cross, nor, vec); normalize_v3(cross); dot= 0.5f*saacos(dot); /* halve the rotation if its applied twice */ if(rot_src) dot *= 0.5f; si= (float)sin(dot); q1[0]= (float)cos(dot); q1[1]= cross[0]*si; q1[2]= cross[1]*si; q1[3]= cross[2]*si; quat_to_mat3( mat,q1); } } if(rot_src) { rotateflag(vc.em, SELECT, cent, mat); /* also project the source, for retopo workflow */ if(use_proj) EM_project_snap_verts(C, vc.ar, vc.obedit, vc.em); } extrudeflag(vc.obedit, vc.em, SELECT, nor, 0); rotateflag(vc.em, SELECT, cent, mat); translateflag(vc.em, SELECT, min); recalc_editnormals(vc.em); } else if(vc.em->selectmode & SCE_SELECT_VERTEX) { float imat[4][4]; const float *curs= give_cursor(vc.scene, vc.v3d); copy_v3_v3(min, curs); view3d_get_view_aligned_coordinate(&vc, min, event->mval, TRUE); eve= addvertlist(vc.em, 0, NULL); invert_m4_m4(imat, vc.obedit->obmat); mul_v3_m4v3(eve->co, imat, min); eve->f= SELECT; } if(use_proj) EM_project_snap_verts(C, vc.ar, vc.obedit, vc.em); WM_event_add_notifier(C, NC_GEOM|ND_DATA, vc.obedit->data); DAG_id_tag_update(vc.obedit->data, 0); return OPERATOR_FINISHED; }
MINLINE float len_v3(const float a[3]) { return sqrtf(dot_v3v3(a, a)); }
static void rotateDifferentialCoordinates(LaplacianSystem *sys) { float alpha, beta, gamma; float pj[3], ni[3], di[3]; float uij[3], dun[3], e2[3], pi[3], fni[3], vn[4][3]; int i, j, lvin, num_fni, k, fi; int *fidn; for (i = 0; i < sys->total_verts; i++) { copy_v3_v3(pi, sys->co[i]); copy_v3_v3(ni, sys->no[i]); k = sys->unit_verts[i]; copy_v3_v3(pj, sys->co[k]); sub_v3_v3v3(uij, pj, pi); mul_v3_v3fl(dun, ni, dot_v3v3(uij, ni)); sub_v3_v3(uij, dun); normalize_v3(uij); cross_v3_v3v3(e2, ni, uij); copy_v3_v3(di, sys->delta[i]); alpha = dot_v3v3(ni, di); beta = dot_v3v3(uij, di); gamma = dot_v3v3(e2, di); pi[0] = nlGetVariable(0, i); pi[1] = nlGetVariable(1, i); pi[2] = nlGetVariable(2, i); zero_v3(ni); num_fni = 0; num_fni = sys->ringf_map[i].count; for (fi = 0; fi < num_fni; fi++) { const unsigned int *vin; fidn = sys->ringf_map[i].indices; vin = sys->faces[fidn[fi]]; lvin = vin[3] ? 4 : 3; for (j = 0; j < lvin; j++) { vn[j][0] = nlGetVariable(0, vin[j]); vn[j][1] = nlGetVariable(1, vin[j]); vn[j][2] = nlGetVariable(2, vin[j]); if (vin[j] == sys->unit_verts[i]) { copy_v3_v3(pj, vn[j]); } } if (lvin == 3) { normal_tri_v3(fni, vn[0], vn[1], vn[2]); } else if (lvin == 4) { normal_quad_v3(fni, vn[0], vn[1], vn[2], vn[3]); } add_v3_v3(ni, fni); } normalize_v3(ni); sub_v3_v3v3(uij, pj, pi); mul_v3_v3fl(dun, ni, dot_v3v3(uij, ni)); sub_v3_v3(uij, dun); normalize_v3(uij); cross_v3_v3v3(e2, ni, uij); fni[0] = alpha * ni[0] + beta * uij[0] + gamma * e2[0]; fni[1] = alpha * ni[1] + beta * uij[1] + gamma * e2[1]; fni[2] = alpha * ni[2] + beta * uij[2] + gamma * e2[2]; if (len_squared_v3(fni) > FLT_EPSILON) { nlRightHandSideSet(0, i, fni[0]); nlRightHandSideSet(1, i, fni[1]); nlRightHandSideSet(2, i, fni[2]); } else { nlRightHandSideSet(0, i, sys->delta[i][0]); nlRightHandSideSet(1, i, sys->delta[i][1]); nlRightHandSideSet(2, i, sys->delta[i][2]); } } }
/** * AtmospherePixleShader: * this function apply atmosphere effect on a pixle color `rgb' at distance `s' * parameters: * sunSky, contains information about sun parameters and user values * view, is camera view vector * s, is distance * rgb, contains rendered color value for a pixle * */ void AtmospherePixleShader( struct SunSky* sunSky, float view[3], float s, float rgb[3]) { float costheta; float Phase_1; float Phase_2; float sunColor[3]; float E[3]; float E1[3]; float I[3]; float fTemp; float vTemp1[3], vTemp2[3]; float sunDirection[3]; s *= sunSky->atm_DistanceMultiplier; sunDirection[0] = sunSky->toSun[0]; sunDirection[1] = sunSky->toSun[1]; sunDirection[2] = sunSky->toSun[2]; costheta = dot_v3v3(view, sunDirection); // cos(theta) Phase_1 = 1 + (costheta * costheta); // Phase_1 vec3opf(sunSky->atm_BetaRay, sunSky->atm_BetaRay, *, sunSky->atm_BetaRayMultiplier); vec3opf(sunSky->atm_BetaMie, sunSky->atm_BetaMie, *, sunSky->atm_BetaMieMultiplier); vec3opv(sunSky->atm_BetaRM, sunSky->atm_BetaRay, +, sunSky->atm_BetaMie); //e^(-(beta_1 + beta_2) * s) = E1 vec3opf(E1, sunSky->atm_BetaRM, *, -s/(float)M_LN2); E1[0] = exp(E1[0]); E1[1] = exp(E1[1]); E1[2] = exp(E1[2]); copy_v3_v3(E, E1); //Phase2(theta) = (1-g^2)/(1+g-2g*cos(theta))^(3/2) fTemp = 1 + sunSky->atm_HGg - 2 * sunSky->atm_HGg * costheta; fTemp = fTemp * sqrtf(fTemp); Phase_2 = (1 - sunSky->atm_HGg * sunSky->atm_HGg)/fTemp; vec3opf(vTemp1, sunSky->atm_BetaDashRay, *, Phase_1); vec3opf(vTemp2, sunSky->atm_BetaDashMie, *, Phase_2); vec3opv(vTemp1, vTemp1, +, vTemp2); fopvec3(vTemp2, 1.0f, -, E1); vec3opv(vTemp1, vTemp1, *, vTemp2); fopvec3(vTemp2, 1.0f, / , sunSky->atm_BetaRM); vec3opv(I, vTemp1, *, vTemp2); vec3opf(I, I, *, sunSky->atm_InscatteringMultiplier); vec3opf(E, E, *, sunSky->atm_ExtinctionMultiplier); //scale to color sun ComputeAttenuatedSunlight(sunSky->theta, sunSky->turbidity, sunColor); vec3opv(E, E, *, sunColor); vec3opf(I, I, *, sunSky->atm_SunIntensity); vec3opv(rgb, rgb, *, E); vec3opv(rgb, rgb, +, I); }
/* only valid for perspective cameras */ bool BKE_camera_view_frame_fit_to_scene(Scene *scene, struct View3D *v3d, Object *camera_ob, float r_co[3]) { float shift[2]; float plane_tx[4][3]; float rot_obmat[3][3]; const float zero[3] = {0, 0, 0}; CameraViewFrameData data_cb; unsigned int i; BKE_camera_view_frame(scene, camera_ob->data, data_cb.frame_tx); copy_m3_m4(rot_obmat, camera_ob->obmat); normalize_m3(rot_obmat); for (i = 0; i < 4; i++) { /* normalize so Z is always 1.0f*/ mul_v3_fl(data_cb.frame_tx[i], 1.0f / data_cb.frame_tx[i][2]); } /* get the shift back out of the frame */ shift[0] = (data_cb.frame_tx[0][0] + data_cb.frame_tx[1][0] + data_cb.frame_tx[2][0] + data_cb.frame_tx[3][0]) / 4.0f; shift[1] = (data_cb.frame_tx[0][1] + data_cb.frame_tx[1][1] + data_cb.frame_tx[2][1] + data_cb.frame_tx[3][1]) / 4.0f; for (i = 0; i < 4; i++) { mul_m3_v3(rot_obmat, data_cb.frame_tx[i]); } for (i = 0; i < 4; i++) { normal_tri_v3(data_cb.normal_tx[i], zero, data_cb.frame_tx[i], data_cb.frame_tx[(i + 1) % 4]); plane_from_point_normal_v3(data_cb.plane_tx[i], data_cb.frame_tx[i], data_cb.normal_tx[i]); } /* initialize callback data */ copy_v4_fl(data_cb.dist_vals_sq, FLT_MAX); data_cb.tot = 0; /* run callback on all visible points */ BKE_scene_foreach_display_point(scene, v3d, BA_SELECT, camera_to_frame_view_cb, &data_cb); if (data_cb.tot <= 1) { return false; } else { float plane_isect_1[3], plane_isect_1_no[3], plane_isect_1_other[3]; float plane_isect_2[3], plane_isect_2_no[3], plane_isect_2_other[3]; float plane_isect_pt_1[3], plane_isect_pt_2[3]; /* apply the dist-from-plane's to the transformed plane points */ for (i = 0; i < 4; i++) { mul_v3_v3fl(plane_tx[i], data_cb.normal_tx[i], sqrtf_signed(data_cb.dist_vals_sq[i])); } if ((!isect_plane_plane_v3(plane_isect_1, plane_isect_1_no, plane_tx[0], data_cb.normal_tx[0], plane_tx[2], data_cb.normal_tx[2])) || (!isect_plane_plane_v3(plane_isect_2, plane_isect_2_no, plane_tx[1], data_cb.normal_tx[1], plane_tx[3], data_cb.normal_tx[3]))) { return false; } add_v3_v3v3(plane_isect_1_other, plane_isect_1, plane_isect_1_no); add_v3_v3v3(plane_isect_2_other, plane_isect_2, plane_isect_2_no); if (isect_line_line_v3(plane_isect_1, plane_isect_1_other, plane_isect_2, plane_isect_2_other, plane_isect_pt_1, plane_isect_pt_2) == 0) { return false; } else { float cam_plane_no[3] = {0.0f, 0.0f, -1.0f}; float plane_isect_delta[3]; float plane_isect_delta_len; mul_m3_v3(rot_obmat, cam_plane_no); sub_v3_v3v3(plane_isect_delta, plane_isect_pt_2, plane_isect_pt_1); plane_isect_delta_len = len_v3(plane_isect_delta); if (dot_v3v3(plane_isect_delta, cam_plane_no) > 0.0f) { copy_v3_v3(r_co, plane_isect_pt_1); /* offset shift */ normalize_v3(plane_isect_1_no); madd_v3_v3fl(r_co, plane_isect_1_no, shift[1] * -plane_isect_delta_len); } else { copy_v3_v3(r_co, plane_isect_pt_2); /* offset shift */ normalize_v3(plane_isect_2_no); madd_v3_v3fl(r_co, plane_isect_2_no, shift[0] * -plane_isect_delta_len); } return true; } } }
float IMB_colormanagement_get_luminance(const float rgb[3]) { return dot_v3v3(imbuf_luma_coefficients, rgb); }
MALWAYS_INLINE int isec_tri_quad_neighbour(float start[3], float dir[3], RayFace *face) { float co1[3], co2[3], co3[3], co4[3]; float t0[3], t1[3], x[3], r[3], m[3], u, v, divdet, det1; int quad; quad= RE_rayface_isQuad(face); copy_v3_v3(co1, face->v1); copy_v3_v3(co2, face->v2); copy_v3_v3(co3, face->v3); negate_v3_v3(r, dir); /* note, different than above function */ /* intersect triangle */ sub_v3_v3v3(t0, co3, co2); sub_v3_v3v3(t1, co3, co1); cross_v3_v3v3(x, r, t1); divdet= dot_v3v3(t0, x); sub_v3_v3v3(m, start, co3); det1= dot_v3v3(m, x); if(divdet != 0.0f) { divdet= 1.0f/divdet; v= det1*divdet; if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) { float cros[3]; cross_v3_v3v3(cros, m, t0); u= divdet*dot_v3v3(cros, r); if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON)) return 1; } } /* intersect second triangle in quad */ if(quad) { copy_v3_v3(co4, face->v4); sub_v3_v3v3(t0, co3, co4); divdet= dot_v3v3(t0, x); if(divdet != 0.0f) { divdet= 1.0f/divdet; v = det1*divdet; if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) { float cros[3]; cross_v3_v3v3(cros, m, t0); u= divdet*dot_v3v3(cros, r); if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON)) return 2; } } } return 0; }
static void do_texture_effector(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, float *total_force) { TexResult result[4]; float tex_co[3], strength, force[3]; float nabla = eff->pd->tex_nabla; int hasrgb; short mode = eff->pd->tex_mode; if (!eff->pd->tex) return; result[0].nor = result[1].nor = result[2].nor = result[3].nor = NULL; strength= eff->pd->f_strength * efd->falloff; copy_v3_v3(tex_co, point->loc); if (eff->pd->flag & PFIELD_TEX_2D) { float fac=-dot_v3v3(tex_co, efd->nor); madd_v3_v3fl(tex_co, efd->nor, fac); } if (eff->pd->flag & PFIELD_TEX_OBJECT) { mul_m4_v3(eff->ob->imat, tex_co); } hasrgb = multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result, NULL); if (hasrgb && mode==PFIELD_TEX_RGB) { force[0] = (0.5f - result->tr) * strength; force[1] = (0.5f - result->tg) * strength; force[2] = (0.5f - result->tb) * strength; } else { strength/=nabla; tex_co[0] += nabla; multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+1, NULL); tex_co[0] -= nabla; tex_co[1] += nabla; multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+2, NULL); tex_co[1] -= nabla; tex_co[2] += nabla; multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+3, NULL); if (mode == PFIELD_TEX_GRAD || !hasrgb) { /* if we don't have rgb fall back to grad */ /* generate intensity if texture only has rgb value */ if (hasrgb & TEX_RGB) { int i; for (i=0; i<4; i++) result[i].tin = (1.0f / 3.0f) * (result[i].tr + result[i].tg + result[i].tb); } force[0] = (result[0].tin - result[1].tin) * strength; force[1] = (result[0].tin - result[2].tin) * strength; force[2] = (result[0].tin - result[3].tin) * strength; } else { /*PFIELD_TEX_CURL*/ float dbdy, dgdz, drdz, dbdx, dgdx, drdy; dbdy = result[2].tb - result[0].tb; dgdz = result[3].tg - result[0].tg; drdz = result[3].tr - result[0].tr; dbdx = result[1].tb - result[0].tb; dgdx = result[1].tg - result[0].tg; drdy = result[2].tr - result[0].tr; force[0] = (dbdy - dgdz) * strength; force[1] = (drdz - dbdx) * strength; force[2] = (dgdx - drdy) * strength; } } if (eff->pd->flag & PFIELD_TEX_2D) { float fac = -dot_v3v3(force, efd->nor); madd_v3_v3fl(force, efd->nor, fac); } add_v3_v3(total_force, force); }
/* tries to realize the wanted velocity taking all constraints into account */ void boid_body(BoidBrainData *bbd, ParticleData *pa) { BoidSettings *boids = bbd->part->boids; BoidParticle *bpa = pa->boid; BoidValues val; EffectedPoint epoint; float acc[3] = {0.0f, 0.0f, 0.0f}, tan_acc[3], nor_acc[3]; float dvec[3], bvec[3]; float new_dir[3], new_speed; float old_dir[3], old_speed; float wanted_dir[3]; float q[4], mat[3][3]; /* rotation */ float ground_co[3] = {0.0f, 0.0f, 0.0f}, ground_nor[3] = {0.0f, 0.0f, 1.0f}; float force[3] = {0.0f, 0.0f, 0.0f}; float pa_mass=bbd->part->mass, dtime=bbd->dfra*bbd->timestep; set_boid_values(&val, boids, pa); /* make sure there's something in new velocity, location & rotation */ copy_particle_key(&pa->state, &pa->prev_state, 0); if (bbd->part->flag & PART_SIZEMASS) pa_mass*=pa->size; /* if boids can't fly they fall to the ground */ if ((boids->options & BOID_ALLOW_FLIGHT)==0 && ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)==0 && psys_uses_gravity(bbd->sim)) bpa->data.mode = eBoidMode_Falling; if (bpa->data.mode == eBoidMode_Falling) { /* Falling boids are only effected by gravity. */ acc[2] = bbd->sim->scene->physics_settings.gravity[2]; } else { /* figure out acceleration */ float landing_level = 2.0f; float level = landing_level + 1.0f; float new_vel[3]; if (bpa->data.mode == eBoidMode_Liftoff) { bpa->data.mode = eBoidMode_InAir; bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor); } else if (bpa->data.mode == eBoidMode_InAir && boids->options & BOID_ALLOW_LAND) { /* auto-leveling & landing if close to ground */ bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor); /* level = how many particle sizes above ground */ level = (pa->prev_state.co[2] - ground_co[2])/(2.0f * pa->size) - 0.5f; landing_level = - boids->landing_smoothness * pa->prev_state.vel[2] * pa_mass; if (pa->prev_state.vel[2] < 0.0f) { if (level < 1.0f) { bbd->wanted_co[0] = bbd->wanted_co[1] = bbd->wanted_co[2] = 0.0f; bbd->wanted_speed = 0.0f; bpa->data.mode = eBoidMode_Falling; } else if (level < landing_level) { bbd->wanted_speed *= (level - 1.0f)/landing_level; bbd->wanted_co[2] *= (level - 1.0f)/landing_level; } } } copy_v3_v3(old_dir, pa->prev_state.ave); new_speed = normalize_v3_v3(wanted_dir, bbd->wanted_co); /* first check if we have valid direction we want to go towards */ if (new_speed == 0.0f) { copy_v3_v3(new_dir, old_dir); } else { float old_dir2[2], wanted_dir2[2], nor[3], angle; copy_v2_v2(old_dir2, old_dir); normalize_v2(old_dir2); copy_v2_v2(wanted_dir2, wanted_dir); normalize_v2(wanted_dir2); /* choose random direction to turn if wanted velocity */ /* is directly behind regardless of z-coordinate */ if (dot_v2v2(old_dir2, wanted_dir2) < -0.99f) { wanted_dir[0] = 2.0f*(0.5f - BLI_rng_get_float(bbd->rng)); wanted_dir[1] = 2.0f*(0.5f - BLI_rng_get_float(bbd->rng)); wanted_dir[2] = 2.0f*(0.5f - BLI_rng_get_float(bbd->rng)); normalize_v3(wanted_dir); } /* constrain direction with maximum angular velocity */ angle = saacos(dot_v3v3(old_dir, wanted_dir)); angle = min_ff(angle, val.max_ave); cross_v3_v3v3(nor, old_dir, wanted_dir); axis_angle_to_quat(q, nor, angle); copy_v3_v3(new_dir, old_dir); mul_qt_v3(q, new_dir); normalize_v3(new_dir); /* save direction in case resulting velocity too small */ axis_angle_to_quat(q, nor, angle*dtime); copy_v3_v3(pa->state.ave, old_dir); mul_qt_v3(q, pa->state.ave); normalize_v3(pa->state.ave); } /* constrain speed with maximum acceleration */ old_speed = len_v3(pa->prev_state.vel); if (bbd->wanted_speed < old_speed) new_speed = MAX2(bbd->wanted_speed, old_speed - val.max_acc); else new_speed = MIN2(bbd->wanted_speed, old_speed + val.max_acc); /* combine direction and speed */ copy_v3_v3(new_vel, new_dir); mul_v3_fl(new_vel, new_speed); /* maintain minimum flying velocity if not landing */ if (level >= landing_level) { float len2 = dot_v2v2(new_vel, new_vel); float root; len2 = MAX2(len2, val.min_speed*val.min_speed); root = sasqrt(new_speed*new_speed - len2); new_vel[2] = new_vel[2] < 0.0f ? -root : root; normalize_v2(new_vel); mul_v2_fl(new_vel, sasqrt(len2)); } /* finally constrain speed to max speed */ new_speed = normalize_v3(new_vel); mul_v3_fl(new_vel, MIN2(new_speed, val.max_speed)); /* get acceleration from difference of velocities */ sub_v3_v3v3(acc, new_vel, pa->prev_state.vel); /* break acceleration to components */ project_v3_v3v3(tan_acc, acc, pa->prev_state.ave); sub_v3_v3v3(nor_acc, acc, tan_acc); } /* account for effectors */ pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint); pdDoEffectors(bbd->sim->psys->effectors, bbd->sim->colliders, bbd->part->effector_weights, &epoint, force, NULL); if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) { float length = normalize_v3(force); length = MAX2(0.0f, length - boids->land_stick_force); mul_v3_fl(force, length); } add_v3_v3(acc, force); /* store smoothed acceleration for nice banking etc. */ madd_v3_v3fl(bpa->data.acc, acc, dtime); mul_v3_fl(bpa->data.acc, 1.0f / (1.0f + dtime)); /* integrate new location & velocity */ /* by regarding the acceleration as a force at this stage we*/ /* can get better control allthough it's a bit unphysical */ mul_v3_fl(acc, 1.0f/pa_mass); copy_v3_v3(dvec, acc); mul_v3_fl(dvec, dtime*dtime*0.5f); copy_v3_v3(bvec, pa->prev_state.vel); mul_v3_fl(bvec, dtime); add_v3_v3(dvec, bvec); add_v3_v3(pa->state.co, dvec); madd_v3_v3fl(pa->state.vel, acc, dtime); //if (bpa->data.mode != eBoidMode_InAir) bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor); /* change modes, constrain movement & keep track of down vector */ switch (bpa->data.mode) { case eBoidMode_InAir: { float grav[3]; grav[0] = 0.0f; grav[1] = 0.0f; grav[2] = bbd->sim->scene->physics_settings.gravity[2] < 0.0f ? -1.0f : 0.0f; /* don't take forward acceleration into account (better banking) */ if (dot_v3v3(bpa->data.acc, pa->state.vel) > 0.0f) { project_v3_v3v3(dvec, bpa->data.acc, pa->state.vel); sub_v3_v3v3(dvec, bpa->data.acc, dvec); } else { copy_v3_v3(dvec, bpa->data.acc); } /* gather apparent gravity */ madd_v3_v3v3fl(bpa->gravity, grav, dvec, -boids->banking); normalize_v3(bpa->gravity); /* stick boid on goal when close enough */ if (bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) { bpa->data.mode = eBoidMode_Climbing; bpa->ground = bbd->goal_ob; boid_find_ground(bbd, pa, ground_co, ground_nor); boid_climb(boids, pa, ground_co, ground_nor); } else if (pa->state.co[2] <= ground_co[2] + pa->size * boids->height) { /* land boid when below ground */ if (boids->options & BOID_ALLOW_LAND) { pa->state.co[2] = ground_co[2] + pa->size * boids->height; pa->state.vel[2] = 0.0f; bpa->data.mode = eBoidMode_OnLand; } /* fly above ground */ else if (bpa->ground) { pa->state.co[2] = ground_co[2] + pa->size * boids->height; pa->state.vel[2] = 0.0f; } } break; } case eBoidMode_Falling: { float grav[3]; grav[0] = 0.0f; grav[1] = 0.0f; grav[2] = bbd->sim->scene->physics_settings.gravity[2] < 0.0f ? -1.0f : 0.0f; /* gather apparent gravity */ madd_v3_v3fl(bpa->gravity, grav, dtime); normalize_v3(bpa->gravity); if (boids->options & BOID_ALLOW_LAND) { /* stick boid on goal when close enough */ if (bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) { bpa->data.mode = eBoidMode_Climbing; bpa->ground = bbd->goal_ob; boid_find_ground(bbd, pa, ground_co, ground_nor); boid_climb(boids, pa, ground_co, ground_nor); } /* land boid when really near ground */ else if (pa->state.co[2] <= ground_co[2] + 1.01f * pa->size * boids->height) { pa->state.co[2] = ground_co[2] + pa->size * boids->height; pa->state.vel[2] = 0.0f; bpa->data.mode = eBoidMode_OnLand; } /* if we're falling, can fly and want to go upwards lets fly */ else if (boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f) bpa->data.mode = eBoidMode_InAir; } else bpa->data.mode = eBoidMode_InAir; break; } case eBoidMode_Climbing: { boid_climb(boids, pa, ground_co, ground_nor); //float nor[3]; //copy_v3_v3(nor, ground_nor); ///* gather apparent gravity to r_ve */ //madd_v3_v3fl(pa->r_ve, ground_nor, -1.0); //normalize_v3(pa->r_ve); ///* raise boid it's size from surface */ //mul_v3_fl(nor, pa->size * boids->height); //add_v3_v3v3(pa->state.co, ground_co, nor); ///* remove normal component from velocity */ //project_v3_v3v3(v, pa->state.vel, ground_nor); //sub_v3_v3v3(pa->state.vel, pa->state.vel, v); break; } case eBoidMode_OnLand: { /* stick boid on goal when close enough */ if (bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) { bpa->data.mode = eBoidMode_Climbing; bpa->ground = bbd->goal_ob; boid_find_ground(bbd, pa, ground_co, ground_nor); boid_climb(boids, pa, ground_co, ground_nor); } /* ground is too far away so boid falls */ else if (pa->state.co[2]-ground_co[2] > 1.1f * pa->size * boids->height) bpa->data.mode = eBoidMode_Falling; else { /* constrain to surface */ pa->state.co[2] = ground_co[2] + pa->size * boids->height; pa->state.vel[2] = 0.0f; } if (boids->banking > 0.0f) { float grav[3]; /* Don't take gravity's strength in to account, */ /* otherwise amount of banking is hard to control. */ negate_v3_v3(grav, ground_nor); project_v3_v3v3(dvec, bpa->data.acc, pa->state.vel); sub_v3_v3v3(dvec, bpa->data.acc, dvec); /* gather apparent gravity */ madd_v3_v3v3fl(bpa->gravity, grav, dvec, -boids->banking); normalize_v3(bpa->gravity); } else { /* gather negative surface normal */ madd_v3_v3fl(bpa->gravity, ground_nor, -1.0f); normalize_v3(bpa->gravity); } break; } } /* save direction to state.ave unless the boid is falling */ /* (boids can't effect their direction when falling) */ if (bpa->data.mode!=eBoidMode_Falling && len_v3(pa->state.vel) > 0.1f*pa->size) { copy_v3_v3(pa->state.ave, pa->state.vel); pa->state.ave[2] *= bbd->part->boids->pitch; normalize_v3(pa->state.ave); } /* apply damping */ if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) mul_v3_fl(pa->state.vel, 1.0f - 0.2f*bbd->part->dampfac); /* calculate rotation matrix based on forward & down vectors */ if (bpa->data.mode == eBoidMode_InAir) { copy_v3_v3(mat[0], pa->state.ave); project_v3_v3v3(dvec, bpa->gravity, pa->state.ave); sub_v3_v3v3(mat[2], bpa->gravity, dvec); normalize_v3(mat[2]); } else { project_v3_v3v3(dvec, pa->state.ave, bpa->gravity); sub_v3_v3v3(mat[0], pa->state.ave, dvec); normalize_v3(mat[0]); copy_v3_v3(mat[2], bpa->gravity); } negate_v3(mat[2]); cross_v3_v3v3(mat[1], mat[2], mat[0]); /* apply rotation */ mat3_to_quat_is_ok(q, mat); copy_qt_qt(pa->state.rot, q); }
/** * This function populates pixel_array and returns TRUE if things are correct */ static bool cast_ray_highpoly( BVHTreeFromMesh *treeData, TriTessFace *triangles[], BakePixel *pixel_array, BakeHighPolyData *highpoly, const float co[3], const float dir[3], const int pixel_id, const int tot_highpoly, const float du_dx, const float du_dy, const float dv_dx, const float dv_dy) { int i; int primitive_id = -1; float uv[2]; int hit_mesh = -1; float hit_distance = FLT_MAX; BVHTreeRayHit *hits; hits = MEM_mallocN(sizeof(BVHTreeRayHit) * tot_highpoly, "Bake Highpoly to Lowpoly: BVH Rays"); for (i = 0; i < tot_highpoly; i++) { float co_high[3], dir_high[3]; hits[i].index = -1; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */ hits[i].dist = 10000.0f; /* transform the ray from the world space to the highpoly space */ mul_v3_m4v3(co_high, highpoly[i].imat, co); /* rotates */ mul_v3_mat3_m4v3(dir_high, highpoly[i].imat, dir); normalize_v3(dir_high); /* cast ray */ if (treeData[i].tree) { BLI_bvhtree_ray_cast(treeData[i].tree, co_high, dir_high, 0.0f, &hits[i], treeData[i].raycast_callback, &treeData[i]); } if (hits[i].index != -1) { /* cull backface */ const float dot = dot_v3v3(dir_high, hits[i].no); if (dot < 0.0f) { float distance; float hit_world[3]; /* distance comparison in world space */ mul_v3_m4v3(hit_world, highpoly[i].obmat, hits[i].co); distance = len_squared_v3v3(hit_world, co); if (distance < hit_distance) { hit_mesh = i; hit_distance = distance; } } } } if (hit_mesh != -1) { calc_barycentric_from_point(triangles[hit_mesh], hits[hit_mesh].index, hits[hit_mesh].co, &primitive_id, uv); pixel_array[pixel_id].primitive_id = primitive_id; pixel_array[pixel_id].object_id = hit_mesh; copy_v2_v2(pixel_array[pixel_id].uv, uv); /* the differentials are relative to the UV/image space, so the highpoly differentials * are the same as the low poly differentials */ pixel_array[pixel_id].du_dx = du_dx; pixel_array[pixel_id].du_dy = du_dy; pixel_array[pixel_id].dv_dx = dv_dx; pixel_array[pixel_id].dv_dy = dv_dy; } else { pixel_array[pixel_id].primitive_id = -1; pixel_array[pixel_id].object_id = -1; } MEM_freeN(hits); return hit_mesh != -1; }
static int rule_follow_leader(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa) { BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader*) rule; float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f}; float mul, len; int n = (flbr->queue_size <= 1) ? bbd->sim->psys->totpart : flbr->queue_size; int i, ret = 0, p = pa - bbd->sim->psys->particles; if (flbr->ob) { float vec2[3], t; /* first check we're not blocking the leader */ sub_v3_v3v3(vec, flbr->loc, flbr->oloc); mul_v3_fl(vec, 1.0f/bbd->timestep); sub_v3_v3v3(loc, pa->prev_state.co, flbr->oloc); mul = dot_v3v3(vec, vec); /* leader is not moving */ if (mul < 0.01f) { len = len_v3(loc); /* too close to leader */ if (len < 2.0f * val->personal_space * pa->size) { copy_v3_v3(bbd->wanted_co, loc); bbd->wanted_speed = val->max_speed; return 1; } } else { t = dot_v3v3(loc, vec)/mul; /* possible blocking of leader in near future */ if (t > 0.0f && t < 3.0f) { copy_v3_v3(vec2, vec); mul_v3_fl(vec2, t); sub_v3_v3v3(vec2, loc, vec2); len = len_v3(vec2); if (len < 2.0f * val->personal_space * pa->size) { copy_v3_v3(bbd->wanted_co, vec2); bbd->wanted_speed = val->max_speed * (3.0f - t)/3.0f; return 1; } } } /* not blocking so try to follow leader */ if (p && flbr->options & BRULE_LEADER_IN_LINE) { copy_v3_v3(vec, bbd->sim->psys->particles[p-1].prev_state.vel); copy_v3_v3(loc, bbd->sim->psys->particles[p-1].prev_state.co); } else { copy_v3_v3(loc, flbr->oloc); sub_v3_v3v3(vec, flbr->loc, flbr->oloc); mul_v3_fl(vec, 1.0f/bbd->timestep); } /* fac is seconds behind leader */ madd_v3_v3fl(loc, vec, -flbr->distance); sub_v3_v3v3(bbd->wanted_co, loc, pa->prev_state.co); bbd->wanted_speed = len_v3(bbd->wanted_co); ret = 1; } else if (p % n) { float vec2[3], t, t_min = 3.0f; /* first check we're not blocking any leaders */ for (i = 0; i< bbd->sim->psys->totpart; i+=n) { copy_v3_v3(vec, bbd->sim->psys->particles[i].prev_state.vel); sub_v3_v3v3(loc, pa->prev_state.co, bbd->sim->psys->particles[i].prev_state.co); mul = dot_v3v3(vec, vec); /* leader is not moving */ if (mul < 0.01f) { len = len_v3(loc); /* too close to leader */ if (len < 2.0f * val->personal_space * pa->size) { copy_v3_v3(bbd->wanted_co, loc); bbd->wanted_speed = val->max_speed; return 1; } } else { t = dot_v3v3(loc, vec)/mul; /* possible blocking of leader in near future */ if (t > 0.0f && t < t_min) { copy_v3_v3(vec2, vec); mul_v3_fl(vec2, t); sub_v3_v3v3(vec2, loc, vec2); len = len_v3(vec2); if (len < 2.0f * val->personal_space * pa->size) { t_min = t; copy_v3_v3(bbd->wanted_co, loc); bbd->wanted_speed = val->max_speed * (3.0f - t)/3.0f; ret = 1; } } } } if (ret) return 1; /* not blocking so try to follow leader */ if (flbr->options & BRULE_LEADER_IN_LINE) { copy_v3_v3(vec, bbd->sim->psys->particles[p-1].prev_state.vel); copy_v3_v3(loc, bbd->sim->psys->particles[p-1].prev_state.co); } else { copy_v3_v3(vec, bbd->sim->psys->particles[p - p%n].prev_state.vel); copy_v3_v3(loc, bbd->sim->psys->particles[p - p%n].prev_state.co); } /* fac is seconds behind leader */ madd_v3_v3fl(loc, vec, -flbr->distance); sub_v3_v3v3(bbd->wanted_co, loc, pa->prev_state.co); bbd->wanted_speed = len_v3(bbd->wanted_co); ret = 1; } return ret; }
static void rotateDifferentialCoordinates(LaplacianSystem *sys) { float alpha, beta, gamma; float pj[3], ni[3], di[3]; float uij[3], dun[3], e2[3], pi[3], fni[3], vn[3][3]; int i, j, num_fni, k, fi; int *fidn; for (i = 0; i < sys->total_verts; i++) { copy_v3_v3(pi, sys->co[i]); copy_v3_v3(ni, sys->no[i]); k = sys->unit_verts[i]; copy_v3_v3(pj, sys->co[k]); sub_v3_v3v3(uij, pj, pi); mul_v3_v3fl(dun, ni, dot_v3v3(uij, ni)); sub_v3_v3(uij, dun); normalize_v3(uij); cross_v3_v3v3(e2, ni, uij); copy_v3_v3(di, sys->delta[i]); alpha = dot_v3v3(ni, di); beta = dot_v3v3(uij, di); gamma = dot_v3v3(e2, di); pi[0] = EIG_linear_solver_variable_get(sys->context, 0, i); pi[1] = EIG_linear_solver_variable_get(sys->context, 1, i); pi[2] = EIG_linear_solver_variable_get(sys->context, 2, i); zero_v3(ni); num_fni = sys->ringf_map[i].count; for (fi = 0; fi < num_fni; fi++) { const unsigned int *vin; fidn = sys->ringf_map[i].indices; vin = sys->tris[fidn[fi]]; for (j = 0; j < 3; j++) { vn[j][0] = EIG_linear_solver_variable_get(sys->context, 0, vin[j]); vn[j][1] = EIG_linear_solver_variable_get(sys->context, 1, vin[j]); vn[j][2] = EIG_linear_solver_variable_get(sys->context, 2, vin[j]); if (vin[j] == sys->unit_verts[i]) { copy_v3_v3(pj, vn[j]); } } normal_tri_v3(fni, UNPACK3(vn)); add_v3_v3(ni, fni); } normalize_v3(ni); sub_v3_v3v3(uij, pj, pi); mul_v3_v3fl(dun, ni, dot_v3v3(uij, ni)); sub_v3_v3(uij, dun); normalize_v3(uij); cross_v3_v3v3(e2, ni, uij); fni[0] = alpha * ni[0] + beta * uij[0] + gamma * e2[0]; fni[1] = alpha * ni[1] + beta * uij[1] + gamma * e2[1]; fni[2] = alpha * ni[2] + beta * uij[2] + gamma * e2[2]; if (len_squared_v3(fni) > FLT_EPSILON) { EIG_linear_solver_right_hand_side_add(sys->context, 0, i, fni[0]); EIG_linear_solver_right_hand_side_add(sys->context, 1, i, fni[1]); EIG_linear_solver_right_hand_side_add(sys->context, 2, i, fni[2]); } else { EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]); EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]); EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]); } } }
static void testRadialSymmetry(BGraph *graph, BNode *root_node, RadialArc *ring, int total, float axis[3], float limit, int group) { const float limit_sq = limit * limit; int symmetric = 1; int i; /* sort ring by angle */ for (i = 0; i < total - 1; i++) { float minAngle = FLT_MAX; int minIndex = -1; int j; for (j = i + 1; j < total; j++) { float angle = dot_v3v3(ring[i].n, ring[j].n); /* map negative values to 1..2 */ if (angle < 0) { angle = 1 - angle; } if (angle < minAngle) { minIndex = j; minAngle = angle; } } /* swap if needed */ if (minIndex != i + 1) { RadialArc tmp; tmp = ring[i + 1]; ring[i + 1] = ring[minIndex]; ring[minIndex] = tmp; } } for (i = 0; i < total && symmetric; i++) { BNode *node1, *node2; float tangent[3]; float normal[3]; float p[3]; int j = (i + 1) % total; /* next arc in the circular list */ add_v3_v3v3(tangent, ring[i].n, ring[j].n); cross_v3_v3v3(normal, tangent, axis); node1 = BLI_otherNode(ring[i].arc, root_node); node2 = BLI_otherNode(ring[j].arc, root_node); copy_v3_v3(p, node2->p); BLI_mirrorAlongAxis(p, root_node->p, normal); /* check if it's within limit before continuing */ if (len_squared_v3v3(node1->p, p) > limit_sq) { symmetric = 0; } } if (symmetric) { /* mark node as symmetric physically */ copy_v3_v3(root_node->symmetry_axis, axis); root_node->symmetry_flag |= SYM_PHYSICAL; root_node->symmetry_flag |= SYM_RADIAL; /* FLAG SYMMETRY GROUP */ for (i = 0; i < total; i++) { ring[i].arc->symmetry_group = group; ring[i].arc->symmetry_flag = SYM_SIDE_RADIAL + i; } if (graph->radial_symmetry) { graph->radial_symmetry(root_node, ring, total); } } }
int BLI_edgefill_ex(ScanFillContext *sf_ctx, const short do_quad_tri_speedup, const float nor_proj[3]) { /* * - fill works with its own lists, so create that first (no faces!) * - for vertices, put in ->tmp.v the old pointer * - struct elements xs en ys are not used here: don't hide stuff in it * - edge flag ->f becomes 2 when it's a new edge * - mode: & 1 is check for crossings, then create edges (TO DO ) * - returns number of triangle faces added. */ ListBase tempve, temped; ScanFillVert *eve; ScanFillEdge *eed, *nexted; PolyFill *pflist, *pf; float *min_xy_p, *max_xy_p; short a, c, poly = 0, ok = 0, toggle = 0; int totfaces = 0; /* total faces added */ int co_x, co_y; /* reset variables */ eve = sf_ctx->fillvertbase.first; a = 0; while (eve) { eve->f = 0; eve->poly_nr = 0; eve->h = 0; eve = eve->next; a += 1; } if (do_quad_tri_speedup && (a == 3)) { eve = sf_ctx->fillvertbase.first; addfillface(sf_ctx, eve, eve->next, eve->next->next); return 1; } else if (do_quad_tri_speedup && (a == 4)) { float vec1[3], vec2[3]; eve = sf_ctx->fillvertbase.first; /* no need to check 'eve->next->next->next' is valid, already counted */ /* use shortest diagonal for quad */ sub_v3_v3v3(vec1, eve->co, eve->next->next->co); sub_v3_v3v3(vec2, eve->next->co, eve->next->next->next->co); if (dot_v3v3(vec1, vec1) < dot_v3v3(vec2, vec2)) { addfillface(sf_ctx, eve, eve->next, eve->next->next); addfillface(sf_ctx, eve->next->next, eve->next->next->next, eve); } else { addfillface(sf_ctx, eve->next, eve->next->next, eve->next->next->next); addfillface(sf_ctx, eve->next->next->next, eve, eve->next); } return 2; } /* first test vertices if they are in edges */ /* including resetting of flags */ eed = sf_ctx->filledgebase.first; while (eed) { eed->poly_nr = 0; eed->v1->f = SF_VERT_UNKNOWN; eed->v2->f = SF_VERT_UNKNOWN; eed = eed->next; } eve = sf_ctx->fillvertbase.first; while (eve) { if (eve->f & SF_VERT_UNKNOWN) { ok = 1; break; } eve = eve->next; } if (ok == 0) { return 0; } else { float n[3]; if (nor_proj) { copy_v3_v3(n, nor_proj); } else { /* define projection: with 'best' normal */ /* Newell's Method */ /* Similar code used elsewhere, but this checks for double ups * which historically this function supports so better not change */ float *v_prev; zero_v3(n); eve = sf_ctx->fillvertbase.last; v_prev = eve->co; for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) { if (LIKELY(!compare_v3v3(v_prev, eve->co, SF_EPSILON))) { add_newell_cross_v3_v3v3(n, v_prev, eve->co); v_prev = eve->co; } } } if (UNLIKELY(normalize_v3(n) == 0.0f)) { return 0; } axis_dominant_v3(&co_x, &co_y, n); } /* STEP 1: COUNT POLYS */ eve = sf_ctx->fillvertbase.first; while (eve) { eve->xy[0] = eve->co[co_x]; eve->xy[1] = eve->co[co_y]; /* get first vertex with no poly number */ if (eve->poly_nr == 0) { poly++; /* now a sort of select connected */ ok = 1; eve->poly_nr = poly; while (ok) { ok = 0; toggle++; if (toggle & 1) eed = sf_ctx->filledgebase.first; else eed = sf_ctx->filledgebase.last; while (eed) { if (eed->v1->poly_nr == 0 && eed->v2->poly_nr == poly) { eed->v1->poly_nr = poly; eed->poly_nr = poly; ok = 1; } else if (eed->v2->poly_nr == 0 && eed->v1->poly_nr == poly) { eed->v2->poly_nr = poly; eed->poly_nr = poly; ok = 1; } else if (eed->poly_nr == 0) { if (eed->v1->poly_nr == poly && eed->v2->poly_nr == poly) { eed->poly_nr = poly; ok = 1; } } if (toggle & 1) eed = eed->next; else eed = eed->prev; } } } eve = eve->next; } /* printf("amount of poly's: %d\n",poly); */ /* STEP 2: remove loose edges and strings of edges */ eed = sf_ctx->filledgebase.first; while (eed) { if (eed->v1->h++ > 250) break; if (eed->v2->h++ > 250) break; eed = eed->next; } if (eed) { /* otherwise it's impossible to be sure you can clear vertices */ callLocalErrorCallBack("No vertices with 250 edges allowed!"); return 0; } /* does it only for vertices with ->h==1 */ testvertexnearedge(sf_ctx); ok = 1; while (ok) { ok = 0; toggle++; if (toggle & 1) eed = sf_ctx->filledgebase.first; else eed = sf_ctx->filledgebase.last; while (eed) { if (toggle & 1) nexted = eed->next; else nexted = eed->prev; if (eed->v1->h == 1) { eed->v2->h--; BLI_remlink(&sf_ctx->fillvertbase, eed->v1); BLI_remlink(&sf_ctx->filledgebase, eed); ok = 1; } else if (eed->v2->h == 1) { eed->v1->h--; BLI_remlink(&sf_ctx->fillvertbase, eed->v2); BLI_remlink(&sf_ctx->filledgebase, eed); ok = 1; } eed = nexted; } } if (sf_ctx->filledgebase.first == 0) { /* printf("All edges removed\n"); */ return 0; } /* CURRENT STATUS: * - eve->f :1= availalble in edges * - eve->xs :polynumber * - eve->h :amount of edges connected to vertex * - eve->tmp.v :store! original vertex number * * - eed->f :1= boundary edge (optionally set by caller) * - eed->poly_nr :poly number */ /* STEP 3: MAKE POLYFILL STRUCT */ pflist = (PolyFill *)MEM_callocN(poly * sizeof(PolyFill), "edgefill"); pf = pflist; for (a = 1; a <= poly; a++) { pf->nr = a; pf->min_xy[0] = pf->min_xy[1] = 1.0e20; pf->max_xy[0] = pf->max_xy[1] = -1.0e20; pf++; } eed = sf_ctx->filledgebase.first; while (eed) { pflist[eed->poly_nr - 1].edges++; eed = eed->next; } eve = sf_ctx->fillvertbase.first; while (eve) { pflist[eve->poly_nr - 1].verts++; min_xy_p = pflist[eve->poly_nr - 1].min_xy; max_xy_p = pflist[eve->poly_nr - 1].max_xy; min_xy_p[0] = (min_xy_p[0]) < (eve->xy[0]) ? (min_xy_p[0]) : (eve->xy[0]); min_xy_p[1] = (min_xy_p[1]) < (eve->xy[1]) ? (min_xy_p[1]) : (eve->xy[1]); max_xy_p[0] = (max_xy_p[0]) > (eve->xy[0]) ? (max_xy_p[0]) : (eve->xy[0]); max_xy_p[1] = (max_xy_p[1]) > (eve->xy[1]) ? (max_xy_p[1]) : (eve->xy[1]); if (eve->h > 2) pflist[eve->poly_nr - 1].f = 1; eve = eve->next; } /* STEP 4: FIND HOLES OR BOUNDS, JOIN THEM * ( bounds just to divide it in pieces for optimization, * the edgefill itself has good auto-hole detection) * WATCH IT: ONLY WORKS WITH SORTED POLYS!!! */ if (poly > 1) { short *polycache, *pc; /* so, sort first */ qsort(pflist, poly, sizeof(PolyFill), vergpoly); #if 0 pf = pflist; for (a = 1; a <= poly; a++) { printf("poly:%d edges:%d verts:%d flag: %d\n", a, pf->edges, pf->verts, pf->f); PRINT2(f, f, pf->min[0], pf->min[1]); pf++; } #endif polycache = pc = MEM_callocN(sizeof(short) * poly, "polycache"); pf = pflist; for (a = 0; a < poly; a++, pf++) { for (c = a + 1; c < poly; c++) { /* if 'a' inside 'c': join (bbox too) * Careful: 'a' can also be inside another poly. */ if (boundisect(pf, pflist + c)) { *pc = c; pc++; } /* only for optimize! */ /* else if (pf->max_xy[0] < (pflist+c)->min[cox]) break; */ } while (pc != polycache) { pc--; mergepolysSimp(sf_ctx, pf, pflist + *pc); } } MEM_freeN(polycache); } #if 0 printf("after merge\n"); pf = pflist; for (a = 1; a <= poly; a++) { printf("poly:%d edges:%d verts:%d flag: %d\n", a, pf->edges, pf->verts, pf->f); pf++; } #endif /* STEP 5: MAKE TRIANGLES */ tempve.first = sf_ctx->fillvertbase.first; tempve.last = sf_ctx->fillvertbase.last; temped.first = sf_ctx->filledgebase.first; temped.last = sf_ctx->filledgebase.last; sf_ctx->fillvertbase.first = sf_ctx->fillvertbase.last = NULL; sf_ctx->filledgebase.first = sf_ctx->filledgebase.last = NULL; pf = pflist; for (a = 0; a < poly; a++) { if (pf->edges > 1) { splitlist(sf_ctx, &tempve, &temped, pf->nr); totfaces += scanfill(sf_ctx, pf); } pf++; } BLI_movelisttolist(&sf_ctx->fillvertbase, &tempve); BLI_movelisttolist(&sf_ctx->filledgebase, &temped); /* FREE */ MEM_freeN(pflist); return totfaces; }
/** * \return a face index in \a faces and set \a r_is_flip * if the face is flipped away from the center. */ static int recalc_face_normals_find_index(BMesh *bm, BMFace **faces, const int faces_len, bool *r_is_flip) { const float eps = FLT_EPSILON; float cent_area_accum = 0.0f; float cent[3]; const float cent_fac = 1.0f / (float)faces_len; bool is_flip = false; int f_start_index; int i; /** Search for the best loop. Members are compared in-order defined here. */ struct { /** * Squared distance from the center to the loops vertex 'l->v'. * The normalized direction between the center and this vertex * is also used for the dot-products below. */ float dist_sq; /** * Signed dot product using the normalized edge vector, * (best of 'l->prev->v' or 'l->next->v'). */ float edge_dot; /** * Unsigned dot product using the loop-normal * (sign is used to check if we need to flip). */ float loop_dot; } best, test; UNUSED_VARS_NDEBUG(bm); zero_v3(cent); /* first calculate the center */ for (i = 0; i < faces_len; i++) { float f_cent[3]; const float f_area = BM_face_calc_area(faces[i]); BM_face_calc_center_median_weighted(faces[i], f_cent); madd_v3_v3fl(cent, f_cent, cent_fac * f_area); cent_area_accum += f_area; BLI_assert(BMO_face_flag_test(bm, faces[i], FACE_TEMP) == 0); BLI_assert(BM_face_is_normal_valid(faces[i])); } if (cent_area_accum != 0.0f) { mul_v3_fl(cent, 1.0f / cent_area_accum); } /* Distances must start above zero, * or we can't do meaningful calculations based on the direction to the center */ best.dist_sq = eps; best.edge_dot = best.loop_dot = -FLT_MAX; /* used in degenerate cases only */ f_start_index = 0; /** * Find the outer-most vertex, comparing distance to the center, * then the outer-most loop attached to that vertex. * * Important this is correctly detected, * where casting a ray from the center wont hit any loops past this one. * Otherwise the result may be incorrect. */ for (i = 0; i < faces_len; i++) { BMLoop *l_iter, *l_first; l_iter = l_first = BM_FACE_FIRST_LOOP(faces[i]); do { bool is_best_dist_sq; float dir[3]; sub_v3_v3v3(dir, l_iter->v->co, cent); test.dist_sq = len_squared_v3(dir); is_best_dist_sq = (test.dist_sq > best.dist_sq); if (is_best_dist_sq || (test.dist_sq == best.dist_sq)) { float edge_dir_pair[2][3]; mul_v3_fl(dir, 1.0f / sqrtf(test.dist_sq)); sub_v3_v3v3(edge_dir_pair[0], l_iter->next->v->co, l_iter->v->co); sub_v3_v3v3(edge_dir_pair[1], l_iter->prev->v->co, l_iter->v->co); if ((normalize_v3(edge_dir_pair[0]) > eps) && (normalize_v3(edge_dir_pair[1]) > eps)) { bool is_best_edge_dot; test.edge_dot = max_ff(dot_v3v3(dir, edge_dir_pair[0]), dot_v3v3(dir, edge_dir_pair[1])); is_best_edge_dot = (test.edge_dot > best.edge_dot); if (is_best_dist_sq || is_best_edge_dot || (test.edge_dot == best.edge_dot)) { float loop_dir[3]; cross_v3_v3v3(loop_dir, edge_dir_pair[0], edge_dir_pair[1]); if (normalize_v3(loop_dir) > eps) { float loop_dir_dot; /* Highly unlikely the furthest loop is also the concave part of an ngon, * but it can be contrived with _very_ non-planar faces - so better check. */ if (UNLIKELY(dot_v3v3(loop_dir, l_iter->f->no) < 0.0f)) { negate_v3(loop_dir); } loop_dir_dot = dot_v3v3(dir, loop_dir); test.loop_dot = fabsf(loop_dir_dot); if (is_best_dist_sq || is_best_edge_dot || (test.loop_dot > best.loop_dot)) { best = test; f_start_index = i; is_flip = (loop_dir_dot < 0.0f); } } } } } } while ((l_iter = l_iter->next) != l_first); } *r_is_flip = is_flip; return f_start_index; }
static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd, Object *ob, DerivedMesh *dm) { float (*coords)[3], (*co)[3]; MLoopUV *mloop_uv; MTexPoly *mtexpoly, *mt = NULL; int i, numVerts, numPolys, numLoops; Image *image = umd->image; MPoly *mpoly, *mp; MLoop *mloop; const bool override_image = (umd->flags & MOD_UVPROJECT_OVERRIDEIMAGE) != 0; Projector projectors[MOD_UVPROJECT_MAXPROJECTORS]; int num_projectors = 0; char uvname[MAX_CUSTOMDATA_LAYER_NAME]; float aspx = umd->aspectx ? umd->aspectx : 1.0f; float aspy = umd->aspecty ? umd->aspecty : 1.0f; float scax = umd->scalex ? umd->scalex : 1.0f; float scay = umd->scaley ? umd->scaley : 1.0f; int free_uci = 0; for (i = 0; i < umd->num_projectors; ++i) if (umd->projectors[i]) projectors[num_projectors++].ob = umd->projectors[i]; if (num_projectors == 0) return dm; /* make sure there are UV Maps available */ if (!CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) return dm; /* make sure we're using an existing layer */ CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, umd->uvlayer_name, uvname); /* calculate a projection matrix and normal for each projector */ for (i = 0; i < num_projectors; ++i) { float tmpmat[4][4]; float offsetmat[4][4]; Camera *cam = NULL; /* calculate projection matrix */ invert_m4_m4(projectors[i].projmat, projectors[i].ob->obmat); projectors[i].uci = NULL; if (projectors[i].ob->type == OB_CAMERA) { cam = (Camera *)projectors[i].ob->data; if (cam->type == CAM_PANO) { projectors[i].uci = BLI_uvproject_camera_info(projectors[i].ob, NULL, aspx, aspy); BLI_uvproject_camera_info_scale(projectors[i].uci, scax, scay); free_uci = 1; } else { CameraParams params; /* setup parameters */ BKE_camera_params_init(¶ms); BKE_camera_params_from_object(¶ms, projectors[i].ob); /* compute matrix, viewplane, .. */ BKE_camera_params_compute_viewplane(¶ms, 1, 1, aspx, aspy); /* scale the view-plane */ params.viewplane.xmin *= scax; params.viewplane.xmax *= scax; params.viewplane.ymin *= scay; params.viewplane.ymax *= scay; BKE_camera_params_compute_matrix(¶ms); mul_m4_m4m4(tmpmat, params.winmat, projectors[i].projmat); } } else { copy_m4_m4(tmpmat, projectors[i].projmat); } unit_m4(offsetmat); mul_mat3_m4_fl(offsetmat, 0.5); offsetmat[3][0] = offsetmat[3][1] = offsetmat[3][2] = 0.5; mul_m4_m4m4(projectors[i].projmat, offsetmat, tmpmat); /* calculate worldspace projector normal (for best projector test) */ projectors[i].normal[0] = 0; projectors[i].normal[1] = 0; projectors[i].normal[2] = 1; mul_mat3_m4_v3(projectors[i].ob->obmat, projectors[i].normal); } numPolys = dm->getNumPolys(dm); numLoops = dm->getNumLoops(dm); /* make sure we are not modifying the original UV map */ mloop_uv = CustomData_duplicate_referenced_layer_named(&dm->loopData, CD_MLOOPUV, uvname, numLoops); /* can be NULL */ mt = mtexpoly = CustomData_duplicate_referenced_layer_named(&dm->polyData, CD_MTEXPOLY, uvname, numPolys); numVerts = dm->getNumVerts(dm); coords = MEM_mallocN(sizeof(*coords) * numVerts, "uvprojectModifier_do coords"); dm->getVertCos(dm, coords); /* convert coords to world space */ for (i = 0, co = coords; i < numVerts; ++i, ++co) mul_m4_v3(ob->obmat, *co); /* if only one projector, project coords to UVs */ if (num_projectors == 1 && projectors[0].uci == NULL) for (i = 0, co = coords; i < numVerts; ++i, ++co) mul_project_m4_v3(projectors[0].projmat, *co); mpoly = dm->getPolyArray(dm); mloop = dm->getLoopArray(dm); /* apply coords as UVs, and apply image if tfaces are new */ for (i = 0, mp = mpoly; i < numPolys; ++i, ++mp, ++mt) { if (override_image || !image || (mtexpoly == NULL || mt->tpage == image)) { if (num_projectors == 1) { if (projectors[0].uci) { unsigned int fidx = mp->totloop - 1; do { unsigned int lidx = mp->loopstart + fidx; unsigned int vidx = mloop[lidx].v; BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], projectors[0].uci); } while (fidx--); } else { /* apply transformed coords as UVs */ unsigned int fidx = mp->totloop - 1; do { unsigned int lidx = mp->loopstart + fidx; unsigned int vidx = mloop[lidx].v; copy_v2_v2(mloop_uv[lidx].uv, coords[vidx]); } while (fidx--); } } else { /* multiple projectors, select the closest to face normal direction */ float face_no[3]; int j; Projector *best_projector; float best_dot; /* get the untransformed face normal */ BKE_mesh_calc_poly_normal_coords(mp, mloop + mp->loopstart, (const float (*)[3])coords, face_no); /* find the projector which the face points at most directly * (projector normal with largest dot product is best) */ best_dot = dot_v3v3(projectors[0].normal, face_no); best_projector = &projectors[0]; for (j = 1; j < num_projectors; ++j) { float tmp_dot = dot_v3v3(projectors[j].normal, face_no); if (tmp_dot > best_dot) { best_dot = tmp_dot; best_projector = &projectors[j]; } } if (best_projector->uci) { unsigned int fidx = mp->totloop - 1; do { unsigned int lidx = mp->loopstart + fidx; unsigned int vidx = mloop[lidx].v; BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], best_projector->uci); } while (fidx--); } else { unsigned int fidx = mp->totloop - 1; do { unsigned int lidx = mp->loopstart + fidx; unsigned int vidx = mloop[lidx].v; mul_v2_project_m4_v3(mloop_uv[lidx].uv, best_projector->projmat, coords[vidx]); } while (fidx--); } } } if (override_image && mtexpoly) { mt->tpage = image; } } MEM_freeN(coords); if (free_uci) { int j; for (j = 0; j < num_projectors; ++j) { if (projectors[j].uci) { MEM_freeN(projectors[j].uci); } } } /* Mark tessellated CD layers as dirty. */ dm->dirty |= DM_DIRTY_TESS_CDLAYERS; return dm; }
/* MultiresBake callback for heights baking * general idea: * - find coord of point with specified UV in hi-res mesh (let's call it p1) * - find coord of point and normal with specified UV in lo-res mesh (or subdivided lo-res * mesh to make texture smoother) let's call this point p0 and n. * - height wound be dot(n, p1-p0) */ static void apply_heights_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, void *thread_data_v, void *bake_data, ImBuf *ibuf, const int face_index, const int lvl, const float st[2], float UNUSED(tangmat[3][3]), const int x, const int y) { MTFace *mtface = CustomData_get_layer(&lores_dm->faceData, CD_MTFACE); MFace mface; MHeightBakeData *height_data = (MHeightBakeData *)bake_data; MultiresBakeThread *thread_data = (MultiresBakeThread *) thread_data_v; float uv[2], *st0, *st1, *st2, *st3; int pixel = ibuf->x * y + x; float vec[3], p0[3], p1[3], n[3], len; lores_dm->getTessFace(lores_dm, face_index, &mface); st0 = mtface[face_index].uv[0]; st1 = mtface[face_index].uv[1]; st2 = mtface[face_index].uv[2]; if (mface.v4) { st3 = mtface[face_index].uv[3]; resolve_quad_uv(uv, st, st0, st1, st2, st3); } else resolve_tri_uv(uv, st, st0, st1, st2); CLAMP(uv[0], 0.0f, 1.0f); CLAMP(uv[1], 0.0f, 1.0f); get_ccgdm_data(lores_dm, hires_dm, height_data->orig_index_mf_to_mpoly, height_data->orig_index_mp_to_orig, lvl, face_index, uv[0], uv[1], p1, NULL); if (height_data->ssdm) { get_ccgdm_data(lores_dm, height_data->ssdm, height_data->orig_index_mf_to_mpoly, height_data->orig_index_mp_to_orig, 0, face_index, uv[0], uv[1], p0, n); } else { lores_dm->getTessFace(lores_dm, face_index, &mface); if (mface.v4) { interp_bilinear_mface(lores_dm, &mface, uv[0], uv[1], 1, p0); interp_bilinear_mface(lores_dm, &mface, uv[0], uv[1], 0, n); } else { interp_barycentric_mface(lores_dm, &mface, uv[0], uv[1], 1, p0); interp_barycentric_mface(lores_dm, &mface, uv[0], uv[1], 0, n); } } sub_v3_v3v3(vec, p1, p0); len = dot_v3v3(n, vec); height_data->heights[pixel] = len; thread_data->height_min = min_ff(thread_data->height_min, len); thread_data->height_max = max_ff(thread_data->height_max, len); if (ibuf->rect_float) { float *rrgbf = ibuf->rect_float + pixel * 4; rrgbf[0] = rrgbf[1] = rrgbf[2] = len; rrgbf[3] = 1.0f; } else { char *rrgb = (char *)ibuf->rect + pixel * 4; rrgb[0] = rrgb[1] = rrgb[2] = FTOCHAR(len); rrgb[3] = 255; } }
/* MultiresBake callback for heights baking general idea: - find coord of point with specified UV in hi-res mesh (let's call it p1) - find coord of point and normal with specified UV in lo-res mesh (or subdivided lo-res mesh to make texture smoother) let's call this point p0 and n. - height wound be dot(n, p1-p0) */ static void apply_heights_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *bake_data, const int face_index, const int lvl, const float st[2], float UNUSED(tangmat[3][3]), const int x, const int y) { MTFace *mtface= CustomData_get_layer(&lores_dm->faceData, CD_MTFACE); MFace mface; Image *ima= mtface[face_index].tpage; ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); MHeightBakeData *height_data= (MHeightBakeData*)bake_data; float uv[2], *st0, *st1, *st2, *st3; int pixel= ibuf->x*y + x; float vec[3], p0[3], p1[3], n[3], len; lores_dm->getFace(lores_dm, face_index, &mface); st0= mtface[face_index].uv[0]; st1= mtface[face_index].uv[1]; st2= mtface[face_index].uv[2]; if(mface.v4) { st3= mtface[face_index].uv[3]; resolve_quad_uv(uv, st, st0, st1, st2, st3); } else resolve_tri_uv(uv, st, st0, st1, st2); CLAMP(uv[0], 0.0f, 1.0f); CLAMP(uv[1], 0.0f, 1.0f); get_ccgdm_data(lores_dm, hires_dm, lvl, face_index, uv[0], uv[1], p1, 0); if(height_data->ssdm) { //get_ccgdm_data_ss(lores_dm, height_data->ssdm, lvl, face_index, uv[0], uv[1], p0, n); get_ccgdm_data(lores_dm, height_data->ssdm, 0, face_index, uv[0], uv[1], p0, n); } else { MFace mface; lores_dm->getFace(lores_dm, face_index, &mface); if(mface.v4) { interp_bilinear_mface(lores_dm, &mface, uv[0], uv[1], 1, p0); interp_bilinear_mface(lores_dm, &mface, uv[0], uv[1], 0, n); } else { interp_barycentric_mface(lores_dm, &mface, uv[0], uv[1], 1, p0); interp_barycentric_mface(lores_dm, &mface, uv[0], uv[1], 0, n); } } sub_v3_v3v3(vec, p1, p0); //len= len_v3(vec); len= dot_v3v3(n, vec); height_data->heights[pixel]= len; if(len<height_data->height_min) height_data->height_min= len; if(len>height_data->height_max) height_data->height_max= len; if(ibuf->rect_float) { float *rrgbf= ibuf->rect_float + pixel*4; rrgbf[3]= 1.0f; ibuf->userflags= IB_RECT_INVALID; } else { char *rrgb= (char*)ibuf->rect + pixel*4; rrgb[3]= 255; } }
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 */ /* UNUSED */, 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(); sub_v3_v3v3(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]; copy_v3_v3(edges[0][0], cv[4]); // maxx, maxy, minz copy_v3_v3(edges[1][0], cv[5]); // minx, maxy, minz copy_v3_v3(edges[2][0], cv[6]); // minx, miny, minz copy_v3_v3(edges[3][0], cv[7]); // maxx, miny, minz copy_v3_v3(edges[4][0], cv[3]); // maxx, miny, maxz copy_v3_v3(edges[5][0], cv[2]); // minx, miny, maxz copy_v3_v3(edges[6][0], cv[6]); // minx, miny, minz copy_v3_v3(edges[7][0], cv[7]); // maxx, miny, minz copy_v3_v3(edges[8][0], cv[1]); // minx, maxy, maxz copy_v3_v3(edges[9][0], cv[2]); // minx, miny, maxz copy_v3_v3(edges[10][0], cv[6]); // minx, miny, minz copy_v3_v3(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 copy_v3_v3(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]); */ /* UNUSED */ 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; copy_v3_v3(tmp_point, viewnormal); mul_v3_fl(tmp_point, -dd*((ds/dd)-(float)n)); add_v3_v3v3(tmp_point2, cv[good_index], tmp_point); d = dot_v3v3(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) { copy_v3_v3(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]; copy_v3_v3(tmp2, &points[j * 3]); copy_v3_v3(&points[j * 3], &points[i * 3]); copy_v3_v3(&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); } }
MALWAYS_INLINE int isec_tri_quad(float start[3], float dir[3], RayFace *face, float uv[2], float *lambda) { float co1[3], co2[3], co3[3], co4[3]; float t0[3], t1[3], x[3], r[3], m[3], u, v, divdet, det1, l; int quad; quad= RE_rayface_isQuad(face); copy_v3_v3(co1, face->v1); copy_v3_v3(co2, face->v2); copy_v3_v3(co3, face->v3); copy_v3_v3(r, dir); /* intersect triangle */ sub_v3_v3v3(t0, co3, co2); sub_v3_v3v3(t1, co3, co1); cross_v3_v3v3(x, r, t1); divdet= dot_v3v3(t0, x); sub_v3_v3v3(m, start, co3); det1= dot_v3v3(m, x); if(divdet != 0.0f) { divdet= 1.0f/divdet; v= det1*divdet; if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) { float cros[3]; cross_v3_v3v3(cros, m, t0); u= divdet*dot_v3v3(cros, r); if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON)) { l= divdet*dot_v3v3(cros, t1); /* check if intersection is within ray length */ if(l > -RE_RAYTRACE_EPSILON && l < *lambda) { uv[0]= u; uv[1]= v; *lambda= l; return 1; } } } } /* intersect second triangle in quad */ if(quad) { copy_v3_v3(co4, face->v4); sub_v3_v3v3(t0, co3, co4); divdet= dot_v3v3(t0, x); if(divdet != 0.0f) { divdet= 1.0f/divdet; v = det1*divdet; if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) { float cros[3]; cross_v3_v3v3(cros, m, t0); u= divdet*dot_v3v3(cros, r); if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON)) { l= divdet*dot_v3v3(cros, t1); if(l >- RE_RAYTRACE_EPSILON && l < *lambda) { uv[0]= u; uv[1]= -(1.0f + v + u); *lambda= l; return 2; } } } } } return 0; }
MINLINE float plane_point_side_v3(const float plane[4], const float co[3]) { return dot_v3v3(co, plane) + plane[3]; }
static PyObject *M_Geometry_intersect_ray_tri(PyObject *UNUSED(self), PyObject *args) { VectorObject *ray, *ray_off, *vec1, *vec2, *vec3; float dir[3], orig[3], v1[3], v2[3], v3[3], e1[3], e2[3], pvec[3], tvec[3], qvec[3]; float det, inv_det, u, v, t; int clip = 1; if (!PyArg_ParseTuple(args, "O!O!O!O!O!|i:intersect_ray_tri", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &ray, &vector_Type, &ray_off, &clip)) { return NULL; } if (vec1->size != 3 || vec2->size != 3 || vec3->size != 3 || ray->size != 3 || ray_off->size != 3) { PyErr_SetString(PyExc_ValueError, "only 3D vectors for all parameters"); return NULL; } if (BaseMath_ReadCallback(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1 || BaseMath_ReadCallback(vec3) == -1 || BaseMath_ReadCallback(ray) == -1 || BaseMath_ReadCallback(ray_off) == -1) { return NULL; } copy_v3_v3(v1, vec1->vec); copy_v3_v3(v2, vec2->vec); copy_v3_v3(v3, vec3->vec); copy_v3_v3(dir, ray->vec); normalize_v3(dir); copy_v3_v3(orig, ray_off->vec); /* find vectors for two edges sharing v1 */ sub_v3_v3v3(e1, v2, v1); sub_v3_v3v3(e2, v3, v1); /* begin calculating determinant - also used to calculated U parameter */ cross_v3_v3v3(pvec, dir, e2); /* if determinant is near zero, ray lies in plane of triangle */ det = dot_v3v3(e1, pvec); if (det > -0.000001f && det < 0.000001f) { Py_RETURN_NONE; } inv_det = 1.0f / det; /* calculate distance from v1 to ray origin */ sub_v3_v3v3(tvec, orig, v1); /* calculate U parameter and test bounds */ u = dot_v3v3(tvec, pvec) * inv_det; if (clip && (u < 0.0f || u > 1.0f)) { Py_RETURN_NONE; } /* prepare to test the V parameter */ cross_v3_v3v3(qvec, tvec, e1); /* calculate V parameter and test bounds */ v = dot_v3v3(dir, qvec) * inv_det; if (clip && (v < 0.0f || u + v > 1.0f)) { Py_RETURN_NONE; } /* calculate t, ray intersects triangle */ t = dot_v3v3(e2, qvec) * inv_det; mul_v3_fl(dir, t); add_v3_v3v3(pvec, orig, dir); return Vector_CreatePyObject(pvec, 3, Py_NEW, NULL); }