2 * Copyright (c) 2011 Kazuhiko Kobayashi All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * * Neither the name of 'MMDLoaderJME' nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
30 package projectkyoto.jme3.mmd;
32 import com.jme3.animation.Bone;
33 import com.jme3.animation.Skeleton;
34 import com.jme3.asset.AssetManager;
35 import com.jme3.material.Material;
36 import com.jme3.math.ColorRGBA;
37 import com.jme3.math.FastMath;
38 import com.jme3.math.Matrix4f;
39 import com.jme3.math.Quaternion;
40 import com.jme3.math.Vector3f;
41 import com.jme3.renderer.queue.RenderQueue.Bucket;
42 import com.jme3.scene.Geometry;
43 import com.jme3.scene.Mesh;
44 import com.jme3.scene.Node;
45 import com.jme3.scene.Spatial;
46 import com.jme3.scene.VertexBuffer;
47 import com.jme3.util.TempVars;
48 import java.nio.FloatBuffer;
49 import projectkyoto.mmd.file.PMDModel;
50 import com.jme3.scene.VertexBuffer.*;
51 import com.jme3.scene.control.BillboardControl;
52 import com.jme3.scene.debug.SkeletonWire;
53 import com.jme3.scene.shape.Box;
54 import com.jme3.shader.VarType;
55 import java.nio.ShortBuffer;
56 import java.util.Arrays;
57 import java.util.HashMap;
58 import java.util.List;
61 import projectkyoto.mmd.file.PMDBone;
62 import projectkyoto.mmd.file.PMDException;
63 import projectkyoto.mmd.file.PMDSkinVertData;
64 import projectkyoto.mmd.file.PMDVertex;
70 public class PMDNode extends Node {
75 PMDSkinMesh[] skinTargets;
76 PMDGeometry[] pmdGeometryArray;
77 Map<String, Skin> skinMap = new HashMap<String, Skin>();
78 Skin[] skinArray = new Skin[0];
79 javax.vecmath.Vector3f skinPosArray[];
80 javax.vecmath.Vector3f skinNormalArray[];
81 javax.vecmath.Vector3f skinPosArrayOrig[];
82 javax.vecmath.Vector3f skinNormalArrayOrig[];
83 float skinBoneWeightArray[];
85 AssetManager assetManager;
86 Matrix4f[] offsetMatrices;
87 boolean updateNeeded = true;
88 boolean skinUpdateNeeded = true;
89 boolean wireFrame = false;
90 float edgeSize = 1.0f;
91 boolean skeletonWireVisible = false;
92 Geometry skeletonWireGeom;
93 boolean bonePositionVisible = false;
94 Node bonePositionNode;
95 Geometry bonePositionGeomArray[];
98 boolean glslSkinning = true;
100 public PMDNode(String name, PMDModel pmdModel, AssetManager assetManager) {
102 this.pmdModel = pmdModel;
103 this.assetManager = assetManager;
111 // initRigidBodyArray();
116 void setSkinData(PMDSkinMesh[] skinTargets, List<PMDVertex> skinVertexList, Skin[] skinAray) {
117 this.skinTargets = skinTargets;
118 for (Skin skin : skinAray) {
119 skinMap.put(skin.getSkinName(), skin);
121 int skinVertSize = skinVertexList.size();
122 skinPosArray = new javax.vecmath.Vector3f[skinVertSize];
123 skinNormalArray = new javax.vecmath.Vector3f[skinVertSize];
124 skinPosArrayOrig = new javax.vecmath.Vector3f[skinVertSize];
125 skinNormalArrayOrig = new javax.vecmath.Vector3f[skinVertSize];
126 skinBoneWeightArray = new float[skinVertSize];
127 skinBoneArray = new int[skinVertSize * 2];
128 for (int i = 0; i < skinVertSize; i++) {
129 PMDVertex v = skinVertexList.get(i);
130 skinPosArrayOrig[i] = v.getPos();
131 skinPosArray[i] = new javax.vecmath.Vector3f(v.getPos());
132 skinNormalArrayOrig[i] = v.getNormal();
133 skinNormalArray[i] = new javax.vecmath.Vector3f(v.getNormal());
134 skinBoneWeightArray[i] = (float) v.getBoneWeight() / 100f;
135 skinBoneArray[i * 2] = v.getBoneNum1();
136 skinBoneArray[i * 2 + 1] = v.getBoneNum2();
140 public PMDModel getPmdModel() {
144 public void setPmdModel(PMDModel pmdModel) {
145 this.pmdModel = pmdModel;
148 public Matrix4f[] calcOffsetMatrices() {
149 offsetMatrices = skeleton.computeSkinningMatrices();
150 return offsetMatrices;
152 boolean setBoneMatricesFlag = true;
153 public void update() {
154 // skeleton.reset(); // reset skeleton to bind pose
158 updateNeeded = false;
159 // skeleton.updateWorldVectors();
160 // updateIKBoneRotation();
161 // here update the targets verticles if no hardware skinning supported
163 // offsetMatrices = skeleton.computeSkinningMatrices();
164 for(PMDGeometry g : pmdGeometryArray) {
165 Material m = g.getMaterial();
166 PMDMesh pmdMesh = g.pmdMesh;
167 int boneIndexArray[] = pmdMesh.getBoneIndexArray();
168 Matrix4f[] boneMatrixArray = pmdMesh.getBoneMatrixArray();
169 for (int i = pmdMesh.getBoneIndexArray().length-1; i >=0; i--) {
170 boneMatrixArray[i] = (offsetMatrices[boneIndexArray[i]]);
173 if (pmdMesh.boneMatricesParamIndex < 0) {
174 m.setParam("BoneMatrices", VarType.Matrix4Array, pmdMesh.getBoneMatrixArray());
175 pmdMesh.boneMatricesParamIndex = g.getMaterial().getParamIndex("BoneMatrices");
177 m.setParam(pmdMesh.boneMatricesParamIndex, VarType.Matrix4Array, pmdMesh.getBoneMatrixArray());
183 for (PMDMesh mesh : targets) {
184 softwareSkinUpdate(mesh);
187 // updateSkinMesh(skinTargets[0]);
188 // if (skinUpdateNeeded) {
189 // updateSkinBackData();
192 if (skeletonWireGeom != null) {
193 ((SkeletonWire) skeletonWireGeom.getMesh()).updateGeometry();
195 if (bonePositionVisible) {
196 for (int i = 0; i < bonePositionGeomArray.length; i++) {
197 Geometry bonePosGeom = bonePositionGeomArray[i];
198 // Mesh mesh = bonePosGeom.getMesh();
199 // VertexBuffer vb = mesh.getBuffer(Type.Position);
200 // FloatBuffer posBuf = (FloatBuffer)vb.getData();
202 Bone bone = skeleton.getBone(i);
203 Vector3f bonePos = bone.getModelSpacePosition();
204 // posBuf.position(0);
205 // posBuf.put(bonePos.x);
206 // posBuf.put(bonePos.y);
207 // posBuf.put(bonePos.z);
208 // vb.setUpdateNeeded();
209 // mesh.updateCounts();
210 // mesh.updateBound();
211 // bonePosGeom.setModelBound(new BoundingBox(bonePos, 10f,10f,10f));
212 // bonePosGeom.updateModelBound();
213 // bonePosGeom.setMesh(new Box(bonePos, 0.1f,0.1f,0.1f));
214 bonePosGeom.setLocalTranslation(bonePos);
219 private void swapSkinMesh() {
220 VertexBuffer vb = skinTargets[0].getBuffer(VertexBuffer.Type.Position);
221 VertexBuffer nb = skinTargets[0].getBuffer(VertexBuffer.Type.Normal);
222 skinTargets[0].skinvb2.setUpdateNeeded();
223 skinTargets[0].skinnb2.setUpdateNeeded();
224 for(PMDSkinMesh skinMesh : skinTargets) {
225 // skinMesh.clearBuffer(Type.Position);
226 // skinMesh.clearBuffer(Type.Normal);
227 skinMesh.setBuffer(skinTargets[0].getSkinvb2());
228 skinMesh.setBuffer(skinTargets[0].getSkinnb2());
230 skinTargets[0].skinvb2 = vb;
231 skinTargets[0].skinnb2 = nb;
232 vb = skinTargets[0].getBuffer(VertexBuffer.Type.Position);
233 nb = skinTargets[0].getBuffer(VertexBuffer.Type.Normal);
234 vb.setUpdateNeeded();
235 nb.setUpdateNeeded();
237 private void softwareSkinUpdate(PMDMesh mesh){
238 int maxWeightsPerVert = 2;//mesh.getMaxNumWeights();
239 int fourMinusMaxWeights = 4 - maxWeightsPerVert;
240 // Matrix4f[] offsetMatrices = mesh.getBoneMatrixArray();
242 // NOTE: This code assumes the vertex buffer is in bind pose
243 // resetToBind() has been called this frame
245 VertexBuffer vb = mesh.getBuffer(VertexBuffer.Type.Position);
246 FloatBuffer fvb = (FloatBuffer) vb.getData();
249 VertexBuffer nb = mesh.getBuffer(VertexBuffer.Type.Normal);
250 FloatBuffer fnb = (FloatBuffer) nb.getData();
253 FloatBuffer fvb2 = (FloatBuffer)mesh.getVbBackup().getData();
255 FloatBuffer fnb2 = (FloatBuffer)mesh.getNbBackup().getData();
258 // get boneIndexes and weights for mesh
259 ShortBuffer ib = (ShortBuffer) mesh.getBuffer(VertexBuffer.Type.BoneIndex).getData();
260 FloatBuffer wb = (FloatBuffer) mesh.getBuffer(VertexBuffer.Type.BoneWeight).getData();
265 // float[] weights = wb.array();
266 // short[] indices = ib.array();
269 TempVars vars = TempVars.get();
270 float[] posBuf = vars.skinPositions;
271 float[] normBuf = vars.skinNormals;
273 int iterations = (int) FastMath.ceil(fvb.capacity() / ((float)posBuf.length));
274 int bufLength = posBuf.length * 3;
275 for (int i = iterations-1; i >= 0; i--){
276 // read next set of positions and normals from native buffer
277 bufLength = Math.min(posBuf.length, fvb.remaining());
278 fvb2.get(posBuf, 0, bufLength);
279 fnb2.get(normBuf, 0, bufLength);
280 int verts = bufLength / 3;
281 int idxPositions = 0;
283 // iterate vertices and apply skinning transform for each effecting bone
284 for (int vert = verts - 1; vert >= 0; vert--){
285 float nmx = normBuf[idxPositions];
286 float vtx = posBuf[idxPositions++];
287 float nmy = normBuf[idxPositions];
288 float vty = posBuf[idxPositions++];
289 float nmz = normBuf[idxPositions];
290 float vtz = posBuf[idxPositions++];
292 float rx=0, ry=0, rz=0, rnx=0, rny=0, rnz=0;
294 for (int w = maxWeightsPerVert - 1; w >= 0; w--){
295 float weight = wb.get(idxWeights); //weights[idxWeights];
296 Matrix4f mat = mesh.getBoneMatrixArray()[ib.get(idxWeights++)];//offsetMatrices[indices[idxWeights++]];
298 rx += (mat.m00 * vtx + mat.m01 * vty + mat.m02 * vtz + mat.m03) * weight;
299 ry += (mat.m10 * vtx + mat.m11 * vty + mat.m12 * vtz + mat.m13) * weight;
300 rz += (mat.m20 * vtx + mat.m21 * vty + mat.m22 * vtz + mat.m23) * weight;
302 rnx += (nmx * mat.m00 + nmy * mat.m01 + nmz * mat.m02) * weight;
303 rny += (nmx * mat.m10 + nmy * mat.m11 + nmz * mat.m12) * weight;
304 rnz += (nmx * mat.m20 + nmy * mat.m21 + nmz * mat.m22) * weight;
307 idxWeights += fourMinusMaxWeights;
310 normBuf[idxPositions] = rnx;
311 posBuf[idxPositions++] = rx;
312 normBuf[idxPositions] = rny;
313 posBuf[idxPositions++] = ry;
314 normBuf[idxPositions] = rnz;
315 posBuf[idxPositions++] = rz;
319 // fvb.position(fvb2.position()-bufLength);
320 fvb.put(posBuf, 0, bufLength);
321 // fnb.position(fnb2.position()-bufLength);
322 fnb.put(normBuf, 0, bufLength);
324 vb.setUpdateNeeded();
325 nb.setUpdateNeeded();
328 // mesh.updateBound();
330 public void updateSkinBackData() {
331 PMDSkinMesh skinMesh = skinTargets[0];
332 VertexBuffer vb = skinMesh.getSkinvb2(); //.getBuffer(Type.Position);
333 FloatBuffer fvb = (FloatBuffer) vb.getData();
334 VertexBuffer nb = skinMesh.getSkinnb2(); //skinMesh.getBuffer(Type.Normal);
335 FloatBuffer fnb = (FloatBuffer) nb.getData();
337 for(int i=skinPosArray.length-1;i>=0;i--) {
338 skinPosArray[i].set(skinPosArrayOrig[i]);
340 for (Skin skin : skinArray) {
341 if (true || skin.isUpdateNeeded()) {
342 if (skin.getWeight() != 0f) {
343 for (PMDSkinVertData svd : skin.getSkinData().getSkinVertData()) {
344 javax.vecmath.Vector3f dist = skinPosArray[svd.getSkinVertIndex()];
345 dist.set(svd.getSkinVertPos());
346 dist.scale(skin.getWeight());
347 dist.add(skinPosArrayOrig[svd.getSkinVertIndex()]);
350 skin.setUpdateNeeded(false);
356 TempVars vars = TempVars.get();
357 for (int i = 0; i < skinPosArray.length; i++) {
360 float[] posBuf = vars.skinPositions;
361 float[] normBuf = vars.skinNormals;
363 // read next set of positions and normals from native buffer
364 int idxPositions = 0;
366 // iterate vertices and apply skinning transform for each effecting bone
367 float nmx = skinNormalArray[i].x;//normBuf[idxPositions];
368 float vtx = skinPosArray[i].x;//posBuf[idxPositions++];
369 float nmy = skinNormalArray[i].y;//normBuf[idxPositions];
370 float vty = skinPosArray[i].y;//posBuf[idxPositions++];
371 float nmz = skinNormalArray[i].z;//normBuf[idxPositions];
372 float vtz = skinPosArray[i].z;//posBuf[idxPositions++];
374 float rx = 0, ry = 0, rz = 0, rnx = 0, rny = 0, rnz = 0;
376 for (int w = 2 - 1; w >= 0; w--) {
377 float weight = skinBoneWeightArray[i];//(float) v.getBoneWeight();//weights[idxWeights];
379 weight = 1f - weight;
381 //weight = weight / 100f;
383 Matrix4f mat = offsetMatrices[skinBoneArray[i * 2 + w]];
385 rx += (mat.m00 * vtx + mat.m01 * vty + mat.m02 * vtz + mat.m03) * weight;
386 ry += (mat.m10 * vtx + mat.m11 * vty + mat.m12 * vtz + mat.m13) * weight;
387 rz += (mat.m20 * vtx + mat.m21 * vty + mat.m22 * vtz + mat.m23) * weight;
389 rnx += (nmx * mat.m00 + nmy * mat.m01 + nmz * mat.m02) * weight;
390 rny += (nmx * mat.m10 + nmy * mat.m11 + nmz * mat.m12) * weight;
391 rnz += (nmx * mat.m20 + nmy * mat.m21 + nmz * mat.m22) * weight;
394 fnb.put(rnx).put(rny).put(rnz);
395 fvb.put(rx).put(ry).put(rz);
398 vb.setUpdateNeeded();
399 nb.setUpdateNeeded();
400 skinUpdateNeeded = false;
403 void updateSkinMesh(PMDSkinMesh skinMesh) {
404 VertexBuffer vb = skinMesh.getBuffer(Type.Position);
405 FloatBuffer fvb = (FloatBuffer) vb.getData();
406 VertexBuffer nb = skinMesh.getBuffer(Type.Normal);
407 FloatBuffer fnb = (FloatBuffer) nb.getData();
409 for (Skin skin : skinArray) {
410 if (skin.isUpdateNeeded()) {
411 if (skin.getWeight() != 1f) {
412 for (PMDSkinVertData svd : skin.getSkinData().getSkinVertData()) {
413 javax.vecmath.Vector3f dist = skinPosArray[svd.getSkinVertIndex()];
414 dist.set(svd.getSkinVertPos());
415 dist.scale(skin.getWeight());
416 dist.add(skinPosArrayOrig[svd.getSkinVertIndex()]);
419 skin.setUpdateNeeded(false);
425 TempVars vars = TempVars.get();
426 for (int i = 0; i < skinPosArray.length; i++) {
429 float[] posBuf = vars.skinPositions;
430 float[] normBuf = vars.skinNormals;
432 // read next set of positions and normals from native buffer
433 int idxPositions = 0;
435 // iterate vertices and apply skinning transform for each effecting bone
436 float nmx = skinNormalArray[i].x;//normBuf[idxPositions];
437 float vtx = skinPosArray[i].x;//posBuf[idxPositions++];
438 float nmy = skinNormalArray[i].y;//normBuf[idxPositions];
439 float vty = skinPosArray[i].y;//posBuf[idxPositions++];
440 float nmz = skinNormalArray[i].z;//normBuf[idxPositions];
441 float vtz = skinPosArray[i].z;//posBuf[idxPositions++];
443 float rx = 0, ry = 0, rz = 0, rnx = 0, rny = 0, rnz = 0;
445 for (int w = 2 - 1; w >= 0; w--) {
446 float weight = skinBoneWeightArray[i];//(float) v.getBoneWeight();//weights[idxWeights];
448 weight = 1f - weight;
450 //weight = weight / 100f;
452 Matrix4f mat = offsetMatrices[skinBoneArray[i * 2 + w]];
454 rx += (mat.m00 * vtx + mat.m01 * vty + mat.m02 * vtz + mat.m03) * weight;
455 ry += (mat.m10 * vtx + mat.m11 * vty + mat.m12 * vtz + mat.m13) * weight;
456 rz += (mat.m20 * vtx + mat.m21 * vty + mat.m22 * vtz + mat.m23) * weight;
458 rnx += (nmx * mat.m00 + nmy * mat.m01 + nmz * mat.m02) * weight;
459 rny += (nmx * mat.m10 + nmy * mat.m11 + nmz * mat.m12) * weight;
460 rnz += (nmx * mat.m20 + nmy * mat.m21 + nmz * mat.m22) * weight;
463 fnb.put(rnx).put(rny).put(rnz);
464 fvb.put(rx).put(ry).put(rz);
467 vb.setUpdateNeeded();
468 nb.setUpdateNeeded();
471 public void resetToBind() {
472 for (int i = 0; i < skeleton.getBoneCount(); i++) {
473 Bone bone = skeleton.getBone(i);
474 PMDBone pmdBone = pmdModel.getBoneList().getBones()[i];
475 if (pmdBone.getParentBoneIndex() < skeleton.getBoneCount()) {
476 Bone parentBone = skeleton.getBone(pmdBone.getParentBoneIndex());
477 PMDBone parentPMDBone = pmdModel.getBoneList().getBones()[pmdBone.getParentBoneIndex()];
478 // parentBone.addChild(bone);
479 Vector3f v1 = new Vector3f();
480 Vector3f v2 = new Vector3f();
481 v1.set(pmdBone.getBoneHeadPos().x, pmdBone.getBoneHeadPos().y, pmdBone.getBoneHeadPos().z);
482 v2.set(parentPMDBone.getBoneHeadPos().x, parentPMDBone.getBoneHeadPos().y, parentPMDBone.getBoneHeadPos().z);
483 v1.subtractLocal(v2);
485 bone.setBindTransforms(v1, Quaternion.IDENTITY, new Vector3f(1, 1, 1));
487 Vector3f v1 = new Vector3f();
488 v1.set(pmdBone.getBoneHeadPos().x, pmdBone.getBoneHeadPos().y, pmdBone.getBoneHeadPos().z);
489 bone.setBindTransforms(v1, Quaternion.IDENTITY, new Vector3f(1, 1, 1));
492 for (PMDMesh mesh : targets) {
495 for (Skin skin : skinArray) {
498 setUpdateNeeded(true);
501 void resetToBind(PMDMesh mesh) {
503 void _resetToBind(PMDMesh mesh) {
504 VertexBuffer vb = mesh.getBuffer(VertexBuffer.Type.Position);
505 FloatBuffer vfb = (FloatBuffer) vb.getData();
506 VertexBuffer nb = mesh.getBuffer(VertexBuffer.Type.Normal);
507 FloatBuffer nfb = (FloatBuffer) nb.getData();
509 VertexBuffer bvb = mesh.getBuffer(VertexBuffer.Type.BindPosePosition);
510 FloatBuffer bvfb = (FloatBuffer) bvb.getData();
511 VertexBuffer bnb = mesh.getBuffer(VertexBuffer.Type.BindPoseNormal);
512 FloatBuffer bnfb = (FloatBuffer) bnb.getData();
514 for (int i = 0; i < vfb.capacity(); i++) {
515 vfb.put(i, bvfb.get(i));
517 for (int i = 0; i < nfb.capacity(); i++) {
518 nfb.put(i, bnfb.get(i));
520 vb.setUpdateNeeded();
521 nb.setUpdateNeeded();
523 void resetToBindSkinBackData(PMDSkinMesh mesh) {
524 VertexBuffer vb = mesh.getSkinvb2(); // mesh.getBuffer(VertexBuffer.Type.Position);
525 FloatBuffer vfb = (FloatBuffer) vb.getData();
526 VertexBuffer nb = mesh.getSkinnb2(); //mesh.getBuffer(VertexBuffer.Type.Normal);
527 FloatBuffer nfb = (FloatBuffer) nb.getData();
529 VertexBuffer bvb = mesh.getBuffer(VertexBuffer.Type.BindPosePosition);
530 FloatBuffer bvfb = (FloatBuffer) bvb.getData();
531 VertexBuffer bnb = mesh.getBuffer(VertexBuffer.Type.BindPoseNormal);
532 FloatBuffer bnfb = (FloatBuffer) bnb.getData();
534 for (int i = 0; i < vfb.capacity(); i++) {
535 vfb.put(i, bvfb.get(i));
537 for (int i = 0; i < nfb.capacity(); i++) {
538 nfb.put(i, bnfb.get(i));
540 vb.setUpdateNeeded();
541 nb.setUpdateNeeded();
543 public Set<String> getSkinSet() {
544 return skinMap.keySet();
546 public Map<String, Skin> getSkinMap() {
550 public float getSkinWeight(String skinName) {
551 return skinMap.get(skinName).getWeight();
554 public void setSkinWeight(String skinName, float weight) {
555 Skin skin = skinMap.get(skinName);
557 skin.setWeight(weight);
558 skinUpdateNeeded = true;
559 // for (PMDSkinVertData svd : skin.getSkinData().getSkinVertData()) {
560 // javax.vecmath.Vector3f dist = skinPosArray[svd.getSkinVertIndex()];
561 // dist.set(svd.getSkinVertPos());
562 // dist.scale(weight);
563 // dist.add(skinPosArrayOrig[svd.getSkinVertIndex()]);
568 public boolean isUpdateNeeded() {
572 public void setUpdateNeeded(boolean updateNeeded) {
573 this.updateNeeded = updateNeeded;
576 public Skeleton getSkeleton() {
580 public void setSkeleton(Skeleton skeleton) {
581 this.skeleton = skeleton;
584 public void setWireFrame(boolean wireFrame) {
585 for (Spatial sp : getChildren()) {
586 if (sp instanceof Geometry) {
587 Geometry geom = (Geometry) sp;
588 geom.getMaterial().getAdditionalRenderState().setWireframe(wireFrame);
591 this.wireFrame = wireFrame;
594 public boolean isWireFrame() {
598 public void setEdgeWidth(float edgeSize) {
599 for (Spatial sp : getChildren()) {
600 if (sp instanceof PMDGeometry) {
601 PMDGeometry geom = (PMDGeometry) sp;
602 if (geom.getPmdMaterial().getEdgeFlag() != 0) {
603 geom.getMaterial().setFloat("EdgeSize", edgeSize);
607 this.edgeSize = edgeSize;
610 public void setSkeletonWireVisible(boolean skeletonWireVisible) {
611 if (skeletonWireVisible) {
612 if (skeletonWireGeom == null) {
613 SkeletonWire skeletonWire = new SkeletonWire(skeleton);
614 skeletonWireGeom = new Geometry("skeletonWire", skeletonWire);
615 Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
616 mat.setColor("Color", ColorRGBA.Green);
617 mat.getAdditionalRenderState().setDepthTest(false);
618 mat.getAdditionalRenderState().setDepthWrite(false);
619 skeletonWireGeom.setMaterial(mat);
620 skeletonWireGeom.setQueueBucket(Bucket.Transparent);
621 attachChild(skeletonWireGeom);
622 skeletonWire.updateGeometry();
625 if (skeletonWireGeom != null) {
626 skeletonWireGeom.removeFromParent();
627 skeletonWireGeom = null;
630 this.skeletonWireVisible = skeletonWireVisible;
633 public void setBonePositionVisible(boolean bonePositionVisible) {
634 if (bonePositionVisible) {
635 if (bonePositionNode == null) {
636 bonePositionNode = new Node("bonePositionNode");
637 bonePositionGeomArray = new Geometry[pmdModel.getBoneList().getBoneCount()];
638 Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
639 mat.setColor("Color", ColorRGBA.Red);
640 mat.getAdditionalRenderState().setDepthTest(false);
641 mat.getAdditionalRenderState().setDepthWrite(false);
642 Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
643 mat2.setColor("Color", ColorRGBA.Blue);
644 mat2.getAdditionalRenderState().setDepthTest(false);
645 mat2.getAdditionalRenderState().setDepthWrite(false);
646 Material mat3 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
647 mat3.setColor("Color", ColorRGBA.Green);
648 mat3.getAdditionalRenderState().setDepthTest(false);
649 mat3.getAdditionalRenderState().setDepthWrite(false);
650 for (int i = 0; i < bonePositionGeomArray.length; i++) {
651 Mesh mesh = new Mesh();
652 // mesh.setMode(Mesh.Mode.Points);
653 // VertexBuffer pb = new VertexBuffer(Type.Position);
654 // FloatBuffer fpb = BufferUtils.createFloatBuffer(3);
655 // fpb.put(0f).put(0f).put(0f);
656 // pb.setupData(Usage.Static, 3, Format.Float, fpb);
657 // mesh.setBuffer(pb);
658 // mesh.setPointSize(7);
659 // mesh.updateCounts();
660 Geometry geom = new Geometry(pmdModel.getBoneList().getBones()[i].getBoneName(), new Box(0.1f, 0.1f, 0.0f));
661 geom.setMaterial(mat);
662 geom.setQueueBucket(Bucket.Transparent);
663 bonePositionGeomArray[i] = geom;
664 bonePositionNode.attachChild(geom);
665 geom.addControl(new BillboardControl());
666 if (pmdModel.getBoneList().getBones()[i].getBoneType() == 2) {
667 geom.setMaterial(mat2);
669 if (pmdModel.getBoneList().getBones()[i].getBoneType() == 6) {
670 geom.setMaterial(mat3);
673 attachChild(bonePositionNode);
677 if (bonePositionNode != null) {
678 bonePositionNode.removeFromParent();
679 bonePositionNode = null;
680 bonePositionGeomArray = null;
683 setUpdateNeeded(true);
684 this.bonePositionVisible = bonePositionVisible;
687 public Node getBonePositionNode() {
688 return bonePositionNode;
691 public Matrix4f[] getOffsetMatrices() {
692 return offsetMatrices;
695 public void setRigidBodyVisible(boolean flag) {
697 if (rigidBodyNode != null) {
700 RigidBodyConverter rbc = new RigidBodyConverter(pmdModel, assetManager);
701 rigidBodyNode = rbc.convert("rigidBody");
702 attachChild(rigidBodyNode);
704 if (rigidBodyNode != null) {
705 detachChild(rigidBodyNode);
706 rigidBodyNode = null;
711 public Node getRigidBodyNode() {
712 return rigidBodyNode;
715 // PMDRigidBody rigidBodyArray[];
717 void initMaterials() {
718 for (Spatial sp : getChildren()) {
719 if (sp instanceof PMDGeometry) {
720 PMDGeometry geom = (PMDGeometry) sp;
721 Mesh mesh = geom.getMesh();
722 if (mesh instanceof PMDMesh) {
724 geom.setMaterial(geom.getGlslSkinningMaterial());
726 geom.setMaterial(geom.getNoSkinningMaterial());
733 public Node getJointNode() {
737 public void setJointNode(Node jointNode) {
738 this.jointNode = jointNode;
741 // PMDRigidBody createRigidBody(projectkyoto.mmd.file.PMDRigidBody fileRigidBody, Bone bone) {
744 public boolean isGlslSkinning() {
748 public void setGlslSkinning(boolean glslSkinning) {
749 this.glslSkinning = glslSkinning;
750 for (Spatial sp : getChildren()) {
751 if (sp instanceof PMDGeometry) {
752 Mesh mesh = ((PMDGeometry) sp).getMesh();
753 if (mesh instanceof PMDMesh) {
754 PMDMesh pmdMesh = (PMDMesh)mesh;
755 resetToBind(pmdMesh);
757 pmdMesh.releaseSoftwareSkinningBufferes();
758 mesh.getBuffer(Type.Position).setUsage(Usage.Static);
759 mesh.getBuffer(Type.Normal).setUsage(Usage.Static);
761 pmdMesh.createSoftwareSkinningBuffers();
762 mesh.getBuffer(Type.Position).setUsage(Usage.Dynamic);
763 mesh.getBuffer(Type.Normal).setUsage(Usage.Dynamic);
772 public boolean equals(Object obj) {
780 public int hashCode() {
781 return pmdModel.getModelName().hashCode();
785 public PMDNode clone() {
787 PMDNode newPMDNode = (PMDNode)super.clone();
788 // newPMDNode.pmdModel = pmdModel;
789 newPMDNode.skeleton = new Skeleton(skeleton);
790 for(int i=0;i<skeleton.getBoneCount();i++) {
791 Bone newBone = newPMDNode.skeleton.getBone(i);
792 Bone bone = skeleton.getBone(i);
793 newBone.getLocalPosition().set(bone.getLocalPosition());
794 newBone.getLocalRotation().set(bone.getLocalRotation());
795 newBone.getLocalScale().set(bone.getLocalScale());
797 newPMDNode.targets = new PMDMesh[targets.length];
798 newPMDNode.skinTargets = new PMDSkinMesh[skinTargets.length];
800 int skinMeshCount = 0;
801 for(Spatial sp : newPMDNode.getChildren()) {
802 Spatial newSp = sp;//.clone();
803 // newPMDNode.attachChild(newSp);
804 if (sp instanceof PMDGeometry) {
805 Mesh mesh = ((Geometry)newSp).getMesh();
806 if (mesh instanceof PMDMesh) {
807 pmdGeometryArray[meshCount] = (PMDGeometry)sp;
808 newPMDNode.targets[meshCount++] = (PMDMesh)mesh;
809 } else if (mesh instanceof PMDSkinMesh) {
810 newPMDNode.skinTargets[skinMeshCount++] = (PMDSkinMesh)mesh;
814 newPMDNode.skinMap = new HashMap<String, Skin>();
815 for(String skinName : skinMap.keySet()) {
816 Skin skin = skinMap.get(skinName);
818 newPMDNode.skinMap.put(skinName, skin);
820 newPMDNode.skinArray = newPMDNode.skinMap.values().toArray(new Skin[newPMDNode.skinMap.size()]);
821 newPMDNode.skinPosArray = new javax.vecmath.Vector3f[skinPosArray.length];
822 for(int i=0;i<skinPosArray.length;i++) {
823 newPMDNode.skinPosArray[i] = new javax.vecmath.Vector3f(skinPosArray[i]);
825 newPMDNode.skinNormalArray = new javax.vecmath.Vector3f[skinNormalArray.length];
826 for(int i=0;i<skinNormalArray.length;i++) {
827 newPMDNode.skinNormalArray[i] = new javax.vecmath.Vector3f(skinNormalArray[i]);
829 // newPMDNode.offsetMatrices = new Matrix4f[offsetMatrices.length];
830 newPMDNode.setGlslSkinning(newPMDNode.glslSkinning);
831 newPMDNode.skeleton.updateWorldVectors();
832 newPMDNode.calcOffsetMatrices();
833 newPMDNode.updateSkinBackData();
835 newPMDNode.updateSkinBackData();
838 } catch(CloneNotSupportedException ex) {
839 throw new PMDException(ex);