playcanvas
Version:
PlayCanvas WebGL game engine
171 lines (168 loc) • 6.32 kB
JavaScript
import { RENDERSTYLE_WIREFRAME } from './constants.js';
import { MeshInstance } from './mesh-instance.js';
import { MorphInstance } from './morph-instance.js';
import { SkinInstance } from './skin-instance.js';
/**
* @import { GraphNode } from './graph-node.js'
*/ /**
* A model is a graphical object that can be added to or removed from a scene. It contains a
* hierarchy and any number of mesh instances.
*
* @category Graphics
*/ class Model {
getGraph() {
return this.graph;
}
setGraph(graph) {
this.graph = graph;
}
getCameras() {
return this.cameras;
}
setCameras(cameras) {
this.cameras = cameras;
}
getLights() {
return this.lights;
}
setLights(lights) {
this.lights = lights;
}
getMaterials() {
var materials = [];
for(var i = 0; i < this.meshInstances.length; i++){
var meshInstance = this.meshInstances[i];
if (materials.indexOf(meshInstance.material) === -1) {
materials.push(meshInstance.material);
}
}
return materials;
}
/**
* Clones a model. The returned model has a newly created hierarchy and mesh instances, but
* meshes are shared between the clone and the specified model.
*
* @returns {Model} A clone of the specified model.
* @example
* const clonedModel = model.clone();
*/ clone() {
// Duplicate the node hierarchy
var srcNodes = [];
var cloneNodes = [];
var _duplicate = function _duplicate1(node) {
var newNode = node.clone();
srcNodes.push(node);
cloneNodes.push(newNode);
for(var idx = 0; idx < node._children.length; idx++){
newNode.addChild(_duplicate(node._children[idx]));
}
return newNode;
};
var cloneGraph = _duplicate(this.graph);
var cloneMeshInstances = [];
var cloneSkinInstances = [];
var cloneMorphInstances = [];
// Clone the skin instances
for(var i = 0; i < this.skinInstances.length; i++){
var skin = this.skinInstances[i].skin;
var cloneSkinInstance = new SkinInstance(skin);
// Resolve bone IDs to actual graph nodes
var bones = [];
for(var j = 0; j < skin.boneNames.length; j++){
var boneName = skin.boneNames[j];
var bone = cloneGraph.findByName(boneName);
bones.push(bone);
}
cloneSkinInstance.bones = bones;
cloneSkinInstances.push(cloneSkinInstance);
}
// Clone the morph instances
for(var i1 = 0; i1 < this.morphInstances.length; i1++){
var morph = this.morphInstances[i1].morph;
var cloneMorphInstance = new MorphInstance(morph);
cloneMorphInstances.push(cloneMorphInstance);
}
// Clone the mesh instances
for(var i2 = 0; i2 < this.meshInstances.length; i2++){
var meshInstance = this.meshInstances[i2];
var nodeIndex = srcNodes.indexOf(meshInstance.node);
var cloneMeshInstance = new MeshInstance(meshInstance.mesh, meshInstance.material, cloneNodes[nodeIndex]);
if (meshInstance.skinInstance) {
var skinInstanceIndex = this.skinInstances.indexOf(meshInstance.skinInstance);
cloneMeshInstance.skinInstance = cloneSkinInstances[skinInstanceIndex];
}
if (meshInstance.morphInstance) {
var morphInstanceIndex = this.morphInstances.indexOf(meshInstance.morphInstance);
cloneMeshInstance.morphInstance = cloneMorphInstances[morphInstanceIndex];
}
cloneMeshInstances.push(cloneMeshInstance);
}
var clone = new Model();
clone.graph = cloneGraph;
clone.meshInstances = cloneMeshInstances;
clone.skinInstances = cloneSkinInstances;
clone.morphInstances = cloneMorphInstances;
clone.getGraph().syncHierarchy();
return clone;
}
/**
* Destroys skinning texture and possibly deletes vertex/index buffers of a model. Mesh is
* reference-counted, so buffers are only deleted if all models with referencing mesh instances
* were deleted. That means all in-scene models + the "base" one (asset.resource) which is
* created when the model is parsed. It is recommended to use asset.unload() instead, which
* will also remove the model from the scene.
*/ destroy() {
var meshInstances = this.meshInstances;
for(var i = 0; i < meshInstances.length; i++){
meshInstances[i].destroy();
}
this.meshInstances.length = 0;
}
/**
* Generates the necessary internal data for a model to be renderable as wireframe. Once this
* function has been called, any mesh instance in the model can have its renderStyle property
* set to {@link RENDERSTYLE_WIREFRAME}.
*
* @example
* model.generateWireframe();
* for (let i = 0; i < model.meshInstances.length; i++) {
* model.meshInstances[i].renderStyle = pc.RENDERSTYLE_WIREFRAME;
* }
*/ generateWireframe() {
MeshInstance._prepareRenderStyleForArray(this.meshInstances, RENDERSTYLE_WIREFRAME);
}
/**
* Creates a new model.
*
* @example
* // Create a new model
* const model = new pc.Model();
*/ constructor(){
/**
* The root node of the model's graph node hierarchy.
*
* @type {GraphNode|null}
*/ this.graph = null;
/**
* An array of MeshInstances contained in this model.
*
* @type {MeshInstance[]}
*/ this.meshInstances = [];
/**
* An array of SkinInstances contained in this model.
*
* @type {SkinInstance[]}
*/ this.skinInstances = [];
/**
* An array of MorphInstances contained in this model.
*
* @type {MorphInstance[]}
*/ this.morphInstances = [];
this.cameras = [];
this.lights = [];
this._shadersVersion = 0;
// used by the model component to flag that this model has been assigned
this._immutable = false;
}
}
export { Model };