/* Sync rigid body and object transformations */ void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime) { RigidBodyOb *rbo = ob->rigidbody_object; /* keep original transform for kinematic and passive objects */ if (ELEM(NULL, rbw, rbo) || rbo->flag & RBO_FLAG_KINEMATIC || rbo->type == RBO_TYPE_PASSIVE) return; /* use rigid body transform after cache start frame if objects is not being transformed */ if (BKE_rigidbody_check_sim_running(rbw, ctime) && !(ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ)) { float mat[4][4], size_mat[4][4], size[3]; normalize_qt(rbo->orn); // RB_TODO investigate why quaternion isn't normalized at this point quat_to_mat4(mat, rbo->orn); copy_v3_v3(mat[3], rbo->pos); mat4_to_size(size, ob->obmat); size_to_mat4(size_mat, size); mul_m4_m4m4(mat, mat, size_mat); copy_m4_m4(ob->obmat, mat); } /* otherwise set rigid body transform to current obmat */ else { mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat); } }
void UnitConverter::calculate_scale(Scene &sce) { PointerRNA scene_ptr, unit_settings; PropertyRNA *system_ptr, *scale_ptr; RNA_id_pointer_create(&sce.id, &scene_ptr); unit_settings = RNA_pointer_get(&scene_ptr, "unit_settings"); system_ptr = RNA_struct_find_property(&unit_settings, "system"); scale_ptr = RNA_struct_find_property(&unit_settings, "scale_length"); int type = RNA_property_enum_get(&unit_settings, system_ptr); float bl_scale; switch (type) { case USER_UNIT_NONE: bl_scale = 1.0; // map 1 Blender unit to 1 Meter break; case USER_UNIT_METRIC: bl_scale = RNA_property_float_get(&unit_settings, scale_ptr); break; default : bl_scale = RNA_property_float_get(&unit_settings, scale_ptr); // it looks like the conversion to Imperial is done implicitly. // So nothing to do here. break; } float rescale[3]; rescale[0] = rescale[1] = rescale[2] = getLinearMeter() / bl_scale; size_to_mat4(scale_mat4, rescale); }
/** * Calculate a rescale factor such that the imported scene's scale * is preserved. I.e. 1 meter in the import will also be * 1 meter in the current scene. * XXX : I am not sure if it is correct to map 1 Blender Unit * to 1 Meter for unit type NONE. But it looks reasonable to me. */ void bc_match_scale(std::vector<Object *> *objects_done, Scene &sce, UnitConverter &bc_unit) { Object *ob = NULL; PointerRNA scene_ptr, unit_settings; PropertyRNA *system_ptr, *scale_ptr; RNA_id_pointer_create(&sce.id, &scene_ptr); unit_settings = RNA_pointer_get(&scene_ptr, "unit_settings"); system_ptr = RNA_struct_find_property(&unit_settings, "system"); scale_ptr = RNA_struct_find_property(&unit_settings, "scale_length"); int type = RNA_property_enum_get(&unit_settings, system_ptr); float bl_scale; switch (type) { case USER_UNIT_NONE: bl_scale = 1.0; // map 1 Blender unit to 1 Meter break; case USER_UNIT_METRIC: bl_scale = RNA_property_float_get(&unit_settings, scale_ptr); break; default : bl_scale = RNA_property_float_get(&unit_settings, scale_ptr); // it looks like the conversion to Imperial is done implicitly. // So nothing to do here. break; } float scale_conv = bc_unit.getLinearMeter() / bl_scale; float rescale[3]; rescale[0] = rescale[1] = rescale[2] = scale_conv; float size_mat4[4][4]; float axis_mat4[4][4]; unit_m4(axis_mat4); size_to_mat4(size_mat4, rescale); for (std::vector<Object *>::iterator it = objects_done->begin(); it != objects_done->end(); ++it) { ob = *it; mult_m4_m4m4(ob->obmat, size_mat4, ob->obmat); mult_m4_m4m4(ob->obmat, bc_unit.get_rotation(), ob->obmat); BKE_object_apply_mat4(ob, ob->obmat, 0, 0); } }
/* Get 4x4 transformation matrix which corresponds to * stabilization data and used for easy coordinate * transformation. * * NOTE: The reason it is 4x4 matrix is because it's * used for OpenGL drawing directly. */ void BKE_tracking_stabilization_data_to_mat4(int width, int height, float aspect, float translation[2], float scale, float angle, float mat[4][4]) { float translation_mat[4][4], rotation_mat[4][4], scale_mat[4][4], center_mat[4][4], inv_center_mat[4][4], aspect_mat[4][4], inv_aspect_mat[4][4]; float scale_vector[3] = {scale, scale, scale}; unit_m4(translation_mat); unit_m4(rotation_mat); unit_m4(scale_mat); unit_m4(center_mat); unit_m4(aspect_mat); /* aspect ratio correction matrix */ aspect_mat[0][0] = 1.0f / aspect; invert_m4_m4(inv_aspect_mat, aspect_mat); /* image center as rotation center * * Rotation matrix is constructing in a way rotation happens around image center, * and it's matter of calculating translation in a way, that applying translation * after rotation would make it so rotation happens around median point of tracks * used for translation stabilization. */ center_mat[3][0] = (float)width / 2.0f; center_mat[3][1] = (float)height / 2.0f; invert_m4_m4(inv_center_mat, center_mat); size_to_mat4(scale_mat, scale_vector); /* scale matrix */ add_v2_v2(translation_mat[3], translation); /* translation matrix */ rotate_m4(rotation_mat, 'Z', angle); /* rotation matrix */ /* compose transformation matrix */ mul_serie_m4(mat, translation_mat, center_mat, aspect_mat, rotation_mat, inv_aspect_mat, scale_mat, inv_center_mat, NULL); }
/** * Updates cameras from the ``rv3d`` values, optionally auto-keyframing. */ void ED_view3d_cameracontrol_update( View3DCameraControl *vctrl, /* args for keyframing */ const bool use_autokey, struct bContext *C, const bool do_rotate, const bool do_translate) { /* we are in camera view so apply the view ofs and quat to the view matrix and set the camera to the view */ Scene *scene = vctrl->ctx_scene; View3D *v3d = vctrl->ctx_v3d; RegionView3D *rv3d = vctrl->ctx_rv3d; ID *id_key; /* transform the parent or the camera? */ if (vctrl->root_parent) { Object *ob_update; float view_mat[4][4]; float prev_view_imat[4][4]; float diff_mat[4][4]; float parent_mat[4][4]; invert_m4_m4(prev_view_imat, vctrl->view_mat_prev); ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist); mul_m4_m4m4(diff_mat, view_mat, prev_view_imat); mul_m4_m4m4(parent_mat, diff_mat, vctrl->root_parent->obmat); BKE_object_apply_mat4(vctrl->root_parent, parent_mat, true, false); ob_update = v3d->camera->parent; while (ob_update) { DAG_id_tag_update(&ob_update->id, OB_RECALC_OB); ob_update = ob_update->parent; } copy_m4_m4(vctrl->view_mat_prev, view_mat); id_key = &vctrl->root_parent->id; } else { float view_mat[4][4]; float size_mat[4][4]; float size_back[3]; /* even though we handle the size matrix, this still changes over time */ copy_v3_v3(size_back, v3d->camera->size); ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist); size_to_mat4(size_mat, v3d->camera->size); mul_m4_m4m4(view_mat, view_mat, size_mat); BKE_object_apply_mat4(v3d->camera, view_mat, true, true); copy_v3_v3(v3d->camera->size, size_back); id_key = &v3d->camera->id; } /* record the motion */ if (use_autokey && autokeyframe_cfra_can_key(scene, id_key)) { ListBase dsources = {NULL, NULL}; /* add data-source override for the camera object */ ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL); /* insert keyframes * 1) on the first frame * 2) on each subsequent frame * TODO: need to check in future that frame changed before doing this */ if (do_rotate) { struct KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID); ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); } if (do_translate) { struct KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID); ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); } /* free temp data */ BLI_freelistN(&dsources); } }
/* OB_DUPLIPARTS */ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem *psys) { Scene *scene = ctx->scene; Object *par = ctx->object; bool for_render = ctx->eval_ctx->mode == DAG_EVAL_RENDER; bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW); GroupObject *go; Object *ob = NULL, **oblist = NULL, obcopy, *obcopylist = NULL; DupliObject *dob; ParticleDupliWeight *dw; ParticleSettings *part; ParticleData *pa; ChildParticle *cpa = NULL; ParticleKey state; ParticleCacheKey *cache; float ctime, pa_time, scale = 1.0f; float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size = 0.0; float (*obmat)[4]; int a, b, hair = 0; int totpart, totchild, totgroup = 0 /*, pa_num */; const bool dupli_type_hack = !BKE_scene_use_new_shading_nodes(scene); int no_draw_flag = PARS_UNEXIST; if (psys == NULL) return; part = psys->part; if (part == NULL) return; if (!psys_check_enabled(par, psys)) return; if (!for_render) no_draw_flag |= PARS_NO_DISP; ctime = BKE_scene_frame_get(scene); /* NOTE: in old animsys, used parent object's timeoffset... */ totpart = psys->totpart; totchild = psys->totchild; BLI_srandom((unsigned int)(31415926 + psys->seed)); if ((psys->renderdata || part->draw_as == PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) { ParticleSimulationData sim = {NULL}; sim.scene = scene; sim.ob = par; sim.psys = psys; sim.psmd = psys_get_modifier(par, psys); /* make sure emitter imat is in global coordinates instead of render view coordinates */ invert_m4_m4(par->imat, par->obmat); /* first check for loops (particle system object used as dupli object) */ if (part->ren_as == PART_DRAW_OB) { if (ELEM(part->dup_ob, NULL, par)) return; } else { /*PART_DRAW_GR */ if (part->dup_group == NULL || BLI_listbase_is_empty(&part->dup_group->gobject)) return; if (BLI_findptr(&part->dup_group->gobject, par, offsetof(GroupObject, ob))) { return; } } /* if we have a hair particle system, use the path cache */ if (part->type == PART_HAIR) { if (psys->flag & PSYS_HAIR_DONE) hair = (totchild == 0 || psys->childcache) && psys->pathcache; if (!hair) return; /* we use cache, update totchild according to cached data */ totchild = psys->totchildcache; totpart = psys->totcached; } psys_check_group_weights(part); psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); /* gather list of objects or single object */ if (part->ren_as == PART_DRAW_GR) { if (ctx->do_update) { BKE_group_handle_recalc_and_update(ctx->eval_ctx, scene, par, part->dup_group); } if (part->draw & PART_DRAW_COUNT_GR) { for (dw = part->dupliweights.first; dw; dw = dw->next) totgroup += dw->count; } else { for (go = part->dup_group->gobject.first; go; go = go->next) totgroup++; } /* we also copy the actual objects to restore afterwards, since * BKE_object_where_is_calc_time will change the object which breaks transform */ oblist = MEM_callocN((size_t)totgroup * sizeof(Object *), "dupgroup object list"); obcopylist = MEM_callocN((size_t)totgroup * sizeof(Object), "dupgroup copy list"); if (part->draw & PART_DRAW_COUNT_GR && totgroup) { dw = part->dupliweights.first; for (a = 0; a < totgroup; dw = dw->next) { for (b = 0; b < dw->count; b++, a++) { oblist[a] = dw->ob; obcopylist[a] = *dw->ob; } } } else { go = part->dup_group->gobject.first; for (a = 0; a < totgroup; a++, go = go->next) { oblist[a] = go->ob; obcopylist[a] = *go->ob; } } } else { ob = part->dup_ob; obcopy = *ob; } if (totchild == 0 || part->draw & PART_DRAW_PARENT) a = 0; else a = totpart; for (pa = psys->particles; a < totpart + totchild; a++, pa++) { if (a < totpart) { /* handle parent particle */ if (pa->flag & no_draw_flag) continue; /* pa_num = pa->num; */ /* UNUSED */ pa_time = pa->time; size = pa->size; } else { /* handle child particle */ cpa = &psys->child[a - totpart]; /* pa_num = a; */ /* UNUSED */ pa_time = psys->particles[cpa->parent].time; size = psys_get_child_size(psys, cpa, ctime, NULL); } /* some hair paths might be non-existent so they can't be used for duplication */ if (hair && psys->pathcache && ((a < totpart && psys->pathcache[a]->segments < 0) || (a >= totpart && psys->childcache[a - totpart]->segments < 0))) { continue; } if (part->ren_as == PART_DRAW_GR) { /* prevent divide by zero below [#28336] */ if (totgroup == 0) continue; /* for groups, pick the object based on settings */ if (part->draw & PART_DRAW_RAND_GR) b = BLI_rand() % totgroup; else b = a % totgroup; ob = oblist[b]; obmat = oblist[b]->obmat; } else { obmat = ob->obmat; } if (hair) { /* hair we handle separate and compute transform based on hair keys */ if (a < totpart) { cache = psys->pathcache[a]; psys_get_dupli_path_transform(&sim, pa, NULL, cache, pamat, &scale); } else { cache = psys->childcache[a - totpart]; psys_get_dupli_path_transform(&sim, NULL, cpa, cache, pamat, &scale); } copy_v3_v3(pamat[3], cache->co); pamat[3][3] = 1.0f; } else { /* first key */ state.time = ctime; if (psys_get_particle_state(&sim, a, &state, 0) == 0) { continue; } else { float tquat[4]; normalize_qt_qt(tquat, state.rot); quat_to_mat4(pamat, tquat); copy_v3_v3(pamat[3], state.co); pamat[3][3] = 1.0f; } } if (part->ren_as == PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) { for (go = part->dup_group->gobject.first, b = 0; go; go = go->next, b++) { copy_m4_m4(tmat, oblist[b]->obmat); /* apply particle scale */ mul_mat3_m4_fl(tmat, size * scale); mul_v3_fl(tmat[3], size * scale); /* group dupli offset, should apply after everything else */ if (!is_zero_v3(part->dup_group->dupli_ofs)) sub_v3_v3(tmat[3], part->dup_group->dupli_ofs); /* individual particle transform */ mul_m4_m4m4(mat, pamat, tmat); dob = make_dupli(ctx, go->ob, mat, a, false, false); dob->particle_system = psys; if (use_texcoords) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); } } else { /* to give ipos in object correct offset */ BKE_object_where_is_calc_time(scene, ob, ctime - pa_time); copy_v3_v3(vec, obmat[3]); obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f; /* particle rotation uses x-axis as the aligned axis, so pre-rotate the object accordingly */ if ((part->draw & PART_DRAW_ROTATE_OB) == 0) { float xvec[3], q[4], size_mat[4][4], original_size[3]; mat4_to_size(original_size, obmat); size_to_mat4(size_mat, original_size); xvec[0] = -1.f; xvec[1] = xvec[2] = 0; vec_to_quat(q, xvec, ob->trackflag, ob->upflag); quat_to_mat4(obmat, q); obmat[3][3] = 1.0f; /* add scaling if requested */ if ((part->draw & PART_DRAW_NO_SCALE_OB) == 0) mul_m4_m4m4(obmat, obmat, size_mat); } else if (part->draw & PART_DRAW_NO_SCALE_OB) { /* remove scaling */ float size_mat[4][4], original_size[3]; mat4_to_size(original_size, obmat); size_to_mat4(size_mat, original_size); invert_m4(size_mat); mul_m4_m4m4(obmat, obmat, size_mat); } mul_m4_m4m4(tmat, pamat, obmat); mul_mat3_m4_fl(tmat, size * scale); copy_m4_m4(mat, tmat); if (part->draw & PART_DRAW_GLOBAL_OB) add_v3_v3v3(mat[3], mat[3], vec); dob = make_dupli(ctx, ob, mat, a, false, false); dob->particle_system = psys; if (use_texcoords) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); /* XXX blender internal needs this to be set to dupligroup to render * groups correctly, but we don't want this hack for cycles */ if (dupli_type_hack && ctx->group) dob->type = OB_DUPLIGROUP; } } /* restore objects since they were changed in BKE_object_where_is_calc_time */ if (part->ren_as == PART_DRAW_GR) { for (a = 0; a < totgroup; a++) *(oblist[a]) = obcopylist[a]; } else *ob = obcopy; } /* clean up */ if (oblist) MEM_freeN(oblist); if (obcopylist) MEM_freeN(obcopylist); if (psys->lattice_deform_data) { end_latt_deform(psys->lattice_deform_data); psys->lattice_deform_data = NULL; } }
void TransformReader::dae_scale_to_mat4(COLLADAFW::Transformation *tm, float m[][4]) { COLLADABU::Math::Vector3& s = ((COLLADAFW::Scale*)tm)->getScale(); float size[3] = {(float)s[0], (float)s[1], (float)s[2]}; size_to_mat4(m, size); }
static void flyMoveCamera(bContext *C, RegionView3D *rv3d, FlyInfo *fly, const bool do_rotate, const bool do_translate) { /* we are in camera view so apply the view ofs and quat to the view matrix and set the camera to the view */ View3D *v3d = fly->v3d; Scene *scene = fly->scene; ID *id_key; /* transform the parent or the camera? */ if (fly->root_parent) { Object *ob_update; float view_mat[4][4]; float prev_view_mat[4][4]; float prev_view_imat[4][4]; float diff_mat[4][4]; float parent_mat[4][4]; float size_mat[4][4]; ED_view3d_to_m4(prev_view_mat, fly->rv3d->ofs, fly->rv3d->viewquat, fly->rv3d->dist); invert_m4_m4(prev_view_imat, prev_view_mat); ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist); mult_m4_m4m4(diff_mat, view_mat, prev_view_imat); mult_m4_m4m4(parent_mat, diff_mat, fly->root_parent->obmat); size_to_mat4(size_mat, fly->root_parent->size); mult_m4_m4m4(parent_mat, parent_mat, size_mat); BKE_object_apply_mat4(fly->root_parent, parent_mat, true, false); // BKE_object_where_is_calc(scene, fly->root_parent); ob_update = v3d->camera->parent; while (ob_update) { DAG_id_tag_update(&ob_update->id, OB_RECALC_OB); ob_update = ob_update->parent; } id_key = &fly->root_parent->id; } else { float view_mat[4][4]; float size_mat[4][4]; ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist); size_to_mat4(size_mat, v3d->camera->size); mult_m4_m4m4(view_mat, view_mat, size_mat); BKE_object_apply_mat4(v3d->camera, view_mat, true, false); id_key = &v3d->camera->id; } /* record the motion */ if (autokeyframe_cfra_can_key(scene, id_key)) { ListBase dsources = {NULL, NULL}; /* add datasource override for the camera object */ ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL); /* insert keyframes * 1) on the first frame * 2) on each subsequent frame * TODO: need to check in future that frame changed before doing this */ if (do_rotate) { KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID); ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); } if (do_translate) { KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID); ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); } /* free temp data */ BLI_freelistN(&dsources); } }
CompBuf* node_composit_transform(CompBuf *cbuf, float x, float y, float angle, float scale, int filter_type) { CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); ImBuf *ibuf, *obuf; float mat[4][4], lmat[4][4], rmat[4][4], smat[4][4], cmat[4][4], icmat[4][4]; float svec[3]= {scale, scale, scale}, loc[2]= {x, y}; unit_m4(rmat); unit_m4(lmat); unit_m4(smat); unit_m4(cmat); /* image center as rotation center */ cmat[3][0]= (float)cbuf->x/2.0f; cmat[3][1]= (float)cbuf->y/2.0f; invert_m4_m4(icmat, cmat); size_to_mat4(smat, svec); /* scale matrix */ add_v2_v2(lmat[3], loc); /* tranlation matrix */ rotate_m4(rmat, 'Z', angle); /* rotation matrix */ /* compose transformation matrix */ mul_serie_m4(mat, lmat, cmat, rmat, smat, icmat, NULL, NULL, NULL); invert_m4(mat); ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0); obuf= IMB_allocImBuf(stackbuf->x, stackbuf->y, 32, 0); if (ibuf && obuf) { int i, j; ibuf->rect_float= cbuf->rect; obuf->rect_float= stackbuf->rect; for (j=0; j<cbuf->y; j++) { for (i=0; i<cbuf->x;i++) { float vec[3]= {i, j, 0}; mul_v3_m4v3(vec, mat, vec); switch(filter_type) { case 0: neareast_interpolation(ibuf, obuf, vec[0], vec[1], i, j); break; case 1: bilinear_interpolation(ibuf, obuf, vec[0], vec[1], i, j); break; case 2: bicubic_interpolation(ibuf, obuf, vec[0], vec[1], i, j); break; } } } IMB_freeImBuf(ibuf); IMB_freeImBuf(obuf); } /* pass on output and free */ return stackbuf; }
void init_tex_mapping(TexMapping *texmap) { float smat[4][4], rmat[4][4], tmat[4][4], proj[4][4], size[3]; if (texmap->projx == PROJ_X && texmap->projy == PROJ_Y && texmap->projz == PROJ_Z && is_zero_v3(texmap->loc) && is_zero_v3(texmap->rot) && is_one_v3(texmap->size)) { unit_m4(texmap->mat); texmap->flag |= TEXMAP_UNIT_MATRIX; } else { /* axis projection */ zero_m4(proj); proj[3][3] = 1.0f; if (texmap->projx != PROJ_N) proj[texmap->projx - 1][0] = 1.0f; if (texmap->projy != PROJ_N) proj[texmap->projy - 1][1] = 1.0f; if (texmap->projz != PROJ_N) proj[texmap->projz - 1][2] = 1.0f; /* scale */ copy_v3_v3(size, texmap->size); if (ELEM(texmap->type, TEXMAP_TYPE_TEXTURE, TEXMAP_TYPE_NORMAL)) { /* keep matrix invertible */ if (fabsf(size[0]) < 1e-5f) size[0] = signf(size[0]) * 1e-5f; if (fabsf(size[1]) < 1e-5f) size[1] = signf(size[1]) * 1e-5f; if (fabsf(size[2]) < 1e-5f) size[2] = signf(size[2]) * 1e-5f; } size_to_mat4(smat, texmap->size); /* rotation */ eul_to_mat4(rmat, texmap->rot); /* translation */ unit_m4(tmat); copy_v3_v3(tmat[3], texmap->loc); if (texmap->type == TEXMAP_TYPE_TEXTURE) { /* to transform a texture, the inverse transform needs * to be applied to the texture coordinate */ mul_serie_m4(texmap->mat, tmat, rmat, smat, 0, 0, 0, 0, 0); invert_m4(texmap->mat); } else if (texmap->type == TEXMAP_TYPE_POINT) { /* forward transform */ mul_serie_m4(texmap->mat, tmat, rmat, smat, 0, 0, 0, 0, 0); } else if (texmap->type == TEXMAP_TYPE_VECTOR) { /* no translation for vectors */ mul_m4_m4m4(texmap->mat, rmat, smat); } else if (texmap->type == TEXMAP_TYPE_NORMAL) { /* no translation for normals, and inverse transpose */ mul_m4_m4m4(texmap->mat, rmat, smat); invert_m4(texmap->mat); transpose_m4(texmap->mat); } /* projection last */ mul_m4_m4m4(texmap->mat, texmap->mat, proj); texmap->flag &= ~TEXMAP_UNIT_MATRIX; } }
static void camera_stereo3d_model_matrix(Object *camera, const bool is_left, float r_modelmat[4][4]) { Camera *data = (Camera *)camera->data; float interocular_distance, convergence_distance; short convergence_mode, pivot; float sizemat[4][4]; float fac = 1.0f; float fac_signed; interocular_distance = data->stereo.interocular_distance; convergence_distance = data->stereo.convergence_distance; convergence_mode = data->stereo.convergence_mode; pivot = data->stereo.pivot; if (((pivot == CAM_S3D_PIVOT_LEFT) && is_left) || ((pivot == CAM_S3D_PIVOT_RIGHT) && !is_left)) { camera_model_matrix(camera, r_modelmat); return; } else { float size[3]; mat4_to_size(size, camera->obmat); size_to_mat4(sizemat, size); } if (pivot == CAM_S3D_PIVOT_CENTER) fac = 0.5f; fac_signed = is_left ? fac : -fac; /* rotation */ if (convergence_mode == CAM_S3D_TOE) { float angle; float angle_sin, angle_cos; float toeinmat[4][4]; float rotmat[4][4]; unit_m4(rotmat); if (pivot == CAM_S3D_PIVOT_CENTER) { fac = -fac; fac_signed = -fac_signed; } angle = atanf((interocular_distance * 0.5f) / convergence_distance) / fac; angle_cos = cosf(angle * fac_signed); angle_sin = sinf(angle * fac_signed); rotmat[0][0] = angle_cos; rotmat[2][0] = -angle_sin; rotmat[0][2] = angle_sin; rotmat[2][2] = angle_cos; if (pivot == CAM_S3D_PIVOT_CENTER) { /* set the rotation */ copy_m4_m4(toeinmat, rotmat); /* set the translation */ toeinmat[3][0] = interocular_distance * fac_signed; /* transform */ normalize_m4_m4(r_modelmat, camera->obmat); mul_m4_m4m4(r_modelmat, r_modelmat, toeinmat); /* scale back to the original size */ mul_m4_m4m4(r_modelmat, r_modelmat, sizemat); } else { /* CAM_S3D_PIVOT_LEFT, CAM_S3D_PIVOT_RIGHT */ /* rotate perpendicular to the interocular line */ normalize_m4_m4(r_modelmat, camera->obmat); mul_m4_m4m4(r_modelmat, r_modelmat, rotmat); /* translate along the interocular line */ unit_m4(toeinmat); toeinmat[3][0] = -interocular_distance * fac_signed; mul_m4_m4m4(r_modelmat, r_modelmat, toeinmat); /* rotate to toe-in angle */ mul_m4_m4m4(r_modelmat, r_modelmat, rotmat); /* scale back to the original size */ mul_m4_m4m4(r_modelmat, r_modelmat, sizemat); } } else { normalize_m4_m4(r_modelmat, camera->obmat); /* translate - no rotation in CAM_S3D_OFFAXIS, CAM_S3D_PARALLEL */ translate_m4(r_modelmat, -interocular_distance * fac_signed, 0.0f, 0.0f); /* scale back to the original size */ mul_m4_m4m4(r_modelmat, r_modelmat, sizemat); } }