static void bvh_callback(void *userdata, int index, const BVHTreeRay *UNUSED(ray), BVHTreeRayHit *hit) { BVHCallbackUserData *data = (struct BVHCallbackUserData*)userdata; MFace *mf = data->sys->heat.mface + index; float (*verts)[3] = data->sys->heat.verts; float lambda, uv[2], n[3], dir[3]; mul_v3_v3fl(dir, data->vec, hit->dist); if(isect_ray_tri_v3(data->start, dir, verts[mf->v1], verts[mf->v2], verts[mf->v3], &lambda, uv)) { normal_tri_v3(n, verts[mf->v1], verts[mf->v2], verts[mf->v3]); if(lambda < 1.0f && dot_v3v3(n, data->vec) < -1e-5f) { hit->index = index; hit->dist *= lambda; } } mul_v3_v3fl(dir, data->vec, hit->dist); if(isect_ray_tri_v3(data->start, dir, verts[mf->v1], verts[mf->v3], verts[mf->v4], &lambda, uv)) { normal_tri_v3(n, verts[mf->v1], verts[mf->v3], verts[mf->v4]); if(lambda < 1.0f && dot_v3v3(n, data->vec) < -1e-5f) { hit->index = index; hit->dist *= lambda; } } }
/** * finalize after accumulation. */ static void calc_tangent_ortho(float ts[3][3]) { float v_tan_a[3], v_tan_b[3]; float t_vec_a[3], t_vec_b[3]; normalize_v3(ts[2]); copy_v3_v3(v_tan_a, ts[0]); copy_v3_v3(v_tan_b, ts[1]); cross_v3_v3v3(ts[1], ts[2], v_tan_a); mul_v3_fl(ts[1], dot_v3v3(ts[1], v_tan_b) < 0.0f ? -1.0f : 1.0f); /* orthognalise tangent */ mul_v3_v3fl(t_vec_a, ts[2], dot_v3v3(ts[2], v_tan_a)); sub_v3_v3v3(ts[0], v_tan_a, t_vec_a); /* orthognalise bitangent */ mul_v3_v3fl(t_vec_a, ts[2], dot_v3v3(ts[2], ts[1])); mul_v3_v3fl(t_vec_b, ts[0], dot_v3v3(ts[0], ts[1]) / dot_v3v3(v_tan_a, v_tan_a)); sub_v3_v3(ts[1], t_vec_a); sub_v3_v3(ts[1], t_vec_b); normalize_v3(ts[0]); normalize_v3(ts[1]); }
/** * \param r_distance Distance to the hit point */ static bool walk_floor_distance_get(bContext *C, RegionView3D *rv3d, WalkInfo *walk, const float dvec[3], float *r_distance) { float dummy_dist_px = 0; float ray_normal[3] = {0, 0, -1}; /* down */ float ray_start[3]; float r_location[3]; float r_normal[3]; float dvec_tmp[3]; bool ret; *r_distance = TRANSFORM_DIST_MAX_RAY; copy_v3_v3(ray_start, rv3d->viewinv[3]); mul_v3_v3fl(dvec_tmp, dvec, walk->grid); add_v3_v3(ray_start, dvec_tmp); ret = snapObjectsRayEx(CTX_data_scene(C), NULL, NULL, NULL, NULL, SCE_SNAP_MODE_FACE, NULL, NULL, ray_start, ray_normal, r_distance, NULL, &dummy_dist_px, r_location, r_normal, SNAP_ALL); /* artifically scale the distance to the scene size */ *r_distance /= walk->grid; return ret; }
static int bake_intersect_tree(RayObject *raytree, Isect *isect, float *start, float *dir, float sign, float *hitco, float *dist) { float maxdist; int hit; /* might be useful to make a user setting for maxsize*/ if (R.r.bake_maxdist > 0.0f) maxdist = R.r.bake_maxdist; else maxdist = RE_RAYTRACE_MAXDIST + R.r.bake_biasdist; /* 'dir' is always normalized */ madd_v3_v3v3fl(isect->start, start, dir, -R.r.bake_biasdist); mul_v3_v3fl(isect->dir, dir, sign); isect->dist = maxdist; hit = RE_rayobject_raycast(raytree, isect); if (hit) { madd_v3_v3v3fl(hitco, isect->start, isect->dir, isect->dist); *dist = isect->dist; } return hit; }
void sk_straightenStroke(SK_Stroke *stk, int start, int end, float p_start[3], float p_end[3]) { SK_Point pt1, pt2; SK_Point *prev, *next; float delta_p[3]; int i, total; total = end - start; sub_v3_v3v3(delta_p, p_end, p_start); prev = stk->points + start; next = stk->points + end; copy_v3_v3(pt1.p, p_start); copy_v3_v3(pt1.no, prev->no); pt1.mode = prev->mode; pt1.type = prev->type; copy_v3_v3(pt2.p, p_end); copy_v3_v3(pt2.no, next->no); pt2.mode = next->mode; pt2.type = next->type; sk_insertStrokePoint(stk, &pt1, start + 1); /* insert after start */ sk_insertStrokePoint(stk, &pt2, end + 1); /* insert before end (since end was pushed back already) */ for (i = 1; i < total; i++) { float delta = (float)i / (float)total; float *p = stk->points[start + 1 + i].p; mul_v3_v3fl(p, delta_p, delta); add_v3_v3(p, p_start); } }
static void update_position(Object *ob, MirrorGpencilModifierData *mmd, bGPDstroke *gps, int axis) { int i; bGPDspoint *pt; float factor[3] = {1.0f, 1.0f, 1.0f}; factor[axis] = -1.0f; float clear[3] = {0.0f, 0.0f, 0.0f}; clear[axis] = 1.0f; float ob_origin[3]; float pt_origin[3]; if (mmd->object) { float inv_mat[4][4]; invert_m4_m4(inv_mat, mmd->object->obmat); mul_v3_m4v3(ob_origin, inv_mat, ob->obmat[3]); } else { copy_v3_v3(ob_origin, ob->obmat[3]); } /* only works with current axis */ mul_v3_v3(ob_origin, clear); mul_v3_v3fl(pt_origin, ob_origin, -2.0f); for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { mul_v3_v3(&pt->x, factor); if (mmd->object) { add_v3_v3(&pt->x, pt_origin); } } }
static void paint_2d_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const bool is_torus, const float rgb[4]) { if (is_torus) { x %= ibuf->x; if (x < 0) x += ibuf->x; y %= ibuf->y; if (y < 0) y += ibuf->y; } if (ibuf->rect_float) { float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4; float map_alpha = (rgb[3] == 0.0f) ? rrgbf[3] : rrgbf[3] / rgb[3]; mul_v3_v3fl(rrgbf, rgb, map_alpha); } else { unsigned char straight[4]; unsigned char *rrgb = (unsigned char *)ibuf->rect + (ibuf->x * y + x) * 4; premul_float_to_straight_uchar(straight, rgb); rrgb[0] = straight[0]; rrgb[1] = straight[1]; rrgb[2] = straight[2]; } }
/** * \param r_distance Distance to the hit point */ static bool walk_floor_distance_get( RegionView3D *rv3d, WalkInfo *walk, const float dvec[3], float *r_distance) { float ray_normal[3] = {0, 0, -1}; /* down */ float ray_start[3]; float r_location[3]; float r_normal_dummy[3]; float dvec_tmp[3]; bool ret; *r_distance = BVH_RAYCAST_DIST_MAX; copy_v3_v3(ray_start, rv3d->viewinv[3]); mul_v3_v3fl(dvec_tmp, dvec, walk->grid); add_v3_v3(ray_start, dvec_tmp); ret = ED_transform_snap_object_project_ray( walk->snap_context, ray_start, ray_normal, r_distance, r_location, r_normal_dummy); /* artifically scale the distance to the scene size */ *r_distance /= walk->grid; return ret; }
static void rotate(float new_co[3], float a, float ax[3], float co[3]) { float para[3]; float perp[3]; float cp[3]; float cos_a = cos(a * 2 * M_PI); float sin_a = sin(a * 2 * M_PI); // x' = xcosa + n(n.x)(1-cosa) + (x*n)sina mul_v3_v3fl(perp, co, cos_a); mul_v3_v3fl(para, ax, dot_v3v3(co, ax)*(1 - cos_a)); cross_v3_v3v3(cp, ax, co); mul_v3_fl(cp, sin_a); new_co[0] = para[0] + perp[0] + cp[0]; new_co[1] = para[1] + perp[1] + cp[1]; new_co[2] = para[2] + perp[2] + cp[2]; }
/* project a vector on a plane defined by normal and a plane point p */ void project_v3_plane(float v[3], const float n[3], const float p[3]) { float vector[3]; float mul; sub_v3_v3v3(vector, v, p); mul = dot_v3v3(vector, n) / len_squared_v3(n); mul_v3_v3fl(vector, n, mul); sub_v3_v3(v, vector); }
void ConvertRGBToYCCOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) { float inputColor[4]; float color[3]; this->m_inputOperation->read(inputColor, x, y, sampler); rgb_to_ycc(inputColor[0], inputColor[1], inputColor[2], &color[0], &color[1], &color[2], this->m_mode); /* divided by 255 to normalize for viewing in */ /* R,G,B --> Y,Cb,Cr */ mul_v3_v3fl(output, color, 1.0f / 255.0f); output[3] = inputColor[3]; }
void ConvertStraightToPremulOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) { float inputValue[4]; float alpha; this->m_inputOperation->read(inputValue, x, y, sampler); alpha = inputValue[3]; mul_v3_v3fl(output, inputValue, alpha); /* never touches the alpha */ output[3] = alpha; }
static void do_kink_spiral_deform(ParticleKey *state, const float dir[3], const float kink[3], float time, float freq, float shape, float amplitude, const float spiral_start[3]) { float result[3]; CLAMP(time, 0.f, 1.f); copy_v3_v3(result, state->co); { /* Creates a logarithmic spiral: * r(theta) = a * exp(b * theta) * * The "density" parameter b is defined by the shape parameter * and goes up to the Golden Spiral for 1.0 * https://en.wikipedia.org/wiki/Golden_spiral */ const float b = shape * (1.0f + sqrtf(5.0f)) / (float)M_PI * 0.25f; /* angle of the spiral against the curve (rotated opposite to make a smooth transition) */ const float start_angle = ((b != 0.0f) ? atanf(1.0f / b) : (float)-M_PI_2) + (b > 0.0f ? -(float)M_PI_2 : (float)M_PI_2); float spiral_axis[3], rot[3][3]; float vec[3]; float theta = freq * time * 2.0f * (float)M_PI; float radius = amplitude * expf(b * theta); /* a bit more intuitive than using negative frequency for this */ if (amplitude < 0.0f) theta = -theta; cross_v3_v3v3(spiral_axis, dir, kink); normalize_v3(spiral_axis); mul_v3_v3fl(vec, kink, -radius); axis_angle_normalized_to_mat3(rot, spiral_axis, theta); mul_m3_v3(rot, vec); madd_v3_v3fl(vec, kink, amplitude); axis_angle_normalized_to_mat3(rot, spiral_axis, -start_angle); mul_m3_v3(rot, vec); add_v3_v3v3(result, spiral_start, vec); } copy_v3_v3(state->co, result); }
/** * This function returns the coordinate and normal of a barycentric u,v for a face defined by the primitive_id index. * The returned coordinate is extruded along the normal by cage_extrusion */ static void calc_point_from_barycentric_extrusion( TriTessFace *triangles, float mat[4][4], float imat[4][4], int primitive_id, float u, float v, float cage_extrusion, float r_co[3], float r_dir[3], const bool is_cage) { float data[3][3]; float coord[3]; float dir[3]; float cage[3]; bool is_smooth; TriTessFace *triangle = &triangles[primitive_id]; is_smooth = triangle->is_smooth || is_cage; copy_v3_v3(data[0], triangle->mverts[0]->co); copy_v3_v3(data[1], triangle->mverts[1]->co); copy_v3_v3(data[2], triangle->mverts[2]->co); interp_barycentric_tri_v3(data, u, v, coord); if (is_smooth) { normal_short_to_float_v3(data[0], triangle->mverts[0]->no); normal_short_to_float_v3(data[1], triangle->mverts[1]->no); normal_short_to_float_v3(data[2], triangle->mverts[2]->no); interp_barycentric_tri_v3(data, u, v, dir); normalize_v3(dir); } else { copy_v3_v3(dir, triangle->normal); } mul_v3_v3fl(cage, dir, cage_extrusion); add_v3_v3(coord, cage); normalize_v3(dir); negate_v3(dir); /* convert from local to world space */ mul_m4_v3(mat, coord); mul_transposed_mat3_m4_v3(imat, dir); normalize_v3(dir); copy_v3_v3(r_co, coord); copy_v3_v3(r_dir, dir); }
void ScreenLensDistortionOperation::updateVariables(float distortion, float dispersion) { m_k[1] = max_ff(min_ff(distortion, 1.0f), -0.999f); // smaller dispersion range for somewhat more control float d = 0.25f * max_ff(min_ff(dispersion, 1.0f), 0.0f); m_k[0] = max_ff(min_ff((m_k[1] + d), 1.0f), -0.999f); m_k[2] = max_ff(min_ff((m_k[1] - d), 1.0f), -0.999f); m_maxk = max_fff(m_k[0], m_k[1], m_k[2]); m_sc = (m_fit && (m_maxk > 0.0f)) ? (1.0f / (1.0f + 2.0f * m_maxk)) : (1.0f / (1.0f + m_maxk)); m_dk4[0] = 4.0f * (m_k[1] - m_k[0]); m_dk4[1] = 4.0f * (m_k[2] - m_k[1]); m_dk4[2] = 0.0f; /* unused */ mul_v3_v3fl(m_k4, m_k, 4.0f); }
MINLINE float normalize_v3_v3(float r[3], const float a[3]) { float d = dot_v3v3(a, a); /* a larger value causes normalize errors in a * scaled down models with camera extreme close */ if (d > 1.0e-35f) { d = sqrtf(d); mul_v3_v3fl(r, a, 1.0f / d); } else { zero_v3(r); d = 0.0f; } return d; }
static int pointdensity_color(PointDensity *pd, TexResult *texres, float age, const float vec[3]) { int retval = 0; float col[4]; retval |= TEX_RGB; switch (pd->color_source) { case TEX_PD_COLOR_PARTAGE: if (pd->coba) { if (do_colorband(pd->coba, age, col)) { texres->talpha = true; copy_v3_v3(&texres->tr, col); texres->tin *= col[3]; texres->ta = texres->tin; } } break; case TEX_PD_COLOR_PARTSPEED: { float speed = len_v3(vec) * pd->speed_scale; if (pd->coba) { if (do_colorband(pd->coba, speed, col)) { texres->talpha = true; copy_v3_v3(&texres->tr, col); texres->tin *= col[3]; texres->ta = texres->tin; } } break; } case TEX_PD_COLOR_PARTVEL: texres->talpha = true; mul_v3_v3fl(&texres->tr, vec, pd->speed_scale); texres->ta = texres->tin; break; case TEX_PD_COLOR_CONSTANT: default: texres->tr = texres->tg = texres->tb = texres->ta = 1.0f; break; } return retval; }
void ConvertPremulToStraightOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) { float inputValue[4]; float alpha; this->m_inputOperation->read(inputValue, x, y, sampler); alpha = inputValue[3]; if (fabsf(alpha) < 1e-5f) { zero_v3(output); } else { mul_v3_v3fl(output, inputValue, 1.0f / alpha); } /* never touches the alpha */ output[3] = alpha; }
static void track_colors(MovieTrackingTrack *track, int act, float col[3], float scol[3]) { if (track->flag & TRACK_CUSTOMCOLOR) { if (act) UI_GetThemeColor3fv(TH_ACT_MARKER, scol); else copy_v3_v3(scol, track->color); mul_v3_v3fl(col, track->color, 0.5f); } else { UI_GetThemeColor3fv(TH_MARKER, col); if (act) UI_GetThemeColor3fv(TH_ACT_MARKER, scol); else UI_GetThemeColor3fv(TH_SEL_MARKER, scol); } }
float do_clump(ParticleKey *state, const float par_co[3], float time, const float orco_offset[3], float clumpfac, float clumppow, float pa_clump, bool use_clump_noise, float clump_noise_size, CurveMapping *clumpcurve) { float clump; if (use_clump_noise && clump_noise_size != 0.0f) { float center[3], noisevec[3]; float da[4], pa[12]; mul_v3_v3fl(noisevec, orco_offset, 1.0f / clump_noise_size); voronoi(noisevec[0], noisevec[1], noisevec[2], da, pa, 1.0f, 0); mul_v3_fl(&pa[0], clump_noise_size); add_v3_v3v3(center, par_co, &pa[0]); do_clump_level(state->co, state->co, center, time, clumpfac, clumppow, pa_clump, clumpcurve); } clump = do_clump_level(state->co, state->co, par_co, time, clumpfac, clumppow, pa_clump, clumpcurve); return clump; }
/** * \param r_distance: Distance to the hit point */ static bool walk_floor_distance_get(RegionView3D *rv3d, WalkInfo *walk, const float dvec[3], float *r_distance) { float ray_normal[3] = {0, 0, -1}; /* down */ float ray_start[3]; float r_location[3]; float r_normal_dummy[3]; float dvec_tmp[3]; bool ret; *r_distance = BVH_RAYCAST_DIST_MAX; copy_v3_v3(ray_start, rv3d->viewinv[3]); mul_v3_v3fl(dvec_tmp, dvec, walk->grid); add_v3_v3(ray_start, dvec_tmp); ret = ED_transform_snap_object_project_ray(walk->snap_context, &(const struct SnapObjectParams){ .snap_select = SNAP_ALL, },
static void cloth_continuum_fill_grid(HairGrid *grid, Cloth *cloth) { #if 0 Implicit_Data *data = cloth->implicit; int mvert_num = cloth->mvert_num; ClothVertex *vert; int i; for (i = 0, vert = cloth->verts; i < mvert_num; i++, vert++) { float x[3], v[3]; cloth_get_vertex_motion_state(data, vert, x, v); BPH_hair_volume_add_vertex(grid, x, v); } #else LinkNode *link; float cellsize, gmin[3], cell_scale, cell_offset[3]; /* scale and offset for transforming vertex locations into grid space * (cell size is 0..1, gmin becomes origin) */ BPH_hair_volume_grid_geometry(grid, &cellsize, NULL, gmin, NULL); cell_scale = cellsize > 0.0f ? 1.0f / cellsize : 0.0f; mul_v3_v3fl(cell_offset, gmin, cell_scale); negate_v3(cell_offset); link = cloth->springs; while (link) { ClothSpring *spring = (ClothSpring *)link->link; if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL) link = cloth_continuum_add_hair_segments(grid, cell_scale, cell_offset, cloth, link); else link = link->next; } #endif BPH_hair_volume_normalize_vertex_grid(grid); }
/* update rectangular section of the brush image */ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf, int origx, int origy, int w, int h, int xt, int yt) { Scene *scene = painter->scene; Brush *brush = painter->brush; rctf tex_mapping = painter->tex_mapping; rctf mask_mapping = painter->mask_mapping; struct ImagePool *pool = painter->pool; bool use_masking = painter->cache.use_masking; bool use_color_correction = painter->cache.use_color_correction; bool use_float = painter->cache.use_float; bool is_texbrush = painter->cache.is_texbrush; bool is_maskbrush = painter->cache.is_maskbrush; bool use_texture_old = (oldtexibuf != NULL); int x, y, thread = 0; float brush_rgb[3]; ImBuf *ibuf = painter->cache.ibuf; ImBuf *texibuf = painter->cache.texibuf; unsigned short *mask = painter->cache.mask; /* get brush color */ if (brush->imagepaint_tool == PAINT_TOOL_DRAW) { copy_v3_v3(brush_rgb, brush->rgb); if (use_color_correction) srgb_to_linearrgb_v3_v3(brush_rgb, brush_rgb); } else { brush_rgb[0] = 1.0f; brush_rgb[1] = 1.0f; brush_rgb[2] = 1.0f; } /* fill pixes */ for (y = origy; y < h; y++) { for (x = origx; x < w; x++) { /* sample texture and multiply with brush color */ float texco[3], rgba[4]; if (!use_texture_old) { if (is_texbrush) { brush_imbuf_tex_co(&tex_mapping, x, y, texco); BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, pool); /* TODO(sergey): Support texture paint color space. */ if (!use_float) { linearrgb_to_srgb_v3_v3(rgba, rgba); } mul_v3_v3(rgba, brush_rgb); } else { copy_v3_v3(rgba, brush_rgb); rgba[3] = 1.0f; } if (is_maskbrush) { brush_imbuf_tex_co(&mask_mapping, x, y, texco); rgba[3] *= BKE_brush_sample_masktex(scene, brush, texco, thread, pool); } } if (use_float) { /* handle float pixel */ float *bf = ibuf->rect_float + (y * ibuf->x + x) * 4; float *tf = texibuf->rect_float + (y * texibuf->x + x) * 4; /* read from old texture buffer */ if (use_texture_old) { float *otf = oldtexibuf->rect_float + ((y - origy + yt) * oldtexibuf->x + (x - origx + xt)) * 4; copy_v4_v4(rgba, otf); } /* write to new texture buffer */ copy_v4_v4(tf, rgba); /* if not using masking, multiply in the mask now */ if (!use_masking) { unsigned short *m = mask + (y * ibuf->x + x); rgba[3] *= *m * (1.0f / 65535.0f); } /* output premultiplied float image, mf was already premultiplied */ mul_v3_v3fl(bf, rgba, rgba[3]); bf[3] = rgba[3]; } else { unsigned char crgba[4]; /* handle byte pixel */ unsigned char *b = (unsigned char *)ibuf->rect + (y * ibuf->x + x) * 4; unsigned char *t = (unsigned char *)texibuf->rect + (y * texibuf->x + x) * 4; /* read from old texture buffer */ if (use_texture_old) { unsigned char *ot = (unsigned char *)oldtexibuf->rect + ((y - origy + yt) * oldtexibuf->x + (x - origx + xt)) * 4; crgba[0] = ot[0]; crgba[1] = ot[1]; crgba[2] = ot[2]; crgba[3] = ot[3]; } else rgba_float_to_uchar(crgba, rgba); /* write to new texture buffer */ t[0] = crgba[0]; t[1] = crgba[1]; t[2] = crgba[2]; t[3] = crgba[3]; /* if not using masking, multiply in the mask now */ if (!use_masking) { unsigned short *m = mask + (y * ibuf->x + x); crgba[3] = (crgba[3] * (*m)) / 65535; } /* write to brush image buffer */ b[0] = crgba[0]; b[1] = crgba[1]; b[2] = crgba[2]; b[3] = crgba[3]; } } } }
/* create imbuf with brush color */ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size) { Scene *scene = painter->scene; Brush *brush = painter->brush; rctf tex_mapping = painter->tex_mapping; rctf mask_mapping = painter->mask_mapping; struct ImagePool *pool = painter->pool; bool use_masking = painter->cache.use_masking; bool use_color_correction = painter->cache.use_color_correction; bool use_float = painter->cache.use_float; bool is_texbrush = painter->cache.is_texbrush; bool is_maskbrush = painter->cache.is_maskbrush; float alpha = (use_masking) ? 1.0f : BKE_brush_alpha_get(scene, brush); int radius = BKE_brush_size_get(scene, brush); int xoff = -size * 0.5f + 0.5f; int yoff = -size * 0.5f + 0.5f; int x, y, thread = 0; float brush_rgb[3]; /* allocate image buffer */ ImBuf *ibuf = IMB_allocImBuf(size, size, 32, (use_float) ? IB_rectfloat : IB_rect); /* get brush color */ if (brush->imagepaint_tool == PAINT_TOOL_DRAW) { copy_v3_v3(brush_rgb, brush->rgb); if (use_color_correction) srgb_to_linearrgb_v3_v3(brush_rgb, brush_rgb); } else { brush_rgb[0] = 1.0f; brush_rgb[1] = 1.0f; brush_rgb[2] = 1.0f; } /* fill image buffer */ for (y = 0; y < size; y++) { for (x = 0; x < size; x++) { /* sample texture and multiply with brush color */ float texco[3], rgba[4]; if (is_texbrush) { brush_imbuf_tex_co(&tex_mapping, x, y, texco); BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, pool); /* TODO(sergey): Support texture paint color space. */ if (!use_float) { linearrgb_to_srgb_v3_v3(rgba, rgba); } mul_v3_v3(rgba, brush_rgb); } else { copy_v3_v3(rgba, brush_rgb); rgba[3] = 1.0f; } if (is_maskbrush) { brush_imbuf_tex_co(&mask_mapping, x, y, texco); rgba[3] *= BKE_brush_sample_masktex(scene, brush, texco, thread, pool); } /* when not using masking, multiply in falloff and strength */ if (!use_masking) { float xy[2] = {x + xoff, y + yoff}; float len = len_v2(xy); rgba[3] *= alpha * BKE_brush_curve_strength_clamp(brush, len, radius); } if (use_float) { /* write to float pixel */ float *dstf = ibuf->rect_float + (y * size + x) * 4; mul_v3_v3fl(dstf, rgba, rgba[3]); /* premultiply */ dstf[3] = rgba[3]; } else { /* write to byte pixel */ unsigned char *dst = (unsigned char *)ibuf->rect + (y * size + x) * 4; rgb_float_to_uchar(dst, rgba); dst[3] = FTOCHAR(rgba[3]); } } } return ibuf; }
/* old collision stuff for cloth, use for continuity * until a good replacement is ready */ static void cloth_collision_solve_extra(Object *ob, ClothModifierData *clmd, ListBase *effectors, float frame, float step, float dt) { Cloth *cloth = clmd->clothObject; Implicit_Data *id = cloth->implicit; ClothVertex *verts = cloth->verts; int mvert_num = cloth->mvert_num; const float spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale; bool do_extra_solve; int i; if (!(clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED)) return; if (!clmd->clothObject->bvhtree) return; // update verts to current positions for (i = 0; i < mvert_num; i++) { BPH_mass_spring_get_new_position(id, i, verts[i].tx); sub_v3_v3v3(verts[i].tv, verts[i].tx, verts[i].txold); copy_v3_v3(verts[i].v, verts[i].tv); } #if 0 /* unused */ for (i=0, cv=cloth->verts; i<cloth->mvert_num; i++, cv++) { copy_v3_v3(initial_cos[i], cv->tx); } #endif // call collision function // TODO: check if "step" or "step+dt" is correct - dg do_extra_solve = cloth_bvh_objcollision(ob, clmd, step / clmd->sim_parms->timescale, dt / clmd->sim_parms->timescale); // copy corrected positions back to simulation for (i = 0; i < mvert_num; i++) { float curx[3]; BPH_mass_spring_get_position(id, i, curx); // correct velocity again, just to be sure we had to change it due to adaptive collisions sub_v3_v3v3(verts[i].tv, verts[i].tx, curx); } if (do_extra_solve) { // cloth_calc_helper_forces(ob, clmd, initial_cos, step/clmd->sim_parms->timescale, dt/clmd->sim_parms->timescale); for (i = 0; i < mvert_num; i++) { float newv[3]; if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) && (verts [i].flags & CLOTH_VERT_FLAG_PINNED)) continue; BPH_mass_spring_set_new_position(id, i, verts[i].tx); mul_v3_v3fl(newv, verts[i].tv, spf); BPH_mass_spring_set_new_velocity(id, i, newv); } } // X = Xnew; BPH_mass_spring_apply_result(id); if (do_extra_solve) { ImplicitSolverResult result; /* initialize forces to zero */ BPH_mass_spring_clear_forces(id); // calculate forces cloth_calc_force(clmd, frame, effectors, step); // calculate new velocity and position BPH_mass_spring_solve_velocities(id, dt, &result); // cloth_record_result(clmd, &result, clmd->sim_parms->stepsPerFrame); /* note: positions are advanced only once in the main solver step! */ BPH_mass_spring_apply_result(id); } }
static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListBase *effectors, float time) { /* Collect forces and derivatives: F, dFdX, dFdV */ Cloth *cloth = clmd->clothObject; Implicit_Data *data = cloth->implicit; unsigned int i = 0; float drag = clmd->sim_parms->Cvi * 0.01f; /* viscosity of air scaled in percent */ float gravity[3] = {0.0f, 0.0f, 0.0f}; const MVertTri *tri = cloth->tri; unsigned int mvert_num = cloth->mvert_num; ClothVertex *vert; #ifdef CLOTH_FORCE_GRAVITY /* global acceleration (gravitation) */ if (clmd->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { /* scale gravity force */ mul_v3_v3fl(gravity, clmd->scene->physics_settings.gravity, 0.001f * clmd->sim_parms->effector_weights->global_gravity); } vert = cloth->verts; for (i = 0; i < cloth->mvert_num; i++, vert++) { BPH_mass_spring_force_gravity(data, i, vert->mass, gravity); } #endif /* cloth_calc_volume_force(clmd); */ #ifdef CLOTH_FORCE_DRAG BPH_mass_spring_force_drag(data, drag); #endif /* handle external forces like wind */ if (effectors) { /* cache per-vertex forces to avoid redundant calculation */ float (*winvec)[3] = (float (*)[3])MEM_callocN(sizeof(float[3]) * mvert_num, "effector forces"); for (i = 0; i < cloth->mvert_num; i++) { float x[3], v[3]; EffectedPoint epoint; BPH_mass_spring_get_motion_state(data, i, x, v); pd_point_from_loc(clmd->scene, x, v, i, &epoint); pdDoEffectors(effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL); } for (i = 0; i < cloth->tri_num; i++) { const MVertTri *vt = &tri[i]; BPH_mass_spring_force_face_wind(data, vt->tri[0], vt->tri[1], vt->tri[2], winvec); } /* Hair has only edges */ if (cloth->tri_num == 0) { #if 0 ClothHairData *hairdata = clmd->hairdata; ClothHairData *hair_ij, *hair_kl; for (LinkNode *link = cloth->springs; link; link = link->next) { ClothSpring *spring = (ClothSpring *)link->link; if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL) { if (hairdata) { hair_ij = &hairdata[spring->ij]; hair_kl = &hairdata[spring->kl]; BPH_mass_spring_force_edge_wind(data, spring->ij, spring->kl, hair_ij->radius, hair_kl->radius, winvec); } else BPH_mass_spring_force_edge_wind(data, spring->ij, spring->kl, 1.0f, 1.0f, winvec); } } #else ClothHairData *hairdata = clmd->hairdata; vert = cloth->verts; for (i = 0; i < cloth->mvert_num; i++, vert++) { if (hairdata) { ClothHairData *hair = &hairdata[i]; BPH_mass_spring_force_vertex_wind(data, i, hair->radius, winvec); } else BPH_mass_spring_force_vertex_wind(data, i, 1.0f, winvec); } } #endif MEM_freeN(winvec); } // calculate spring forces for (LinkNode *link = cloth->springs; link; link = link->next) { ClothSpring *spring = (ClothSpring *)link->link; // only handle active springs if (!(spring->flags & CLOTH_SPRING_FLAG_DEACTIVATE)) cloth_calc_spring_force(clmd, spring, time); } }
static bool collision_response(ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, float dt, float restitution, float r_impulse[3]) { Cloth *cloth = clmd->clothObject; int index = collpair->ap1; bool result = false; float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3]; float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree); float margin_distance = (float)collpair->distance - epsilon2; float mag_v_rel; zero_v3(r_impulse); if (margin_distance > 0.0f) return false; /* XXX tested before already? */ /* only handle static collisions here */ if ( collpair->flag & COLLISION_IN_FUTURE ) return false; /* velocity */ copy_v3_v3(v1, cloth->verts[index].v); collision_get_collider_velocity(v2_old, v2_new, collmd, collpair); /* relative velocity = velocity of the cloth point relative to the collider */ sub_v3_v3v3(v_rel_old, v1, v2_old); sub_v3_v3v3(v_rel_new, v1, v2_new); /* normal component of the relative velocity */ mag_v_rel = dot_v3v3(v_rel_old, collpair->normal); /* only valid when moving toward the collider */ if (mag_v_rel < -ALMOST_ZERO) { float v_nor_old, v_nor_new; float v_tan_old[3], v_tan_new[3]; float bounce, repulse; /* Collision response based on * "Simulating Complex Hair with Robust Collision Handling" (Choe, Choi, Ko, ACM SIGGRAPH 2005) * http://graphics.snu.ac.kr/publications/2005-choe-HairSim/Choe_2005_SCA.pdf */ v_nor_old = mag_v_rel; v_nor_new = dot_v3v3(v_rel_new, collpair->normal); madd_v3_v3v3fl(v_tan_old, v_rel_old, collpair->normal, -v_nor_old); madd_v3_v3v3fl(v_tan_new, v_rel_new, collpair->normal, -v_nor_new); bounce = -v_nor_old * restitution; repulse = -margin_distance / dt; /* base repulsion velocity in normal direction */ /* XXX this clamping factor is quite arbitrary ... * not sure if there is a more scientific approach, but seems to give good results */ CLAMP(repulse, 0.0f, 4.0f * bounce); if (margin_distance < -epsilon2) { mul_v3_v3fl(r_impulse, collpair->normal, max_ff(repulse, bounce) - v_nor_new); } else { bounce = 0.0f; mul_v3_v3fl(r_impulse, collpair->normal, repulse - v_nor_new); } result = true; } return result; }
static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec) { InstanceRayObject *obj = (InstanceRayObject *)o; float start[3], dir[3], idot_axis[3], dist; int changed = 0, i, res; // TODO - this is disabling self intersection on instances if (isec->orig.ob == obj->ob && obj->ob) { changed = 1; isec->orig.ob = obj->target_ob; } // backup old values copy_v3_v3(start, isec->start); copy_v3_v3(dir, isec->dir); copy_v3_v3(idot_axis, isec->idot_axis); dist = isec->dist; // transform to target coordinates system mul_m4_v3(obj->global2target, isec->start); mul_mat3_m4_v3(obj->global2target, isec->dir); isec->dist *= normalize_v3(isec->dir); // update idot_axis and bv_index for (i = 0; i < 3; i++) { isec->idot_axis[i] = 1.0f / isec->dir[i]; isec->bv_index[2 * i] = isec->idot_axis[i] < 0.0f ? 1 : 0; isec->bv_index[2 * i + 1] = 1 - isec->bv_index[2 * i]; isec->bv_index[2 * i] = i + 3 * isec->bv_index[2 * i]; isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1]; } // raycast res = RE_rayobject_intersect(obj->target, isec); // map dist into original coordinate space if (res == 0) { isec->dist = dist; } else { // note we don't just multiply dist, because of possible // non-uniform scaling in the transform matrix float vec[3]; mul_v3_v3fl(vec, isec->dir, isec->dist); mul_mat3_m4_v3(obj->target2global, vec); isec->dist = len_v3(vec); isec->hit.ob = obj->ob; #ifdef RT_USE_LAST_HIT // TODO support for last hit optimization in instances that can jump // directly to the last hit face. // For now it jumps directly to the last-hit instance root node. isec->last_hit = RE_rayobject_unalignRayAPI((RayObject *) obj); #endif } // restore values copy_v3_v3(isec->start, start); copy_v3_v3(isec->dir, dir); copy_v3_v3(isec->idot_axis, idot_axis); if (changed) isec->orig.ob = obj->ob; // restore bv_index for (i = 0; i < 3; i++) { isec->bv_index[2 * i] = isec->idot_axis[i] < 0.0f ? 1 : 0; isec->bv_index[2 * i + 1] = 1 - isec->bv_index[2 * i]; isec->bv_index[2 * i] = i + 3 * isec->bv_index[2 * i]; isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1]; } return res; }
/* calculates offset for co, based on fractal, sphere or smooth settings */ static void alter_co(BMVert *v, BMEdge *UNUSED(origed), const SubDParams *params, float perc, BMVert *vsta, BMVert *vend) { float tvec[3], fac; float *co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp); int i; copy_v3_v3(co, v->co); if (UNLIKELY(params->use_sphere)) { /* subdivide sphere */ normalize_v3(co); mul_v3_fl(co, params->smooth); } else if (params->use_smooth) { /* we calculate an offset vector vec1[], to be added to *co */ float len, nor[3], nor1[3], nor2[3], val; sub_v3_v3v3(nor, vsta->co, vend->co); len = 0.5f * normalize_v3(nor); copy_v3_v3(nor1, vsta->no); copy_v3_v3(nor2, vend->no); /* cosine angle */ fac = dot_v3v3(nor, nor1); mul_v3_v3fl(tvec, nor1, fac); /* cosine angle */ fac = -dot_v3v3(nor, nor2); madd_v3_v3fl(tvec, nor2, fac); /* falloff for multi subdivide */ val = fabsf(1.0f - 2.0f * fabsf(0.5f - perc)); val = bmesh_subd_falloff_calc(params->smooth_falloff, val); if (params->use_smooth_even) { val *= BM_vert_calc_shell_factor(v); } mul_v3_fl(tvec, params->smooth * val * len); add_v3_v3(co, tvec); } if (params->use_fractal) { const float len = len_v3v3(vsta->co, vend->co); float normal[3], co2[3], base1[3], base2[3]; fac = params->fractal * len; mid_v3_v3v3(normal, vsta->no, vend->no); ortho_basis_v3v3_v3(base1, base2, normal); add_v3_v3v3(co2, v->co, params->fractal_ofs); mul_v3_fl(co2, 10.0f); tvec[0] = fac * (BLI_gTurbulence(1.0, co2[0], co2[1], co2[2], 15, 0, 2) - 0.5f); tvec[1] = fac * (BLI_gTurbulence(1.0, co2[1], co2[0], co2[2], 15, 0, 2) - 0.5f); tvec[2] = fac * (BLI_gTurbulence(1.0, co2[1], co2[2], co2[0], 15, 0, 2) - 0.5f); /* add displacement */ madd_v3_v3fl(co, normal, tvec[0]); madd_v3_v3fl(co, base1, tvec[1] * (1.0f - params->along_normal)); madd_v3_v3fl(co, base2, tvec[2] * (1.0f - params->along_normal)); } /* apply the new difference to the rest of the shape keys, * note that this doesn't take rotations into account, we _could_ support * this by getting the normals and coords for each shape key and * re-calculate the smooth value for each but this is quite involved. * for now its ok to simply apply the difference IMHO - campbell */ sub_v3_v3v3(tvec, v->co, co); if (params->shape_info.totlayer > 1) { /* skip the last layer since its the temp */ i = params->shape_info.totlayer - 1; co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset); while (i--) { BLI_assert(co != BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp)); sub_v3_v3(co += 3, tvec); } } }
/* only valid for perspective cameras */ int 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; 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]); } /* initialize callback data */ data_cb.dist_vals[0]= data_cb.dist_vals[1]= data_cb.dist_vals[2]= data_cb.dist_vals[3]= 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], data_cb.dist_vals[i]); } 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]); 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; } } }