Author Topic: How to Fill SkinData  (Read 4365 times)

Offline AGP

  • quad
  • ******
  • Posts: 1524
    • View Profile
How to Fill SkinData
« on: June 16, 2016, 06:44:26 am »
I've exported into a JSON-serialized format of my creation all the weights of all the joints in each vertex. How, now, do I fill the 2-dimensional arrays that are weights and jointIndices? Thanks in advance.

Offline raft

  • Moderator
  • quad
  • *****
  • Posts: 1971
    • View Profile
    • http://www.aptalkarga.com
Re: How to Fill SkinData
« Reply #1 on: June 16, 2016, 09:56:52 am »
MAX_JOINTS_PER_VERTEX = 4

jointIndices is a [mesh size][MAX_JOINTS_PER_VERTEX] short array, describing which joints in skeleton is affecting each vertex.

weights is a [mesh size][MAX_JOINTS_PER_VERTEX] float array, describing how much each vertex is affected by corresponding joint in skeleton. if weight is zero, no calculation is done and corresponding jointIndex is irrelevant.

Offline AGP

  • quad
  • ******
  • Posts: 1524
    • View Profile
Re: How to Fill SkinData
« Reply #2 on: June 17, 2016, 11:51:46 am »
I have filled arrays with the Bone and BoneReference classes below. How would you fill your arrays given this data? The following was my first, unsuccessful attempt (I don't understand how the data is arranged in your arrays, and I assumed that mesh_size is maxTriangles).

Code: [Select]
float[][] weights = new float[maxTriangles][Skeleton.MAX_JOINTS_PER_VERTEX];//Skeleton.MAX_JOINTS_PER_VERTEX IS 4
short[][] jointIndices = new short[maxTriangles][Skeleton.MAX_JOINTS_PER_VERTEX];
for (int y = 0; y < weights[0].length; y++) {
     for (int x = 0; x < weights.length; x++) {
weights[x][y] = boneRefs.get(x).vertexWeight;
jointIndices[x][y] = boneRefs.get(x).vertexIndexReference;
     }
}
class Bone {
     protected String name;
     protected SimpleVector position;
     protected Matrix transform;
     protected int index, parentIndex;
     public Bone(String name, SimpleVector position, Matrix transform, int index, int parentIndex) {
this.name = name;
this.position = position;
this.transform = transform;
this.index = index;
this.parentIndex = parentIndex;
     }
}
class BoneReference {
     public short vertexIndexReference;
     public short boneIndexReference;
     public float vertexWeight;
     public BoneReference(short vertexIndexReference, short boneIndexReference, float vertexWeight) {
          this.vertexIndexReference = vertexIndexReference;
          this.boneIndexReference = boneIndexReference;
          this.vertexWeight = vertexWeight;
     }
}
« Last Edit: June 17, 2016, 12:29:14 pm by AGP »

Offline raft

  • Moderator
  • quad
  • *****
  • Posts: 1971
    • View Profile
    • http://www.aptalkarga.com
Re: How to Fill SkinData
« Reply #3 on: June 17, 2016, 12:12:53 pm »
Code: [Select]
weights[x][y] = boneRefs.get(x).vertexWeight;
jointIndices[x][y] = boneRefs.get(x).vertexIndexReference;

if I understand your stucture correct, these should be just the opposite.

Code: [Select]
jointIndices[x][y] says vertex x is influenced by joint y, NOT joint x influences vertex y. similar for weights.

looks like you shoud loop over boneRefs and fill in jointIndices and weights accordingly. not the other way around

Offline AGP

  • quad
  • ******
  • Posts: 1524
    • View Profile
Re: How to Fill SkinData
« Reply #4 on: June 17, 2016, 12:24:57 pm »
OK, but if I do
Code: [Select]
for (int i = 0; i < boneRefs.size(); i++)
then, what's y in

Code: [Select]
jointIndices[i][y] = boneRefs.get(i).vertexIndexReference? I can't seem to visualize the 2d array as you designed it.
« Last Edit: June 17, 2016, 12:28:31 pm by AGP »

Offline raft

  • Moderator
  • quad
  • *****
  • Posts: 1971
    • View Profile
    • http://www.aptalkarga.com
Re: How to Fill SkinData
« Reply #5 on: June 17, 2016, 12:37:40 pm »
you cant do that in a single iteration IMHO.*

first iterate over boneRefs to collect vertex-bone relations

Code: [Select]
map = Map<Integer, List<Integer>>();
for (b: boneRefs) {
  map.get(b.vertexIndexReference).add(b.boneIndexReference);
}

then loop over your map to place into jointIndices array. sth like this

Code: [Select]
for (e : map.entrySet) {
  count = 0;
  for (index : e.value) {
    jointIndices[e.key][count++] = index;
  }
}

hope this helps
r a f t

(*) actually you can but will be ugly

Offline AGP

  • quad
  • ******
  • Posts: 1524
    • View Profile
Re: How to Fill SkinData
« Reply #6 on: June 17, 2016, 01:26:25 pm »
Same confusion: between

Code: [Select]
HashMap<Integer, java.util.List<Integer>> map = new HashMap<Integer, java.util.List<Integer>>();
for (BoneReference b: boneRefs)
and
Code: [Select]
     map.get(b.vertexIndexReference).add((int)b.boneIndexReference);
//then loop over your map to place into jointIndices array. sth like this
for (Map.Entry<Integer, java.util.List<Integer>> e : map.entrySet()) {
     int count = 0;
     for (Integer index : e.getValue())//index : e.value
jointIndices[e.getKey()][count++] = index.shortValue();
}
how do I fill the HashMap?

Offline raft

  • Moderator
  • quad
  • *****
  • Posts: 1971
    • View Profile
    • http://www.aptalkarga.com
Re: How to Fill SkinData
« Reply #7 on: June 17, 2016, 01:50:28 pm »
it's written above AGP, in the first iteration

Code: [Select]
map = Map<Integer, List<Integer>>();
for (b: boneRefs) {
  map.get(b.vertexIndexReference).add(b.boneIndexReference);
}

but of course you should first create the list if it's null

Offline AGP

  • quad
  • ******
  • Posts: 1524
    • View Profile
Re: How to Fill SkinData
« Reply #8 on: June 17, 2016, 01:57:22 pm »
boneRefs is neither null nor size 0. But map.get(b.vertexIndexReference).add((int)b.boneIndexReference) produces a NullPointerExecption (because get(...) returns a null value).

Offline raft

  • Moderator
  • quad
  • *****
  • Posts: 1971
    • View Profile
    • http://www.aptalkarga.com
Re: How to Fill SkinData
« Reply #9 on: June 17, 2016, 01:58:38 pm »
but of course you should first create the list if it's null

Code: [Select]
map = Map<Integer, List<Integer>>();
for (b: boneRefs) {
  list = map.get(b.vertexIndexReference);
  if (list == null) {
    list = new ArrayList<Integer>();
    map.put(b.vertexIndexReference, list);
  }
  list.add(b.boneIndexReference);
}

Offline AGP

  • quad
  • ******
  • Posts: 1524
    • View Profile
Re: How to Fill SkinData
« Reply #10 on: June 17, 2016, 02:22:24 pm »
Ah, there you go. Thanks for holding my hand. I've no experience with hash maps. It's working now. Next step, animation!

Offline iguatemi

  • byte
  • *
  • Posts: 9
    • View Profile
Re: How to Fill SkinData
« Reply #11 on: July 20, 2016, 11:50:37 pm »
Hey, guys.
I'm working with AGP and I got stuck.

About the weights and jointsIndices, I'm not sure if I got it right. Here is how I'm building the skin data:
Code: [Select]
float[][] weights = new float[vertices.size()][Skeleton.MAX_JOINTS_PER_VERTEX];
short[][] jointIndices = new short[bones.size()][Skeleton.MAX_JOINTS_PER_VERTEX];
int[] weightCounters = new int[vertices.size()];
int[] jointIndicesCounters = new int[bones.size()];

for (BoneReference aBoneRef: boneRefs) {
    int weightCounter = weightCounters[aBoneRef.vertexIndexReference];
    if (weightCounter < Skeleton.MAX_JOINTS_PER_VERTEX) {
        weights[aBoneRef.vertexIndexReference][weightCounter] = aBoneRef.vertexWeight;
        weightCounters[aBoneRef.vertexIndexReference]++;
    }
    int jointIndicesCounter = jointIndicesCounters[aBoneRef.boneIndexReference];
    if (jointIndicesCounter < Skeleton.MAX_JOINTS_PER_VERTEX) {
        jointIndices[aBoneRef.boneIndexReference][jointIndicesCounter] = aBoneRef.vertexIndexReference;
        jointIndicesCounters[aBoneRef.boneIndexReference]++;
    }
}

Everything goes well untill I try to  applySkeletonPose. I get index out of bounds.

Code: [Select]
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 249
at raft.jpct.bones.Animated3D.applySkeletonPose(Animated3D.java:523)
at Importer.loop(Importer.java:344)
at Importer.<init>(Importer.java:56)
at Importer.main(Importer.java:422)


I'm using the SkeletonDebugger to check the bones and they're look fine.

Do you have any idea on how to make it work?

Thanks!

Offline raft

  • Moderator
  • quad
  • *****
  • Posts: 1971
    • View Profile
    • http://www.aptalkarga.com
Re: How to Fill SkinData
« Reply #12 on: July 22, 2016, 08:23:23 am »
it's hard to guess what your code exactly does but I've noticed a logical error. both weights' and jointIndices' first dimension is vertex index. looks like you use bone index as jointIndices' first dimension.

see the message above:
http://www.jpct.net/forum2/index.php/topic,4706.msg32344.html#msg32344

Offline AGP

  • quad
  • ******
  • Posts: 1524
    • View Profile
Re: How to Fill SkinData
« Reply #13 on: August 03, 2016, 12:21:49 am »
Joint number 9 is the left upper arm. The following code produces the following image. It looks a lot like it's a weight accuracy problem, now, doesn't it? The UVs themselves mostly work but are somewhat screwy too. I don't suppose that you would have any insight on this problem.

Code: [Select]
    else if (state.getKeyCode() == KeyEvent.VK_X) {
                         Animated3D animated = ((Animated3D)toLoad);
                         Skeleton skeleton = animated.getSkeleton();
                         SkeletonPose pose = animated.getSkeletonPose();

                         SkeletonPose pose2 = pose.clone();
                         pose2.setToBindPose();

                         int jointCount = skeleton.getNumberOfJoints();
                         pose2.getLocal(9).rotateX(1f);
                         pose2.updateTransforms();
                         animated.setSkeletonPose(pose2);
                         this.skeletonDebugger.update(pose2);
                         animated.applySkeletonPose();
                         animated.applyAnimation();
                    }


Offline raft

  • Moderator
  • quad
  • *****
  • Posts: 1971
    • View Profile
    • http://www.aptalkarga.com
Re: How to Fill SkinData
« Reply #14 on: August 10, 2016, 07:22:30 am »
I'm not sure if this is a weight accuracy problem. any progress on this one?