Visualization Library 2.1.0

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
MorphingCallback.cpp
Go to the documentation of this file.
1 /**************************************************************************************/
2 /* */
3 /* Visualization Library */
4 /* http://visualizationlibrary.org */
5 /* */
6 /* Copyright (c) 2005-2020, Michele Bosi */
7 /* All rights reserved. */
8 /* */
9 /* Redistribution and use in source and binary forms, with or without modification, */
10 /* are permitted provided that the following conditions are met: */
11 /* */
12 /* - Redistributions of source code must retain the above copyright notice, this */
13 /* list of conditions and the following disclaimer. */
14 /* */
15 /* - Redistributions in binary form must reproduce the above copyright notice, this */
16 /* list of conditions and the following disclaimer in the documentation and/or */
17 /* other materials provided with the distribution. */
18 /* */
19 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
20 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
21 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
22 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
23 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
24 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
25 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
26 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
27 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
28 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
29 /* */
30 /**************************************************************************************/
31 
34 #include <vlGraphics/GLSL.hpp>
35 
36 using namespace vl;
37 
38 //-----------------------------------------------------------------------------
39 // MorphingCallback
40 //-----------------------------------------------------------------------------
42 {
43  VL_DEBUG_SET_OBJECT_NAME()
44 
45  mGeometry = new Geometry;
46  setAnimation(0,0,0);
49 
50  mAnim_t = 0.0f;
51  mFrame1 = -1;
52  mFrame2 = -1;
53  mLastUpdate = -1;
54 }
55 //-----------------------------------------------------------------------------
57 {
58 }
59 //-----------------------------------------------------------------------------
60 void MorphingCallback::onActorRenderStarted(Actor*, real frame_clock, const Camera*, Renderable*, const Shader* shader, int pass)
61 {
62  // perform only on the first pass
63  if ( pass > 0 )
64  return;
65 
66  if ( ! mAnimationStarted )
67  return;
68 
69  mElapsedTime = frame_clock - mAnimationStartTime;
70  // 30 fps update using the CPU vertex blending or continuous update if using the GPU
71  bool do_update = mLastUpdate == -1 || (mElapsedTime - mLastUpdate) > 1.0f/30.0f || glslVertexBlendEnabled();
72  if ( do_update )
73  {
75  real ft = mElapsedTime / mAnimationPeriod;
76  ft = ft - (int)ft;
77  int frame_count = mAnimationEnd - mAnimationStart + 1;
78  mAnim_t = (float)(ft * frame_count - (int)(ft * frame_count));
79  mFrame1 = (int)(ft * frame_count);
80  mFrame2 = (mFrame1 + 1) % frame_count;
83  VL_CHECK(mFrame1 >= 0)
85  }
86 
87  VL_CHECK(mFrame1 != -1)
88  VL_CHECK(mLastUpdate != -1)
89 
90  if (mLastUpdate == -1 || mFrame1 == -1)
91  return;
92 
93  const GLSLProgram* glslprogram = shader->glslProgram();
94 
95  // from here you can change uniforms or query uniform binding location
96 
97  if ( glslVertexBlendEnabled() && glslprogram )
98  {
99  // memo:
100  // Since every character is in a different stage of the animation they all have different vertex/normal/etc. arrays pointers,
101  // thus the lazy-vertex-array setup is forced to call glVertexAttribPointer/glVertexPointer/glBindBuffer continuously.
102  // We may be able to partially solve this by putting all the animations in a single ArrayFloat3 and let the draw_calls
103  // switch the frame by using the base-vertex functionality.
104  // I modified the App_MorphAnimation test so that all the characters share the same animation (thus the same vertex arrays) and don't have
105  // transforms attached to eliminate the cost of glLoadMatrix/glMatrixMode. The resulting frame to frame time resulted only 1.2% reduced.
106 
107  // vertex/normals frame 1
108  mGeometry->setVertexArray( mVertexFrames[mFrame1].get() );
109  mGeometry->setNormalArray( mNormalFrames[mFrame1].get() );
110 
111  if (!mVertexFrames[mFrame1]->bufferObject()->handle() || mVertexFrames[mFrame1]->isBufferObjectDirty())
112  mVertexFrames[mFrame1]->updateBufferObject(BUM_KeepRamBuffer);
113 
114  if (!mVertexFrames[mFrame2]->bufferObject()->handle() || mVertexFrames[mFrame2]->isBufferObjectDirty())
115  mVertexFrames[mFrame2]->updateBufferObject(BUM_KeepRamBuffer);
116 
117  if (!mNormalFrames[mFrame1]->bufferObject()->handle() || mNormalFrames[mFrame1]->isBufferObjectDirty())
118  mNormalFrames[mFrame1]->updateBufferObject(BUM_KeepRamBuffer);
119 
120  if (!mNormalFrames[mFrame2]->bufferObject()->handle() || mNormalFrames[mFrame2]->isBufferObjectDirty())
121  mNormalFrames[mFrame2]->updateBufferObject(BUM_KeepRamBuffer);
122 
123  VL_CHECK( mVertexFrames[mFrame1]->bufferObject()->handle() )
124  VL_CHECK( mVertexFrames[mFrame2]->bufferObject()->handle() )
125  VL_CHECK( mNormalFrames[mFrame1]->bufferObject()->handle() )
126  VL_CHECK( mNormalFrames[mFrame2]->bufferObject()->handle() )
127 
128  #if 1 // faster method:
129 
130  // vertex attrib and uniform animation
131  if (mVertex2_Binding == -1)
132  mVertex2_Binding = glslprogram->getAttribLocation("vl_VertexNextPosition");
133 
134  if (mNormal2_Binding == -1)
135  mNormal2_Binding = glslprogram->getAttribLocation("vl_VertexNextNormal");
136 
137  if (mAnim_t_Binding == -1)
138  mAnim_t_Binding = glslprogram->getUniformLocation("anim_t");
139 
140  // vertex/normals frame 2
141  mGeometry->setVertexAttribArray( mVertex2_Binding, mVertexFrames[mFrame2].get() );
142  mGeometry->setVertexAttribArray( mNormal2_Binding, mNormalFrames[mFrame2].get() );
143  // frame interpolation ratio
144  glUniform1fv(mAnim_t_Binding, 1, &mAnim_t);
145 
146  #else // slower but simpler method:
147 
148  // vertex/normals frame 2
149  mGeometry->setVertexAttribArray( glslprogram->getAttribLocation("vl_VertexNextPosition"), false, false, mVertexFrames[mFrame2].get() );
150  mGeometry->setVertexAttribArray( glslprogram->getAttribLocation("vl_VertexNextNormal"), false, false, mNormalFrames[mFrame2].get() );
151  // frame interpolation ratio
152  glUniform1fv(glslprogram->getUniformLocation("anim_t"), 1, &mAnim_t);
153  #endif
154  }
155  else
156  if ( do_update )
157  {
158  if (mGeometry->vertexArray() == NULL)
159  mGeometry->setVertexArray(mVertices.get());
160 
161  if (mGeometry->normalArray() == NULL)
162  mGeometry->setNormalArray(mNormals.get());
163 
165  }
166 }
167 //-----------------------------------------------------------------------------
169 {
170  actor->actorEventCallbacks()->push_back( this );
171  actor->setLod(0, mGeometry.get());
172 }
173 //-----------------------------------------------------------------------------
175 {
176  if (res_db->count<Geometry>() == 0)
177  return;
178 
179  Geometry* geometry = res_db->get<Geometry>(0);
180  mGeometry->shallowCopyFrom( *geometry );
181  mVertices = new ArrayFloat3;
182  mNormals = new ArrayFloat3;
183 
184  // setup Geometry vertex attributes
185 
186  // copy vertex frames
187 
188  for(unsigned i=0, count=(unsigned)res_db->count<ArrayAbstract>(); i<count; ++i)
189  {
190  ArrayFloat3* buffer = cast<ArrayFloat3>(res_db->get<ArrayAbstract>(i));
191  if (buffer && buffer->objectName() == "vertex_frame")
192  {
193  mVertexFrames.push_back(buffer);
194  }
195  else
196  if (buffer && buffer->objectName() == "normal_frame")
197  {
198  mNormalFrames.push_back(buffer);
199  }
200  }
201 
202  if (mVertexFrames.empty())
203  {
204  Log::error("MorphingCallback::init(): no ArrayFloat3 named 'vertex_frame' found.\n");
205  return;
206  }
207 
208  if (mNormalFrames.empty())
209  {
210  Log::error("MorphingCallback::init(): no ArrayFloat3 named 'normal_frame' found.\n");
211  return;
212  }
213 
214  if (mVertexFrames.size() != mNormalFrames.size())
215  {
216  Log::error("MorphingCallback::init(): vertex frame count differs from normal frame count.\n");
217  return;
218  }
219 
220  // compute AABB using the first frame
221 
222  mGeometry->setVertexArray(mVertexFrames[0].get() );
223  mGeometry->setNormalArray(mNormalFrames[0].get() );
224  mGeometry->computeBounds();
225 
226  mGeometry->setVertexArray(NULL);
227  mGeometry->setNormalArray(NULL);
228 }
229 //-----------------------------------------------------------------------------
230 void MorphingCallback::blendFrames(int a, int b, float t)
231 {
232  // allocate interpolation buffers
233  if (mVertices->size() != mVertexFrames[0]->size() ||
234  mNormals->size() != mNormalFrames[0]->size() )
235  {
236  mVertices->resize( mVertexFrames[0]->size() );
237  mNormals->resize( mNormalFrames[0]->size() );
238  }
239 
240  #if 1
241  float Ha = 1-t;
242  float Hb = t;
243  #else
244  float Ha = 2*t*t*t - 3*t*t + 1;
245  float Hb = -2*t*t*t + 3*t*t;
246  #endif
247 
248  for(size_t i=0; i<mVertices->size(); ++i)
249  {
250  mVertices->at(i) = mVertexFrames[ a ]->at(i)*Ha + mVertexFrames[ b ]->at(i)*Hb;
251  mNormals->at(i) = mNormalFrames[ a ]->at(i)*Ha + mNormalFrames[ b ]->at(i)*Hb;
252  }
253 
254  if (mGeometry->isBufferObjectEnabled() && Has_BufferObject)
255  {
256  mVertices->bufferObject()->setBufferData(BU_DYNAMIC_DRAW, false);
257  mNormals ->bufferObject()->setBufferData(BU_DYNAMIC_DRAW, false);
258  }
259 }
260 //-----------------------------------------------------------------------------
261 void MorphingCallback::setAnimation(int start, int end, float period)
262 {
263  mFrame1 = -1;
264  mFrame2 = -1;
265  mLastUpdate = -1;
266  mElapsedTime = 0;
268  mAnimationStart = start;
269  mAnimationEnd = end;
270  mAnimationPeriod = period;
271  mAnimationStarted = false;
272 }
273 //-----------------------------------------------------------------------------
274 void MorphingCallback::startAnimation(real start_time)
275 {
276  mAnimationStarted = true;
277  mFrame1 = -1;
278  mFrame2 = -1;
279  mLastUpdate = -1;
280  mElapsedTime = 0;
281  mAnimationStartTime = start_time;
282 }
283 //-----------------------------------------------------------------------------
285 {
286  mAnimationStarted = false;
287 }
288 //-----------------------------------------------------------------------------
290 {
291  mVertices = new ArrayFloat3;
292  mNormals = new ArrayFloat3;
293 
294  // copy vertex frames
295 
296  mVertexFrames = morph_cb->mVertexFrames;
297  mNormalFrames = morph_cb->mNormalFrames;
298 
299  #if 0
300  // Geometry sharing method: works only wiht GLSL
301 
302  // we can have a single shared Geometry since our MorphingCallback setups the
303  // appropriate position and normal arrays for every Actor just before the rendering!
304  mGeometry = morph_cb->mGeometry;
305  #else
306  // Geometry copy method
307  mGeometry->shallowCopyFrom( *morph_cb->mGeometry );
308 
309  // compute AABB using the first frame
310 
311  mGeometry->setVertexArray(morph_cb->mVertexFrames[0].get() );
312  mGeometry->setNormalArray(morph_cb->mNormalFrames[0].get() );
313  mGeometry->computeBounds();
314 
315  mGeometry->setVertexArray(NULL);
316  mGeometry->setNormalArray(NULL);
317  #endif
318 
319  setAnimation(0,0,0);
320 }
321 //-----------------------------------------------------------------------------
323 {
324  mVertex2_Binding = -1;
325  mNormal2_Binding = -1;
326  mAnim_t_Binding = -1;
327 }
328 //-----------------------------------------------------------------------------
The ArrayAbstract class defines an abstract interface to conveniently manipulate data stored in a Buf...
Definition: Array.hpp:58
Associates a Renderable object to an Effect and Transform.
Definition: Actor.hpp:130
void setAnimation(int start, int end, float period)
std::vector< ref< ArrayFloat3 > > mNormalFrames
int getUniformLocation(const char *name) const
Returns the binding index of the given uniform.
Definition: GLSL.hpp:405
virtual void onActorRenderStarted(Actor *actor, real frame_clock, const Camera *cam, Renderable *renderable, const Shader *, int pass)
Event generated just before an Actor is rendered but after the render states are ready and setup...
static void error(const String &message)
Use this function to provide information about run-time errors: file not found, out of memory...
Definition: Log.cpp:165
Wraps a GLSL program to which you can bind vertex, fragment and geometry shaders. ...
Definition: GLSL.hpp:233
const Collection< ActorEventCallback > * actorEventCallbacks() const
Returns the list of ActorEventCallback bound to an Actor.
Definition: Actor.hpp:370
Data is specified many times and used many times as the source of drawing and image specification com...
ref< ArrayFloat3 > mNormals
size_t count() const
Don&#39;t use inside loops! Counts the number object of the specified type.
void init(ResourceDatabase *res_db)
Initializes a MorphingCallback from a ResourceDatabase.
The Geometry class is a Renderable that implements a polygonal mesh made of polygons, lines and points.
Definition: Geometry.hpp:66
Visualization Library main namespace.
ref< Geometry > mGeometry
bool Has_BufferObject
Definition: OpenGL.cpp:82
void blendFrames(int a, int b, float t)
void setGLSLVertexBlendEnabled(bool enable)
void get(std::vector< ref< T > > &resources, bool clear_vector=true)
Returns all the objects of the specified type in the given vector.
An abstract class that represents all the objects that can be rendered.
Definition: Renderable.hpp:58
bool glslVertexBlendEnabled() const
std::vector< ref< ArrayFloat3 > > mVertexFrames
int getAttribLocation(const char *name) const
Eqivalento to glGetAttribLocation(handle(), name).
Definition: GLSL.hpp:320
#define NULL
Definition: OpenGLDefs.hpp:81
Manages most of the OpenGL rendering states responsible of the final aspect of the rendered objects...
Definition: Shader.hpp:1830
ref< ArrayFloat3 > mVertices
Keeps the local buffer on RAM and updates the BufferObject only if it is marked as dirty...
const std::string & objectName() const
The name of the object, by default set to the object&#39;s class name.
Definition: Object.hpp:217
void initFrom(MorphingCallback *morph_cb)
The MorphingCallback class implements a simple morphing animation mechanism using the GPU acceleratio...
void setLod(int lod_index, Renderable *renderable)
Sets the Renderable object representing the LOD level specifed by lod_index.
Definition: Actor.hpp:159
void startAnimation(real time=-1)
An array of vl::fvec3.
Definition: Array.hpp:414
Represents a virtual camera defining, among other things, the point of view from which scenes can be ...
Definition: Camera.hpp:49
const GLSLProgram * glslProgram() const
Returns the GLSLProgram associated to a Shader (if any)
Definition: Shader.hpp:2194
void bindActor(Actor *actor)
#define VL_CHECK(expr)
Definition: checks.hpp:73
The ResourceDatabase class contains and manipulates a set of resources.