mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-30 16:15:31 +00:00
If nif has a skeleton vertices are placed on the right position.
This commit is contained in:
parent
6a936100a7
commit
47a28fe02b
1 changed files with 92 additions and 114 deletions
|
@ -32,6 +32,7 @@
|
|||
#include "../nif/property.hpp"
|
||||
#include <libs/platform/strings.h>
|
||||
|
||||
#include <vector>
|
||||
// For warning messages
|
||||
#include <iostream>
|
||||
|
||||
|
@ -336,13 +337,16 @@ void NIFLoader::createOgreSubMesh(NiTriShape *shape, const String &material)
|
|||
sub->vertexData = new VertexData();
|
||||
sub->vertexData->vertexCount = numVerts;
|
||||
sub->useSharedVertices = false;
|
||||
|
||||
VertexDeclaration *decl = sub->vertexData->vertexDeclaration;
|
||||
decl->addElement(nextBuf, 0, VET_FLOAT3, VES_POSITION);
|
||||
|
||||
HardwareVertexBufferSharedPtr vbuf =
|
||||
HardwareBufferManager::getSingleton().createVertexBuffer(
|
||||
VertexElement::getTypeSize(VET_FLOAT3),
|
||||
numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
|
||||
vbuf->writeData(0, vbuf->getSizeInBytes(), data->vertices.ptr, true);
|
||||
|
||||
VertexBufferBinding* bind = sub->vertexData->vertexBufferBinding;
|
||||
bind->setBinding(nextBuf++, vbuf);
|
||||
|
||||
|
@ -406,34 +410,6 @@ void NIFLoader::createOgreSubMesh(NiTriShape *shape, const String &material)
|
|||
|
||||
// Set material if one was given
|
||||
if (!material.empty()) sub->setMaterialName(material);
|
||||
|
||||
|
||||
// assigning bones if skindata is not empty
|
||||
if (!shape->skin.empty())
|
||||
{
|
||||
NodeList *boneList = &shape->skin->bones;
|
||||
|
||||
for (int i=0; i<boneList->length(); i++)
|
||||
{
|
||||
if (boneList->has(i))
|
||||
{
|
||||
Nif::Node *bone = &(*boneList)[i];
|
||||
|
||||
SkeletonPtr skel = SkeletonManager::getSingleton().getByName(getSkeletonName());
|
||||
|
||||
VertexBoneAssignment vba;
|
||||
vba.boneIndex = skel->getBone(bone->name.toString())->getHandle();
|
||||
vba.weight = 1.0;
|
||||
|
||||
for (unsigned int j=0; j<sub->vertexData->vertexCount; j++) //assing every vertex
|
||||
{
|
||||
vba.vertexIndex = j;
|
||||
sub->addBoneAssignment(vba);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Helper math functions. Reinventing linear algebra for the win!
|
||||
|
@ -619,25 +595,99 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou
|
|||
float *ptr = (float*)data->vertices.ptr;
|
||||
float *optr = ptr;
|
||||
|
||||
// Rotate, scale and translate all the vertices
|
||||
const Matrix &rot = shape->trafo->rotation;
|
||||
const Vector &pos = shape->trafo->pos;
|
||||
float scale = shape->trafo->scale;
|
||||
for (int i=0; i<numVerts; i++)
|
||||
//use niskindata for the position of vertices.
|
||||
if (!shape->skin.empty())
|
||||
{
|
||||
vectorMulAdd(rot, pos, ptr, scale);
|
||||
ptr += 3;
|
||||
}
|
||||
// vector that stores if the position if a vertex is absolute
|
||||
std::vector<bool> vertexPosAbsolut(numVerts,false);
|
||||
|
||||
|
||||
// Remember to rotate all the vertex normals as well
|
||||
if (data->normals.length)
|
||||
float *ptrNormals = (float*)data->normals.ptr;
|
||||
//the bone from skin->bones[boneIndex] is linked to skin->data->bones[boneIndex]
|
||||
//the first one contains a link to the bone, the second vertex transformation
|
||||
//relative to the bone
|
||||
int boneIndex = 0;
|
||||
Bone *bonePtr;
|
||||
Vector3 vecPos;
|
||||
Quaternion vecRot;
|
||||
|
||||
std::vector<NiSkinData::BoneInfo> boneList = shape->skin->data->bones;
|
||||
|
||||
/*
|
||||
Iterate through the boneList which contains what vertices are linked to
|
||||
the bone (it->weights array) and at what position (it->trafo)
|
||||
That position is added to every vertex.
|
||||
*/
|
||||
for (std::vector<NiSkinData::BoneInfo>::iterator it = boneList.begin();
|
||||
it != boneList.end(); it++)
|
||||
{
|
||||
//get the bone from bones array of skindata
|
||||
bonePtr = skel->getBone(shape->skin->bones[boneIndex].name.toString());
|
||||
|
||||
// final_vector = old_vector + old_rotation*new_vector*old_scale
|
||||
vecPos = bonePtr->_getDerivedPosition() +
|
||||
bonePtr->_getDerivedOrientation() * convertVector3(it->trafo->trans);
|
||||
|
||||
vecRot = bonePtr->_getDerivedOrientation() * convertRotation(it->trafo->rotation);
|
||||
|
||||
for (unsigned int i=0; i<it->weights.length; i++)
|
||||
{
|
||||
unsigned int verIndex = (it->weights.ptr + i)->vertex;
|
||||
|
||||
//Check if the vertex is relativ, FIXME: Is there a better solution?
|
||||
if (vertexPosAbsolut[verIndex] == false)
|
||||
{
|
||||
//apply transformation to the vertices
|
||||
Vector3 absVertPos = vecPos + vecRot * Vector3(ptr + verIndex *3);
|
||||
|
||||
//convert it back to float *
|
||||
for (int j=0; j<3; j++)
|
||||
(ptr + verIndex*3)[j] = absVertPos[j];
|
||||
|
||||
//apply rotation to the normals (not every vertex has a normal)
|
||||
//FIXME: I guessed that vertex[i] = normal[i], is that true?
|
||||
if (verIndex < data->normals.length)
|
||||
{
|
||||
Vector3 absNormalsPos = vecRot * Vector3(ptrNormals + verIndex *3);
|
||||
|
||||
for (int j=0; j<3; j++)
|
||||
(ptrNormals + verIndex*3)[j] = absNormalsPos[j];
|
||||
}
|
||||
|
||||
|
||||
//TODO: create vbas, and give them to createOgreSubMesh
|
||||
|
||||
vertexPosAbsolut[verIndex] = true;
|
||||
}
|
||||
}
|
||||
|
||||
boneIndex++;
|
||||
//it->trafo (pos, rot, scale) of the vertex
|
||||
//it->weights array containt the vertices linked to the bone and the weight
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = (float*)data->normals.ptr;
|
||||
// Rotate, scale and translate all the vertices,
|
||||
const Matrix &rot = shape->trafo->rotation;
|
||||
const Vector &pos = shape->trafo->pos;
|
||||
float scale = shape->trafo->scale;
|
||||
for (int i=0; i<numVerts; i++)
|
||||
{
|
||||
vectorMul(rot, ptr);
|
||||
vectorMulAdd(rot, pos, ptr, scale);
|
||||
ptr += 3;
|
||||
}
|
||||
|
||||
// Remember to rotate all the vertex normals as well
|
||||
if (data->normals.length)
|
||||
{
|
||||
ptr = (float*)data->normals.ptr;
|
||||
for (int i=0; i<numVerts; i++)
|
||||
{
|
||||
vectorMul(rot, ptr);
|
||||
ptr += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hidden)
|
||||
|
@ -703,13 +753,6 @@ void NIFLoader::handleNode(Nif::Node *node, int flags,
|
|||
bone->setPosition(convertVector3(node->trafo->pos));
|
||||
bone->setOrientation(convertRotation(node->trafo->rotation));
|
||||
}
|
||||
|
||||
//output for debuging purpose
|
||||
// Ogre::Vector3 vec(node->trafo->pos.array);
|
||||
// Ogre::Quaternion q = convertRotation(node->trafo->rotation);
|
||||
// std::cout << node->name.toString() << ": " << vec.x << " " << vec.y << " " << vec.z << "\n";
|
||||
// std::cout << " Y: " << q.getYaw().valueDegrees() << " P: " << q.getPitch().valueDegrees() << " R: " << q.getRoll().valueDegrees() << "\n";
|
||||
|
||||
}
|
||||
|
||||
// Apply the parent transformation to this node. We overwrite the
|
||||
|
@ -803,8 +846,8 @@ void NIFLoader::loadResource(Resource *resource)
|
|||
handleNode(node, 0, NULL, bounds, 0);
|
||||
|
||||
//set skeleton
|
||||
if (!skel.isNull())
|
||||
mesh->setSkeletonName(getSkeletonName());
|
||||
// if (!skel.isNull())
|
||||
// mesh->setSkeletonName(getSkeletonName());
|
||||
|
||||
// Finally, set the bounding value.
|
||||
if (bounds.isValid())
|
||||
|
@ -867,70 +910,5 @@ extern "C" void ogre_insertTexture(char* name, uint32_t width, uint32_t height,
|
|||
pixelBuffer->unlock();
|
||||
}
|
||||
|
||||
// We need this later for animated meshes.
|
||||
extern "C" void* ogre_setupSkeleton(char* name)
|
||||
{
|
||||
SkeletonPtr skel = SkeletonManager::getSingleton().create(
|
||||
name, "Closet", true);
|
||||
|
||||
skel->load();
|
||||
|
||||
// Create all bones at the origin and unrotated. This is necessary
|
||||
// since our submeshes each have their own model space. We must
|
||||
// move the bones after creating an entity, then copy this entity.
|
||||
return (void*)skel->createBone();
|
||||
}
|
||||
|
||||
extern "C" void *ogre_insertBone(char* name, void* rootBone, int32_t index)
|
||||
{
|
||||
return (void*) ( ((Bone*)rootBone)->createChild(index) );
|
||||
}
|
||||
*/
|
||||
/* This was the D part:
|
||||
|
||||
// Create a skeleton and get the root bone (index 0)
|
||||
BonePtr bone = ogre_setupSkeleton(name);
|
||||
|
||||
// Reset the bone index. The next bone to be created has index 1.
|
||||
boneIndex = 1;
|
||||
// Create a mesh and assign the skeleton to it
|
||||
MeshPtr mesh = ogre_setupMesh(name);
|
||||
|
||||
// Loop through the nodes, creating submeshes, materials and
|
||||
// skeleton bones in the process.
|
||||
handleNode(node, bone, mesh);
|
||||
|
||||
// Create the "template" entity
|
||||
EntityPtr entity = ogre_createEntity(name);
|
||||
|
||||
// Loop through once again, this time to set the right
|
||||
// transformations on the entity's SkeletonInstance. The order of
|
||||
// children will be the same, allowing us to reference bones using
|
||||
// their boneIndex.
|
||||
int lastBone = boneIndex;
|
||||
boneIndex = 1;
|
||||
transformBones(node, entity);
|
||||
if(lastBone != boneIndex) writefln("WARNING: Bone number doesn't match");
|
||||
|
||||
if(!hasBBox)
|
||||
ogre_setMeshBoundingBox(mesh, minX, minY, minZ, maxX, maxY, maxZ);
|
||||
|
||||
return entity;
|
||||
}
|
||||
void handleNode(Node node, BonePtr root, MeshPtr mesh)
|
||||
{
|
||||
// Insert a new bone for this node
|
||||
BonePtr bone = ogre_insertBone(node.name, root, boneIndex++);
|
||||
|
||||
}
|
||||
|
||||
void transformBones(Node node, EntityPtr entity)
|
||||
{
|
||||
ogre_transformBone(entity, &node.trafo, boneIndex++);
|
||||
|
||||
NiNode n = cast(NiNode)node;
|
||||
if(n !is null)
|
||||
foreach(Node nd; n.children)
|
||||
transformBones(nd, entity);
|
||||
}
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue