예제 #1
0
void CalSpringSystem::calculateVertices(CalSubmesh *pSubmesh, float deltaTime)
{
  // get the vertex vector of the submesh
  std::vector<CalVector>& vectorVertex = pSubmesh->getVectorVertex();

  // get the physical property vector of the submesh
  std::vector<CalSubmesh::PhysicalProperty>& vectorPhysicalProperty = pSubmesh->getVectorPhysicalProperty();

  // get the physical property vector of the core submesh
  std::vector<CalCoreSubmesh::PhysicalProperty>& vectorCorePhysicalProperty = pSubmesh->getCoreSubmesh()->getVectorPhysicalProperty();

  // loop through all the vertices
  int vertexId;
  for(vertexId = 0; vertexId < (int)vectorVertex.size(); ++vertexId)
  {
    // get the vertex
    CalVector& vertex = vectorVertex[vertexId];

    // get the physical property of the vertex
    CalSubmesh::PhysicalProperty& physicalProperty = vectorPhysicalProperty[vertexId];

    // get the physical property of the core vertex
    CalCoreSubmesh::PhysicalProperty& corePhysicalProperty = vectorCorePhysicalProperty[vertexId];

    // store current position for later use
    CalVector position;
    position = physicalProperty.position;

    // only take vertices with a weight > 0 into account
    if(corePhysicalProperty.weight > 0.0f)
    {
      // do the Verlet step
      physicalProperty.position += (position - physicalProperty.positionOld) * 0.99f + physicalProperty.force / corePhysicalProperty.weight * deltaTime * deltaTime;

		CalSkeleton *pSkeleton = m_pModel->getSkeleton();
		
		if(m_collision)
		{
			std::vector<CalBone *> &m_vectorbone =  pSkeleton->getVectorBone();
			
			unsigned long boneId;
			for(boneId=0; boneId < m_vectorbone.size(); boneId++)
			{
				CalBoundingBox p = m_vectorbone[boneId]->getBoundingBox();
				bool in=true;
				float min=1e10;
				int index=-1;
				
				int faceId;
				for(faceId=0; faceId < 6 ; faceId++)
				{				
					if(p.plane[faceId].eval(physicalProperty.position)<=0)
					{
						in=false;
					}
					else
					{
						float dist=p.plane[faceId].dist(physicalProperty.position);
						if(dist<min)
						{
							index=faceId;
							min=dist;
						}
					}
				}
				
				if(in && index!=-1)
				{
					CalVector normal = CalVector(p.plane[index].a,p.plane[index].b,normal.z = p.plane[index].c);
					normal.normalize();
					physicalProperty.position = physicalProperty.position - min*normal;
				}
				
				in=true;
				
				for(faceId=0; faceId < 6 ; faceId++)
				{				
					if(p.plane[faceId].eval(physicalProperty.position) < 0 )
					{
						in=false;				
					}
				}
				if(in)
				{
					physicalProperty.position = vectorVertex[vertexId];
				}
			}
		}

    }
    else
    {
      physicalProperty.position = vectorVertex[vertexId];
    }

    // make the current position the old one
    physicalProperty.positionOld = position;

    // set the new position of the vertex
    vertex = physicalProperty.position;

    // clear the accumulated force on the vertex
    physicalProperty.force.clear();
  }

  // get the spring vector of the core submesh
  std::vector<CalCoreSubmesh::Spring>& vectorSpring = pSubmesh->getCoreSubmesh()->getVectorSpring();

  // iterate a few times to relax the constraints
  int iterationCount;
#define ITERATION_COUNT 2
  for(iterationCount = 0; iterationCount < ITERATION_COUNT; ++iterationCount)
  {
    // loop through all the springs
    std::vector<CalCoreSubmesh::Spring>::iterator iteratorSpring;
    for(iteratorSpring = vectorSpring.begin(); iteratorSpring != vectorSpring.end(); ++iteratorSpring)
    {
      // get the spring
      CalCoreSubmesh::Spring& spring = *iteratorSpring;

      // compute the difference between the two spring vertices
      CalVector distance;
      distance = vectorVertex[spring.vertexId[1]] - vectorVertex[spring.vertexId[0]];

      // get the current length of the spring
      float length;
      length = distance.length();

      if(length > 0.0f)
      {
      	/*if (spring.springCoefficient == 0)
      	{ 
      	 	vectorVertex[spring.vertexId[1]] = vectorVertex[spring.vertexId[0]];  
      	 	vectorPhysicalProperty[spring.vertexId[1]].position = vectorVertex[spring.vertexId[0]]; 
      	} 
      	else
	{*/
	   float factor[2];
	   factor[0] = (length - spring.idleLength) / length;
	   factor[1] = factor[0];
	   
	   if(vectorCorePhysicalProperty[spring.vertexId[0]].weight > 0.0f)
	   {
              factor[0] /= 2.0f;
              factor[1] /= 2.0f;
           }
           else
           {
             factor[0] = 0.0f;
           }
           
           if(vectorCorePhysicalProperty[spring.vertexId[1]].weight <= 0.0f)
           {
              factor[0] *= 2.0f;
              factor[1] = 0.0f;
           }

           vectorVertex[spring.vertexId[0]] += distance * factor[0];
           vectorPhysicalProperty[spring.vertexId[0]].position = vectorVertex[spring.vertexId[0]];

           vectorVertex[spring.vertexId[1]] -= distance * factor[1];
           vectorPhysicalProperty[spring.vertexId[1]].position = vectorVertex[spring.vertexId[1]];
        //}
      }
    }
  }
/* DEBUG-CODE ********************
  CalVector spherePosition(Sphere.x, Sphere.y, Sphere.z);
  float sphereRadius = Sphere.radius;

  // loop through all the vertices
  for(vertexId = 0; vertexId < (int)vectorVertex.size(); ++vertexId)
  {
    // get the vertex
    CalVector& vertex = vectorVertex[vertexId];

    // get the physical property of the vertex
    CalSubmesh::PhysicalProperty& physicalProperty = vectorPhysicalProperty[vertexId];

    // get the physical property of the core vertex
    CalCoreSubmesh::PhysicalProperty& corePhysicalProperty = vectorCorePhysicalProperty[vertexId];

    // only take vertices with a weight > 0 into account
    if(corePhysicalProperty.weight > 0.0f)
    {
      CalVector position;
      position = physicalProperty.position;
      position -= spherePosition;

      float length;
      length = position.normalize();

      if(length < sphereRadius)
      {
        position *= sphereRadius;
        position += spherePosition;

        physicalProperty.position = position;
        physicalProperty.positionOld = position;
        vertex = physicalProperty.position;
      }
    }
  }
*********************************/
}
예제 #2
0
static
void
generateTangentAndHandednessBuffer( osgCal::MeshData* m,
                                    const CalIndex*   indexBuffer )
{
    if ( !m->texCoordBuffer.valid() )
    {
        return;
    }

    int vertexCount = m->vertexBuffer->size();
    int faceCount   = m->getIndicesCount() / 3;    

    m->tangentAndHandednessBuffer = new TangentAndHandednessBuffer( vertexCount );

    CalVector* tan1 = new CalVector[vertexCount];
    CalVector* tan2 = new CalVector[vertexCount];

    const GLfloat* texCoordBufferData = (GLfloat*) m->texCoordBuffer->getDataPointer();

    const GLfloat* vb = (GLfloat*) m->vertexBuffer->getDataPointer();
#ifdef OSG_CAL_BYTE_BUFFERS
    GLfloat* thb = new GLfloat[ vertexCount*4 ];
    const GLfloat* nb = floatNormalBuffer;
#else
    GLfloat* thb = (GLfloat*) m->tangentAndHandednessBuffer->getDataPointer();
//    GLshort* thb = (GLshort*) m->tangentAndHandednessBuffer->getDataPointer();
    const GLfloat* nb = (GLfloat*) m->normalBuffer->getDataPointer();
#endif

    for ( int face = 0; face < faceCount; face++ )
    {
        for ( int j = 0; j < 3; j++ )
        {
            // there seems to be no visual difference in calculating
            // tangent per vertex (as is tan1[i1] += spos(j=0,1,2))
            // or per face (tan1[i1,i2,i3] += spos)
            CalIndex i1 = indexBuffer[face*3+(j+0)%3];
            CalIndex i2 = indexBuffer[face*3+(j+1)%3];
            CalIndex i3 = indexBuffer[face*3+(j+2)%3];
        
            const float* v1 = &vb[i1*3];
            const float* v2 = &vb[i2*3];
            const float* v3 = &vb[i3*3];

            const float* w1 = &texCoordBufferData[i1*2];
            const float* w2 = &texCoordBufferData[i2*2];
            const float* w3 = &texCoordBufferData[i3*2];

#define x(_a) (_a[0])
#define y(_a) (_a[1])
#define z(_a) (_a[2])
        
            float x1 = x(v2) - x(v1);
            float x2 = x(v3) - x(v1);
            float y1 = y(v2) - y(v1);
            float y2 = y(v3) - y(v1);
            float z1 = z(v2) - z(v1);
            float z2 = z(v3) - z(v1);
        
            float s1 = x(w2) - x(w1);
            float s2 = x(w3) - x(w1);
            float t1 = y(w2) - y(w1);
            float t2 = y(w3) - y(w1);

#undef x
#undef y
#undef z
        
            //float r = 1.0F / (s1 * t2 - s2 * t1);
            float r = (s1 * t2 - s2 * t1) < 0 ? -1.0 : 1.0;
            CalVector sdir((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
                           (t2 * z1 - t1 * z2) * r);
            CalVector tdir((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
                           (s1 * z2 - s2 * z1) * r);

            // sdir & tdir can be 0 (when UV unwrap doesn't exists
            // or has errors like coincide points)
            // we ignore them
            if ( sdir.length() > 0 )
            {
                sdir.normalize(); 

                tan1[i1] += sdir;
                //tan1[i2] += sdir;
                //tan1[i3] += sdir;
            }

            if ( tdir.length() > 0 )
            {
                tdir.normalize();

                tan2[i1] += tdir;
                //tan2[i2] += tdir;
                //tan2[i3] += tdir;
            }
        }
    }
    
    for (long a = 0; a < vertexCount; a++)
    {
        CalVector tangent;
        CalVector binormal;
        CalVector t = tan1[a];
        CalVector b = tan2[a];
        CalVector n = CalVector( nb[a*3+0],
                                 nb[a*3+1],
                                 nb[a*3+2] );

        // tangent & bitangent can be zero when UV unwrap doesn't exists
        // or has errors like coincide points
        if ( t.length() > 0 )
        {
            t.normalize();
        
            // Gram-Schmidt orthogonalize
            tangent = t - n * (n*t);
            tangent.normalize();

            // Calculate handedness
            binormal = CalVector(n % tangent) *
                ((((n % t) * b) < 0.0F) ? -1.0f : 1.0f);
            binormal.normalize();
        }
        else if ( b.length() > 0 )
        {
            b.normalize();
        
            // Gram-Schmidt orthogonalize
            binormal = b - n * (n*b);
            binormal.normalize();

            // Calculate handedness
            tangent = CalVector(n % binormal) *
                ((((n % b) * t) < 0.0F) ? -1.0f : 1.0f);
            tangent.normalize();
        }

//         std::cout << "t = " << tangent.x  << '\t' << tangent.y  << '\t' << tangent.z  << '\n';
//         std::cout << "b = " << binormal.x << '\t' << binormal.y << '\t' << binormal.z << '\n';
//            std::cout << "n = " << n.x        << '\t' << n.y        << '\t' << n.z        << '\n';

//         thb[a*4+0] = floatToHalf( tangent.x ); //tangent.x * 0x7FFF;
//         thb[a*4+1] = floatToHalf( tangent.y ); //tangent.y * 0x7FFF;
//         thb[a*4+2] = floatToHalf( tangent.z ); //tangent.z * 0x7FFF;
//         thb[a*4+3] = floatToHalf((((n % tangent) * binormal) > 0.0F) ? -1.0f : 1.0f); // handedness
        thb[a*4+0] = tangent.x; 
        thb[a*4+1] = tangent.y;
        thb[a*4+2] = tangent.z;
        thb[a*4+3] = ((((n % tangent) * binormal) > 0.0F) ? -1.0f : 1.0f); // handedness
    }
    
    delete[] tan1;
    delete[] tan2;

#ifdef OSG_CAL_BYTE_BUFFERS
    GLbyte* tangents = (GLbyte*) tangentBuffer->getDataPointer();
    GLbyte* binormals = (GLbyte*) binormalBuffer->getDataPointer();

    for ( int i = 0; i < vertexCount*3; i++ )
    {
        tangents[i]  = static_cast< GLbyte >( tangentBuffer[i]*127.0 );
        binormals[i] = static_cast< GLbyte >( binormalBuffer[i]*127.0 );
        //std::cout << (int)tangents[i] << '\n';
    }

    delete[] tangentBuffer;
    delete[] binormalBuffer;
#endif
}
예제 #3
0
void IKCharacter::solve( int iterations, int root_id, int leaf_id )
{
	while ( iterations>0 )
	{
		// start at leaf nodes
		deque<int> queue;
		
		// push leaf bones to target positions
		for ( int i=0; i<leaf_bones.size(); i++ )
		{
			// if we have a leaf id to use, skip all other leaves
			if ( leaf_id != -1 && leaf_id != leaf_bones[i] )
				continue;
			
			// if we have a target for this one
			if ( leaf_targets.find(leaf_bones[i]) != leaf_targets.end() )
			{
				// set it
				world_positions[leaf_bones[i]] = leaf_targets[leaf_bones[i]].second;
			}
			int parent_id = skeleton->getCoreSkeleton()->getCoreBone( leaf_bones[i] )->getParentId();
			if ( parent_id != -1 )
				queue.push_back( parent_id );
		}
		
		// queue to handle branching
		deque< int > branch_queue;
		while ( !queue.empty() || !branch_queue.empty() )
		{
			// if main queue is empty then we are ready to deal with branches
			if ( queue.empty() )
			{
				queue.push_back( branch_queue.front() );
				branch_queue.pop_front();
				continue;
			}
			
			int next_id = queue.front();
			queue.pop_front();
			// bail out if we should
			if ( root_id != -1 && next_id == root_id )
				continue;
			
			CalBone* bone = skeleton->getBone( next_id );
			list<int>& children = bone->getCoreBone()->getListChildId();
			// is this a branch?
			if ( children.size()>1 )
			{
				// still other children to process -- push to branch queue
				if ( !queue.empty() )
				{
					branch_queue.push_back( next_id );
					continue;
				}
				
				// otherwise, process branch here
				// if we're here, then all the children of this branch have been processed already
				int parent_id = bone->getCoreBone()->getParentId();
				if ( parent_id != -1 )
				{
					//printf("averaging %lu positions for %s wc %f: ", children.size(), bone->getCoreBone()->getName().c_str(), getWeightCentre( next_id ) );
					// fetch all child positions
					vector<CalVector> results;
					results.insert( results.begin(), children.size(), world_positions[next_id] );
					int count=0;
					for ( list<int>::iterator it = children.begin(); it != children.end(); ++it,++count ) 
					{
						
						// child_pos
						CalVector& b_c = world_positions[*it];
						// current pos
						CalVector& b_p = results[count];

						// now, the bone is the wrong length. correct its length to fulfil size constraint.
						CalVector delta = b_c - b_p;
						float length = delta.length();
						length = max( 0.00001f, length );
						// pointing from parent to child
						CalVector direction = delta/length;
						
						CalCoreBone* child_bone = skeleton->getCoreSkeleton()->getCoreBone( *it );
						CalVector rest_delta = bone->getCoreBone()->getTranslationAbsolute() - child_bone->getTranslationAbsolute();
						float desired_length = rest_delta.length();
						float delta_length = desired_length - length;
						
						// balance according to weight_centre
						float weight_centre = getWeightCentre(next_id);
						
						// move
						b_c += weight_centre * delta_length * direction;
						b_p -= (1.0f-weight_centre) * delta_length * direction;
						
						//printf("%s %f (%f %f %f), ", child_bone->getName().c_str(), delta_length, b_p.x, b_p.y, b_p.z );
						
					}
					//printf("\n");
					
					// now average
					CalVector average;
					for ( int i=0; i<results.size(); i++ )
					{
						average += results[i];
					}
					average /= results.size();

					// store
					world_positions[next_id] = average;
					
					// add parent
					queue.push_back( parent_id );
				}				
				
			}
			else
			{
				// children.size() is exactly 1
				assert( children.size()==1 );
				int child_id = children.front();
				
				// child_pos
				CalVector& b_c = world_positions[child_id];
				// current pos
				CalVector& b_p = world_positions[next_id];
				
				// now, the bone is the wrong length. correct its length to fulfil size constraint.
				float desired_length = getBoneLength(next_id);
				CalVector delta = b_c - b_p;
				float length = delta.length();
				length = max( 0.00001f, length );
				length = min( desired_length*1.5f, length );
				// pointing from parent to child
				CalVector direction = delta/length;
				
				float delta_length = desired_length - length;
				
				// balance according to weight_centre
				float weight_centre = getWeightCentre(next_id);
				
				// move
				b_c += weight_centre * delta_length * direction;
				b_p -= (1.0f-weight_centre) * delta_length * direction;
				
				
				// add parent
				int parent_id = bone->getCoreBone()->getParentId();
				if ( parent_id != -1 )
					queue.push_back( parent_id );
			}
		}	
		
		iterations--;
	}
	
	
}
예제 #4
0
void CalSpringSystem::calculateVertices(CalSubmesh *pSubmesh, float deltaTime)
{
  // get the vertex vector of the submesh
  std::vector<CalVector>& vectorVertex = pSubmesh->getVectorVertex();

  // get the physical property vector of the submesh
  std::vector<CalSubmesh::PhysicalProperty>& vectorPhysicalProperty = pSubmesh->getVectorPhysicalProperty();

  // get the physical property vector of the core submesh
  std::vector<CalCoreSubmesh::PhysicalProperty>& vectorCorePhysicalProperty = pSubmesh->getCoreSubmesh()->getVectorPhysicalProperty();

  // loop through all the vertices
  int vertexId;
  for(vertexId = 0; vertexId < (int)vectorVertex.size(); ++vertexId)
  {
    // get the vertex
    CalVector& vertex = vectorVertex[vertexId];

    // get the physical property of the vertex
    CalSubmesh::PhysicalProperty& physicalProperty = vectorPhysicalProperty[vertexId];

    // get the physical property of the core vertex
    CalCoreSubmesh::PhysicalProperty& corePhysicalProperty = vectorCorePhysicalProperty[vertexId];

    // store current position for later use
    CalVector position;
    position = physicalProperty.position;

    // only take vertices with a weight > 0 into account
    if(corePhysicalProperty.weight > 0.0f)
    {
      // do the Verlet step
      physicalProperty.position += (position - physicalProperty.positionOld) * 0.99f + physicalProperty.force / corePhysicalProperty.weight * deltaTime * deltaTime;
    }
    else
    {
      physicalProperty.position = vectorVertex[vertexId];
    }

    // make the current position the old one
    physicalProperty.positionOld = position;

    // set the new position of the vertex
    vertex = physicalProperty.position;

    // clear the accumulated force on the vertex
    physicalProperty.force.clear();
  }

  // get the spring vector of the core submesh
  std::vector<CalCoreSubmesh::Spring>& vectorSpring = pSubmesh->getCoreSubmesh()->getVectorSpring();

  // iterate a few times to relax the constraints
  int iterationCount;
#define ITERATION_COUNT 2
  for(iterationCount = 0; iterationCount < ITERATION_COUNT; ++iterationCount)
  {
    // loop through all the springs
    std::vector<CalCoreSubmesh::Spring>::iterator iteratorSpring;
    for(iteratorSpring = vectorSpring.begin(); iteratorSpring != vectorSpring.end(); ++iteratorSpring)
    {
      // get the spring
      CalCoreSubmesh::Spring& spring = *iteratorSpring;

      // compute the difference between the two spring vertices
      CalVector distance;
      distance = vectorVertex[spring.vertexId[1]] - vectorVertex[spring.vertexId[0]];

      // get the current length of the spring
      float length;
      length = distance.length();

      if(length > 0.0f)
      {
        float factor[2];
        factor[0] = (length - spring.idleLength) / length;
        factor[1] = factor[0];

        if(vectorCorePhysicalProperty[spring.vertexId[0]].weight > 0.0f)
        {
          factor[0] /= 2.0f;
          factor[1] /= 2.0f;
        }
        else
        {
          factor[0] = 0.0f;
        }

        if(vectorCorePhysicalProperty[spring.vertexId[1]].weight <= 0.0f)
        {
          factor[0] *= 2.0f;
          factor[1] = 0.0f;
        }

        vectorVertex[spring.vertexId[0]] += distance * factor[0];
        vectorPhysicalProperty[spring.vertexId[0]].position = vectorVertex[spring.vertexId[0]];

        vectorVertex[spring.vertexId[1]] -= distance * factor[1];
        vectorPhysicalProperty[spring.vertexId[1]].position = vectorVertex[spring.vertexId[1]];
      }
    }
  }
/* DEBUG-CODE ********************
  CalVector spherePosition(Sphere.x, Sphere.y, Sphere.z);
  float sphereRadius = Sphere.radius;

  // loop through all the vertices
  for(vertexId = 0; vertexId < (int)vectorVertex.size(); ++vertexId)
  {
    // get the vertex
    CalVector& vertex = vectorVertex[vertexId];

    // get the physical property of the vertex
    CalSubmesh::PhysicalProperty& physicalProperty = vectorPhysicalProperty[vertexId];

    // get the physical property of the core vertex
    CalCoreSubmesh::PhysicalProperty& corePhysicalProperty = vectorCorePhysicalProperty[vertexId];

    // only take vertices with a weight > 0 into account
    if(corePhysicalProperty.weight > 0.0f)
    {
      CalVector position;
      position = physicalProperty.position;
      position -= spherePosition;

      float length;
      length = position.normalize();

      if(length < sphereRadius)
      {
        position *= sphereRadius;
        position += spherePosition;

        physicalProperty.position = position;
        physicalProperty.positionOld = position;
        vertex = physicalProperty.position;
      }
    }
  }
*********************************/
}
예제 #5
0
void IKCharacter::setup( CalSkeleton* cal_skel, bool _auto_root_follow )
{
	skeleton = cal_skel;
	auto_root_follow = _auto_root_follow;
	
	
	// find leaf bones
	deque<int> current;
	vector<int> roots = cal_skel->getCoreSkeleton()->getVectorRootCoreBoneId();
	current.insert( current.begin(), roots.begin(), roots.end() );
	while( !current.empty() )
	{
		CalCoreBone* check = skeleton->getCoreSkeleton()->getCoreBone( current.front() );
		list<int> children = check->getListChildId();
		if ( children.size()==0 )
		{
			// this is a leaf
			leaf_bones.push_back( current.front() );
			printf("found leaf: %s\n", skeleton->getCoreSkeleton()->getCoreBone( leaf_bones.back() )->getName().c_str() );
		}
		else
		{
			// not a leaf
			current.insert( current.end(), children.begin(), children.end() );
		}
		
		// store length
		// default non-zero
		bone_lengths[current.front()] = 0.0001f;
		if ( check->getParentId()!= -1 )
		{
			CalCoreBone* parent = skeleton->getCoreSkeleton()->getCoreBone( check->getParentId() );
			CalVector delta = check->getTranslationAbsolute() - parent->getTranslationAbsolute();
			bone_lengths[check->getParentId()] = delta.length();
		}
	
		// cached rotations
		debug_cached_rotations[current.front()] = CalQuaternion();
		
		current.pop_front();
	}

	// set all weights to default
	vector<CalCoreBone*> all_bones = skeleton->getCoreSkeleton()->getVectorCoreBone();
	for( int i=0; i<all_bones.size() ;i++ )
	{
		weight_centres[all_bones[i]->getId()] = 0.5f;
	}	
	
	// release all leaves
	for ( int i=0; i<leaf_bones.size() ;i++ )
	{
		weight_centres[leaf_bones[i]] = 0;
	}
	// pin all roots
	for ( int i=0; i<roots.size(); i++ )
	{
		weight_centres[roots[i]] = 1;
	}
	
	// fetch world positions from Cal3D model
	pullWorldPositions();
	
	// set targets
	/*
	for ( int i=0; i<leaf_bones.size(); i++ )
	{
		CalVector p = world_positions[leaf_bones[i]];
		setTarget( leaf_bones[i], ofxVec3f(p.x,p.y,p.z) );
	}*/
	
	// 
	setupMagicIgnoringRotationOffsets();
	
}