Beispiel #1
0
    void AssimpModelImporter::ExtractJointsAndWeights(aiMesh* mesh, vector<Vector4i>& joints, vector<Vector4f>& weights, vector<ModelPartBone>& bones) const {

        vector<vector<VertexInfluence>> vertices;
        vertices.resize(mesh->mNumVertices);

        for(U32 i = 0; i < mesh->mNumBones; ++i) {
            aiBone* bone = mesh->mBones[i];
            ModelPartBone modelPartBone(bone->mName.C_Str(), ToMatrix(bone->mOffsetMatrix));
            bones.push_back(modelPartBone);

            for(U32 j = 0; j < bone->mNumWeights; ++j) {
                aiVertexWeight vertexWeight = bone->mWeights[j];
                U32 vertexIndex = vertexWeight.mVertexId;
                VertexInfluence vertexInfluence;
                vertexInfluence.weight = vertexWeight.mWeight;
                vertexInfluence.boneIndex = i;

                vertices[vertexIndex].push_back(vertexInfluence);
            }
        }

        // When exporting program assigned more then 4 joints (engine limit) to single vertex we exclude the least 
        // influential ones and add removed weights to 4th vertex; This is not ideal solution - we should always 
        // prefer exporter with limited number of joints per vertex due to possible discrepancy in exported and 
        // imported animation.

        for(auto it = begin(vertices); it != end(vertices); ++it) {
            vector<VertexInfluence>& influences = *it;
            sort(influences.begin(), influences.end(), [](const VertexInfluence& a, const VertexInfluence& b) -> bool {
                return a.weight > b.weight;
            });
            
            if (influences.size() > 4) {
                influences.erase(begin(influences) + 4, end(influences));

                _ASSERT(4 == influences.size());

                F32 sumOfThreeWeights = influences[0].weight + influences[1].weight + influences[2].weight;
                influences[3].weight = 1.0f - sumOfThreeWeights;
            }
        }

        joints.resize(mesh->mNumVertices, Vector4i(0));
        weights.resize(mesh->mNumVertices, Vector4f(0.0f));

        for(U32 i = 0; i < mesh->mNumVertices; ++i) {
            for(U32 j = 0; j < vertices[i].size(); ++j) {
                joints[i].v[j] = vertices[i][j].boneIndex;
                weights[i].v[j] = vertices[i][j].weight;
            }
        }
    }
Beispiel #2
0
    void ToViewProjectionMatrix(float m[16], float fov, float aspect, float znear, float zfar)
    {

        float w = 1.0f/tan(fov/2.0f);
	    float h = w * aspect;
	    float z1 = zfar / (znear-zfar);
	    float z2 = z1 * znear;
        
        ToMatrix(m);
        *((Vec4*)m + 3) = -*((Vec4*)m + 2);
        *((Vec4*)m) *= w;
        *((Vec4*)m + 1) *= h;
        *((Vec4*)m + 2) *= z1;
        m[11] += z2;
    }
void
RotatedContentBuffer::DrawTo(ThebesLayer* aLayer,
                             gfxContext* aTarget,
                             float aOpacity,
                             gfxASurface* aMask,
                             const gfxMatrix* aMaskTransform)
{
  if (!EnsureBuffer()) {
    return;
  }

  RefPtr<DrawTarget> dt = aTarget->GetDrawTarget();
  MOZ_ASSERT(dt, "Did you pass a non-Azure gfxContext?");
  bool clipped = false;

  // If the entire buffer is valid, we can just draw the whole thing,
  // no need to clip. But we'll still clip if clipping is cheap ---
  // that might let us copy a smaller region of the buffer.
  // Also clip to the visible region if we're told to.
  if (!aLayer->GetValidRegion().Contains(BufferRect()) ||
      (ToData(aLayer)->GetClipToVisibleRegion() &&
       !aLayer->GetVisibleRegion().Contains(BufferRect())) ||
      IsClippingCheap(aTarget, aLayer->GetEffectiveVisibleRegion())) {
    // We don't want to draw invalid stuff, so we need to clip. Might as
    // well clip to the smallest area possible --- the visible region.
    // Bug 599189 if there is a non-integer-translation transform in aTarget,
    // we might sample pixels outside GetEffectiveVisibleRegion(), which is wrong
    // and may cause gray lines.
    gfxUtils::ClipToRegionSnapped(dt, aLayer->GetEffectiveVisibleRegion());
    clipped = true;
  }

  RefPtr<gfx::SourceSurface> mask;
  if (aMask) {
    mask = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, aMask);
  }

  Matrix maskTransform;
  if (aMaskTransform) {
    maskTransform = ToMatrix(*aMaskTransform);
  }

  CompositionOp op = CompositionOpForOp(aTarget->CurrentOperator());
  DrawBufferWithRotation(dt, BUFFER_BLACK, aOpacity, op, mask, &maskTransform);
  if (clipped) {
    dt->PopClip();
  }
}
Beispiel #4
0
    void AssimpModelImporter::CreateModelGraph(aiNode* node, I32 parent, vector<ModelNode>& modelNodes) const {
        _ASSERT(node);

        ModelNode modelNode(node->mName.C_Str(), ToMatrix(node->mTransformation), parent);

        for(U32 i = 0; i < node->mNumMeshes; ++i) {
            U32 meshIndex = node->mMeshes[i];
            modelNode.modelParts.push_back(meshIndex);
        }

        modelNodes.push_back(modelNode);

        I32 currentNodeIndex = modelNodes.size() - 1;

        if (-1 != parent) {
            modelNodes[parent].children.push_back(currentNodeIndex);
        }

        for(U32 i = 0; i < node->mNumChildren; ++i) {
            CreateModelGraph(node->mChildren[i], currentNodeIndex, modelNodes);
        }
    }
Beispiel #5
0
void Quat::ToEuler( Real& x, Real& y, Real& z, EulerOrder eulerOrder ) const
{
    // use matrix based method
    Real m[3][3];

    // convert to matrix
    ToMatrix( m );

    switch( eulerOrder )
    {
    case EULER_ORDER_XYZ:
        Restrain( m[0][2], Real( -1 ), Real( 1 ) );
        y = asin( m[0][2] );
        x = atan2( -m[1][2], m[2][2] );
        z = atan2( -m[0][1], m[0][0] );
        break;

    case EULER_ORDER_ZYX:
        Restrain( m[2][0], Real( -1 ), Real( 1 ) );
        y = asin( -m[2][0] );
        z = atan2( m[1][0], m[0][0] );
        x = atan2( m[2][1], m[2][2] );
        break;

    case EULER_ORDER_YXZ:
        Restrain( m[1][2], Real( -1 ), Real( 1 ) );
        x = asin( -m[1][2] );
        y = atan2( m[0][2], m[2][2] );
        z = atan2( m[1][0], m[1][1] );
        break;

    default:
        throw std::logic_error( "Euler order not supported" );
        break;
    }
}
Beispiel #6
0
  /** original mesh file format.

	char[3]           "MSH"
	uint8_t           mesh count.
	reserved          (2 byte)
	uint32_t          vbo offset by the top of file(32bit alignment).
	uint32_t          vbo byte size(32bit alignment).
	uint32_t          ibo byte size(32bit alignment).

	[
	  uint8_t         mesh name length.
	  char[mesh name length] mesh name(without zero ternmination).
	  uint8_t         material count.
	  padding         (4 - (length + 2) % 4) % 4 byte.
	  [
		uint32_t        ibo offset.
		uint16_t        ibo size(this is the polygon counts, so actual ibo size is 3 times).
		uint8_t         red
		uint8_t         green
		uint8_t         blue
		uint8_t         alpha
		uint8_t         metallic
		uint8_t         roughness
		] x (ibo count)
	] x (mesh count)

	uint8_t                          albedo texture name length.
	char[albedo texture name length] albedo texture name(without zero ternmination).
	uint8_t                          normal texture name length.
	char[normal texture name length] normal texture name(without zero ternmination).
	padding                          (4 - (texture name block size % 4) % 4 byte.

	vbo               vbo data.
	ibo               ibo data.
	padding           (4 - (ibo byte size % 4) % 4 byte.

	uint16_t          bone count.
	uint16_t          animation count.

	[
	  RotTrans        rotation and translation for the bind pose.
	  int32_t         parent bone index.
	] x (bone count)

	[
	  uint8_t         animation name length.
	  char[24]        animation name.
	  bool            loop flag
	  uint16_t        key frame count.
	  float           total time.
	  [
		float         time.
		[
		  RotTrans    rotation and translation.
		] x (bone count)
	  ] x (key frame count)
	] x (animation count)
  */
  ImportMeshResult ImportMesh(const RawBuffer& data, GLuint& vbo, GLintptr& vboEnd, GLuint& ibo, GLintptr& iboEnd)
  {
	const uint8_t* p = &data[0];
	const uint8_t* pEnd = p + data.size();
	if (p[0] != 'M' || p[1] != 'S' || p[2] != 'H') {
	  return ImportMeshResult(ImportMeshResult::Result::invalidHeader);
	}
	p += 3;
	const int count = *p;
	p += 1;
	/*const uint32_t vboOffset = GetValue(p, 4);*/ p += 4;
	const uint32_t vboByteSize = GetValue(p, 4); p += 4;
	const uint32_t iboByteSize = GetValue(p, 4); p += 4;
	if (p >= pEnd) {
	  return ImportMeshResult(ImportMeshResult::Result::noData);
	}

	GLuint iboBaseOffset = iboEnd;
	ImportMeshResult  result(ImportMeshResult::Result::success);
	result.meshes.reserve(count);
	for (int i = 0; i < count; ++i) {
	  Mesh m;
	  const uint32_t nameLength = *p++;
	  m.id.assign(p, p + nameLength); p += nameLength;
	  const size_t materialCount = *p++;
	  p += (4 - (nameLength + 2) % 4) % 4;
	  m.materialList.resize(materialCount);
	  for (auto& e : m.materialList) {
		e.iboOffset = iboBaseOffset; p += 4;
		e.iboSize = GetValue(p, 2); p += 2;
		e.material.color.r = *p++;
		e.material.color.g = *p++;
		e.material.color.b = *p++;
		e.material.color.a = *p++;
		e.material.metallic.Set(static_cast<float>(*p++) / 255.0f);
		e.material.roughness.Set(static_cast<float>(*p++) / 255.0f);
		iboBaseOffset += e.iboSize * sizeof(GLushort);
	  }
	  result.meshes.push_back(m);
	  if (p >= pEnd) {
		return ImportMeshResult(ImportMeshResult::Result::invalidMeshInfo);
	  }
	}

	glBufferSubData(GL_ARRAY_BUFFER, vboEnd, vboByteSize, p);
	p += vboByteSize;
	if (p >= pEnd) {
	  return ImportMeshResult(ImportMeshResult::Result::invalidVBO);
	}

	std::vector<GLushort>  indices;
	indices.reserve(iboByteSize / sizeof(GLushort));
	const uint32_t offsetTmp = vboEnd / sizeof(Vertex);
	if (offsetTmp > 0xffff) {
	  return ImportMeshResult(ImportMeshResult::Result::indexOverflow);
	}
	const GLushort offset = static_cast<GLushort>(offsetTmp);
	for (uint32_t i = 0; i < iboByteSize; i += sizeof(GLushort)) {
	  indices.push_back(*reinterpret_cast<const GLushort*>(p) + offset);
	  p += sizeof(GLushort);
	  if (p >= pEnd) {
		return ImportMeshResult(ImportMeshResult::Result::invalidIBO);
	  }
	}
	glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, iboEnd, iboByteSize, &indices[0]);

	vboEnd += vboByteSize;
	iboEnd += iboByteSize;

	p += (4 - (reinterpret_cast<intptr_t>(p) % 4)) % 4;
	if (p >= pEnd) {
	  return result;
	}

	const uint32_t boneCount = GetValue(p, 2); p += 2;
	const uint32_t animationCount = GetValue(p, 2); p += 2;

	if (boneCount) {
	  JointList joints;
	  joints.resize(boneCount);
	  std::vector<std::vector<int>> parentIndexList;
	  parentIndexList.resize(boneCount);
	  for (uint32_t i = 0; i < boneCount; ++i) {
		if (p >= pEnd) {
		  return ImportMeshResult(ImportMeshResult::Result::invalidJointInfo);
		}
		Joint& e = joints[i];
		e.invBindPose.rot.x = GetFloat(p);
		e.invBindPose.rot.y = GetFloat(p);
		e.invBindPose.rot.z = GetFloat(p);
		e.invBindPose.rot.w = GetFloat(p);
		e.invBindPose.rot.Normalize();
		e.invBindPose.trans.x = GetFloat(p);
		e.invBindPose.trans.y = GetFloat(p);
		e.invBindPose.trans.z = GetFloat(p);
#if 0
		const Matrix4x3 m43 = ToMatrix(e.invBindPose.rot);
		Matrix4x4 m44;
		m44.SetVector(0, m43.GetVector(0));
		m44.SetVector(1, m43.GetVector(1));
		m44.SetVector(2, m43.GetVector(2));
		m44.SetVector(3, e.invBindPose.trans);
		m44.Inverse();
		Vector3F scale;
		m44.Decompose(&e.initialPose.rot, &scale, &e.initialPose.trans);
#else
		e.initialPose.rot = e.invBindPose.rot.Inverse();
		e.initialPose.trans = e.initialPose.rot.Apply(-e.invBindPose.trans);
#endif
		e.offChild = 0;
		e.offSibling = 0;
		const uint32_t parentIndex = GetValue(p, 4); p += 4;
		if (parentIndex != 0xffffffff) {
		  parentIndexList[parentIndex].push_back(i);
		}
	  }
	  for (uint32_t i = 0; i < boneCount; ++i) {
		const auto& e = parentIndexList[i];
		if (!e.empty()) {
		  int current = e[0];
		  joints[i].offChild = current - i;
		  Joint* pJoint = &joints[current];
		  for (auto itr = e.begin() + 1; itr != e.end(); ++itr) {
			const int sibling = *itr;
			pJoint->offSibling = sibling - current;
			pJoint = &joints[sibling];
			current = sibling;
		  }
		}
	  }
	  for (auto& e : result.meshes) {
		e.jointList = joints;
	  }
	}

	if (animationCount) {
	  LOGI("ImportMesh - Read animation:");
	  result.animations.reserve(animationCount);
	  for (uint32_t i = 0; i < animationCount; ++i) {
		Animation anm;
		const uint32_t nameLength = GetValue(p++, 1);
		char name[24];
		for (int i = 0; i < 24; ++i) {
		  name[i] = static_cast<char>(GetValue(p++, 1));
		}
		anm.id.assign(name, name + nameLength);
		anm.data.resize(boneCount);
		for (uint32_t bone = 0; bone < boneCount; ++bone) {
		  anm.data[bone].first = bone;
		}
		anm.loopFlag = static_cast<bool>(GetValue(p++, 1) != 0);
		const uint32_t keyframeCount = GetValue(p, 2); p += 2;
		anm.totalTime = GetFloat(p);
		LOGI("%s: %fsec", anm.id.c_str(), anm.totalTime);
		for (uint32_t keyframe = 0; keyframe < keyframeCount; ++keyframe) {
		  const float time = GetFloat(p);
#ifdef DEBUG_LOG_VERBOSE
		  LOGI("time=%f", time);
#endif // DEBUG_LOG_VERBOSE
		  for (uint32_t bone = 0; bone < boneCount; ++bone) {
			if (p >= pEnd) {
			  return ImportMeshResult(ImportMeshResult::Result::invalidAnimationInfo);
			}
			Animation::Element elem;
			elem.time = time;
			elem.pose.rot.x = GetFloat(p);
			elem.pose.rot.y = GetFloat(p);
			elem.pose.rot.z = GetFloat(p);
			elem.pose.rot.w = GetFloat(p);
			elem.pose.rot.Normalize();
			elem.pose.trans.x = GetFloat(p);
			elem.pose.trans.y = GetFloat(p);
			elem.pose.trans.z = GetFloat(p);
			anm.data[bone].second.push_back(elem);
#ifdef DEBUG_LOG_VERBOSE
			LOGI("%02d:(%+1.3f, %+1.3f, %+1.3f, %+1.3f) (%+1.3f, %+1.3f, %+1.3f)", bone, elem.pose.rot.w, elem.pose.rot.x, elem.pose.rot.y, elem.pose.rot.z, elem.pose.trans.x, elem.pose.trans.y, elem.pose.trans.z);
#endif // DEBUG_LOG_VERBOSE
		  }
		}
		result.animations.push_back(anm);
	  }
	}

	return result;
  }