Create an array of MeshInstances and SkinInstances on the the model
pc.script.attribute('enabled', 'boolean', true);
pc.script.create('skinnedcombiner', function (app) {
var createMesh = function (device, positions, opts) {
// Check the supplied options and provide defaults for unspecified ones
var normals = opts && opts.normals !== undefined ? opts.normals : null;
var tangents = opts && opts.tangents !== undefined ? opts.tangents : null;
var uvs = opts && opts.uvs !== undefined ? opts.uvs : null;
var uvs1 = opts && opts.uvs1 !== undefined ? opts.uvs1 : null;
var indices = opts && opts.indices !== undefined ? opts.indices : null;
var blendWeights = opts && opts.blendWeights !== undefined ? opts.blendWeights : null;
var blendIndices = opts && opts.blendIndices !== undefined ? opts.blendIndices : null;
var vertexDesc = [
{ semantic: pc.SEMANTIC_POSITION, components: 3, type: pc.ELEMENTTYPE_FLOAT32 }
];
if (normals !== null) {
vertexDesc.push({ semantic: pc.SEMANTIC_NORMAL, components: 3, type: pc.ELEMENTTYPE_FLOAT32 });
}
if (tangents !== null) {
vertexDesc.push({ semantic: pc.SEMANTIC_TANGENT, components: 4, type: pc.ELEMENTTYPE_FLOAT32 });
}
if (uvs !== null) {
vertexDesc.push({ semantic: pc.SEMANTIC_TEXCOORD0, components: 2, type: pc.ELEMENTTYPE_FLOAT32 });
}
if (uvs1 !== null) {
vertexDesc.push({ semantic: pc.SEMANTIC_TEXCOORD1, components: 2, type: pc.ELEMENTTYPE_FLOAT32 });
}
if (blendWeights !== null) {
vertexDesc.push({ semantic: pc.SEMANTIC_BLENDWEIGHT, components: 4, type: pc.ELEMENTTYPE_FLOAT32 });
}
if (blendIndices !== null) {
vertexDesc.push({ semantic: pc.SEMANTIC_BLENDINDICES, components: 4, type: pc.ELEMENTTYPE_UINT8 });
}
var vertexFormat = new pc.VertexFormat(device, vertexDesc);
// Create the vertex buffer
var numVertices = positions.length / 3;
var vertexBuffer = new pc.VertexBuffer(device, vertexFormat, numVertices);
// Write the vertex data into the vertex buffer
var iterator = new pc.VertexIterator(vertexBuffer);
for (var i = 0; i < numVertices; i++) {
iterator.element[pc.SEMANTIC_POSITION].set(positions[i*3], positions[i*3+1], positions[i*3+2]);
if (normals !== null) {
iterator.element[pc.SEMANTIC_NORMAL].set(normals[i*3], normals[i*3+1], normals[i*3+2]);
}
if (tangents !== null) {
iterator.element[pc.SEMANTIC_TANGENT].set(tangents[i*4], tangents[i*4+1], tangents[i*4+2], tangents[i*4+3]);
}
if (uvs !== null) {
iterator.element[pc.SEMANTIC_TEXCOORD0].set(uvs[i*2], uvs[i*2+1]);
}
if (uvs1 !== null) {
iterator.element[pc.SEMANTIC_TEXCOORD1].set(uvs1[i*2], uvs1[i*2+1]);
}
if(blendWeights !== null) {
iterator.element[pc.SEMANTIC_BLENDWEIGHT].set(blendWeights[i*4], blendWeights[i*4+1],blendWeights[i*4+2], blendWeights[i*4+3]);
}
if(blendIndices !== null) {
iterator.element[pc.SEMANTIC_BLENDINDICES].set(blendIndices[i*4], blendIndices[i*4+1],blendIndices[i*4+2], blendIndices[i*4+3]);
}
iterator.next();
}
iterator.end();
// Create the index buffer
var indexBuffer = null;
var indexed = (indices !== null);
if (indexed) {
indexBuffer = new pc.IndexBuffer(device, pc.INDEXFORMAT_UINT16, indices.length);
// Read the indicies into the index buffer
var dst = new Uint16Array(indexBuffer.lock());
dst.set(indices);
indexBuffer.unlock();
}
var aabb = new pc.BoundingBox();
aabb.compute(positions);
var mesh = new pc.Mesh();
mesh.vertexBuffer = vertexBuffer;
mesh.indexBuffer[0] = indexBuffer;
mesh.primitive[0].type = pc.PRIMITIVE_TRIANGLES;
mesh.primitive[0].base = 0;
mesh.primitive[0].count = indexed ? indices.length : numVertices;
mesh.primitive[0].indexed = indexed;
mesh.aabb = aabb;
return mesh;
};
var SkinnedCombiner = function SkinnedCombiner(entity) {
this.entity = entity;
//this.enabled = this.enabled;
};
window.allCombined = window.allCombined || [];
function float32(locked, element) {
return new Float32Array(locked, element.offset);
}
var validTypes = {
"POSITION": float32,
"NORMAL": float32,
"TANGENT": float32,
"TEXCOORD0": float32
};
window.nextId = window.nextId || 1;
var vec = new pc.Vec3();
SkinnedCombiner.prototype = {
postInitialize: function () {
if (!this.enabled) {
return;
}
this.enabled = false;
var meshes = [];
pc.utils.ofType(this.entity, 'model')
.forEach(function (model) {
if (model.model && model.enabled && model.entity._enabled) {
model.model.meshInstances.forEach(function (mesh) {
meshes.push({
mesh: mesh,
material: mesh.material,
model: model
});
});
}
});
var byMaterial = _.filter(_.groupBy(meshes, function (mesh) {
return mesh.material.name;
}), function (g) {
return g.length > 0;
});
var sizes = _.map(byMaterial, function (m) {
return _.reduce(m, function (result, c) {
return result + c.mesh.mesh.vertexBuffer.numVertices;
}, 0);
});
var replace = new pc.Entity(app);
app.root.addChild(replace);
replace.name = "ReplaceSkinned";
replace.enabled = true;
_.forEachRight(byMaterial, function (list, materialIndex) {
console.log(materialIndex);
var material = list[0].material;
var combined = new pc.Entity();
replace.addChild(combined);
combined.addComponent('model');
combined.addComponent('script', {
scripts: [{url:'meshfixer.js'}]
});
combined.enabled = true;
window.allCombined.push(combined);
var pos = [];
var uv = [];
var normal = [];
var indices = [];
var tangents = [];
var blendIndices = [];
var blendWeights = [];
var bindPoses = [];
var p = 0;
var ind = 0;
var bones = [];
var boneEntities = [];
var root = new pc.scene.GraphNode();
//Now loop through and transform everything
list.forEach(function (m, index) {
//Add a bone for this object
var bone = new pc.Entity();
boneEntities.push(bone);
bone.name = 'bone_' + nextId + '_' + index;
bones.push(bone.name);
root.addChild(bone);
//Add a bind pose which is the matrix of the original object
var mat = m.model.entity.getWorldTransform();
bindPoses.push(mat);
var vb = m.mesh.mesh.vertexBuffer;
var ib = m.mesh.mesh.indexBuffer[pc.RENDERSTYLE_SOLID];
var iblocked = ib.lock();
var indexes = new Uint16Array(iblocked);
var locked = vb.lock();
var format = vb.getFormat();
var base = m.mesh.mesh.primitive[0].base;
var stride = format.size / 4;
var data = {};
for (j = 0; j < format.elements.length; j++) {
var element = format.elements[j];
var resolver = validTypes[element.name];
if (resolver) {
data[element.name] = resolver(locked, element);
}
}
var positions = data["POSITION"];
var t = p;
//Make room for the new ones
for (var i = 0; i < Math.floor(positions.length / stride); i++) {
pos.push(0);
pos.push(0);
pos.push(0);
uv.push(0);
uv.push(0);
tangents.push(0);
tangents.push(0);
tangents.push(0);
normal.push(0);
normal.push(0);
normal.push(0);
//Give this vertex weighting to the sequenced bone
blendIndices.push(index);
blendIndices.push(0);
blendIndices.push(0);
blendIndices.push(0);
blendWeights.push(1.0);
blendWeights.push(0);
blendWeights.push(0);
blendWeights.push(0);
}
var tv;
for (i = 0; i < positions.length; i += stride) {
pos[t] = positions[i];
pos[t+1] = positions[i+1];
pos[t+2] = positions[i+2];
t += 3;
}
var normals = data["NORMAL"];
t = p;
if (normals) {
for (i = 0; i < normals.length; i += stride) {
normal[t] = normals[i];
normal[t+1] = normals[i+1];
normal[t+2] = normals[i+2];
t += 3;
}
}
var uvs = data["TEXCOORD0"];
t = p / 3 * 2;
if (uvs) {
for (i = 0; i < uvs.length; i += stride, t += 2) {
uv[t] = uvs[i];
uv[t + 1] = uvs[i + 1];
}
}
var numIndices = m.mesh.mesh.primitive[0].count;
for (i = 0; i < numIndices; i++) {
indices.push(indexes[i + base] + p / 3);
}
p += (positions.length / stride) * 3;
//Turn off the existing object
m.model.entity.model.enabled = false;
vb.unlock();
ib.unlock();
});
var data;
var mesh = createMesh(app.graphicsDevice, pos, data = {
normals: normal,
uvs: uv,
indices: indices,
blendWeights: blendWeights,
blendIndices: blendIndices
});
//Create a skin
var skin = new pc.Skin(app.graphicsDevice, bindPoses, bones);
mesh.skin = skin;
var instance = new pc.scene.MeshInstance(root, mesh, material);
var model = new pc.scene.Model();
model.graph = root;
var skinInstance = new pc.SkinInstance(skin);
skinInstance.rootNode = combined;
skinInstance.bones = boneEntities;
model.meshInstances = [instance];
model.skinInstances = [skinInstance];
instance.skinInstance = skinInstance;
combined.model.model = model;
var id = nextId++;
combined.script.meshfixer.model = id;
addModel(id, model);
combined.enabled = true;
});
replace.enabled = true;
}
};
return SkinnedCombiner;
});