@@ -36,6 +36,16 @@ void CameraKeyframes::read(Input& input)
3636
3737 input.read (" name" , name);
3838
39+ // read tracking key frames
40+ uint32_t num_tracking = input.readValue <uint32_t >(" tracking" );
41+ tracking.resize (num_tracking);
42+ for (auto & track : tracking)
43+ {
44+ input.matchPropertyName (" track" );
45+ input.read (1 , &track.time );
46+ input.readObjects (" path" , track.value );
47+ }
48+
3949 // read position key frames
4050 uint32_t num_positions = input.readValue <uint32_t >(" positions" );
4151 positions.resize (num_positions);
@@ -83,6 +93,17 @@ void CameraKeyframes::write(Output& output) const
8393
8494 output.write (" name" , name);
8595
96+ // write position key frames
97+ output.writeValue <uint32_t >(" tracking" , tracking.size ());
98+ for (const auto & track : tracking)
99+ {
100+ output.writePropertyName (" track" );
101+ output.write (1 , &track.time );
102+ output.writeEndOfLine ();
103+
104+ output.writeObjects (" path" , track.value );
105+ }
106+
86107 // write position key frames
87108 output.writeValue <uint32_t >(" positions" , positions.size ());
88109 for (const auto & position : positions)
@@ -176,6 +197,55 @@ void CameraSampler::update(double time)
176197 sample (time, keyframes->rotations , rotation);
177198 sample (time, keyframes->fieldOfViews , fieldOfView);
178199 sample (time, keyframes->nearFars , nearFar);
200+
201+ auto find_values = [](const RefObjectPath& path, dvec3& in_origin, dvec3& in_position, dquat& in_rotation) -> void
202+ {
203+ ComputeTransform ct;
204+ for (auto & obj : path) obj->accept (ct);
205+
206+ in_origin = ct.origin ;
207+
208+ dvec3 scale;
209+ vsg::decompose (ct.matrix , in_position, in_rotation, scale);
210+ };
211+
212+ auto & tracking = keyframes->tracking ;
213+ if (tracking.size () == 1 )
214+ {
215+ find_values (tracking.front ().value , origin, position, rotation);
216+ }
217+ else if (!tracking.empty ())
218+ {
219+ auto pos_itr = std::lower_bound (tracking.begin (), tracking.end (), time, [](const time_path& elem, double t) -> bool { return elem.time < t; });
220+ if (pos_itr == tracking.begin ())
221+ {
222+ find_values (tracking.front ().value , origin, position, rotation);
223+ }
224+ else if (pos_itr == tracking.end ())
225+ {
226+ find_values (tracking.back ().value , origin, position, rotation);
227+ }
228+ else
229+ {
230+ auto before_pos_itr = pos_itr - 1 ;
231+ double delta_time = (pos_itr->time - before_pos_itr->time );
232+ double r = delta_time != 0.0 ? (time - before_pos_itr->time ) / delta_time : 0.5 ;
233+
234+ dvec3 origin_before, position_before;
235+ dquat rotation_before;
236+ find_values (before_pos_itr->value , origin_before, position_before, rotation_before);
237+
238+ dvec3 origin_after, position_after;
239+ dquat rotation_after;
240+ find_values (pos_itr->value , origin_after, position_after, rotation_after);
241+
242+ // convert origin input values and ratio to long double to minimize the intermediate rounding errors.
243+ origin = mix (ldvec3 (origin_before), ldvec3 (origin_after), static_cast <long double >(r));
244+
245+ position = mix (position_before, position_after, r);
246+ rotation = mix (rotation_before, rotation_after, r);
247+ }
248+ }
179249 }
180250
181251 if (object) object->accept (*this );
@@ -186,6 +256,7 @@ double CameraSampler::maxTime() const
186256 double maxTime = 0.0 ;
187257 if (keyframes)
188258 {
259+ if (!keyframes->tracking .empty ()) maxTime = std::max (maxTime, keyframes->tracking .back ().time );
189260 if (!keyframes->origins .empty ()) maxTime = std::max (maxTime, keyframes->origins .back ().time );
190261 if (!keyframes->positions .empty ()) maxTime = std::max (maxTime, keyframes->positions .back ().time );
191262 if (!keyframes->rotations .empty ()) maxTime = std::max (maxTime, keyframes->rotations .back ().time );
@@ -210,8 +281,9 @@ void CameraSampler::apply(LookAt& lookAt)
210281{
211282 if (keyframes)
212283 {
213- if (!keyframes->origins .empty ()) lookAt.origin = origin;
214- if (!keyframes->positions .empty () || !keyframes->rotations .empty ())
284+ bool has_tracking = !keyframes->tracking .empty ();
285+ if (!keyframes->origins .empty () || has_tracking) lookAt.origin = origin;
286+ if (!keyframes->positions .empty () || !keyframes->rotations .empty () || has_tracking)
215287 {
216288 lookAt.set (transform ());
217289 }
@@ -222,9 +294,10 @@ void CameraSampler::apply(LookDirection& lookDirection)
222294{
223295 if (keyframes)
224296 {
225- if (!keyframes->origins .empty ()) lookDirection.origin = origin;
226- if (!keyframes->positions .empty ()) lookDirection.position = position;
227- if (!keyframes->rotations .empty ()) lookDirection.rotation = rotation;
297+ bool has_tracking = !keyframes->tracking .empty ();
298+ if (!keyframes->origins .empty () || has_tracking) lookDirection.origin = origin;
299+ if (!keyframes->positions .empty () || has_tracking) lookDirection.position = position;
300+ if (!keyframes->rotations .empty () || has_tracking) lookDirection.rotation = rotation;
228301 }
229302}
230303
0 commit comments