Random Character Texture Generator / Implementing Symmetry operation

it does have, but not sure when its run.

Plus its simpleUpdate(float tpf) not simpleUpdate()

@tralala you are not supposed to make them turn that way anyway, texture coords usually happen to be between 0 and 1, shifting it results in what looks like random (although it is really nothing strange, moving by 1 gets the old pic back again), rotating it 180 degrees won’t help you as parts that are mapped on top will end up at the bottom, thus still producing near random results, you are trying to fix a map that is correct but simply read from the back, you cannot fix that by moving the texture coordinates.



1) when i exported the model i didnt cap the holes in the middle, because i though jme will automatically fix them, like 3d studio max does. Do i have to weld them in Jme?

Yes, jME is happy to flip your models but will not think beyond that, it might be easier to work with pre-made symmetrical models instead but you probably have thought of that alreade and decided to go this way :wink:



2) it could be the normals, but from the picture with white material we can see they are ok.

Ahem, that pic which draws everthing of the model as white? That actually removes all information about the normals, as the ones on the back of the model are just as white as the front ones (looking through the wrong ones on the front and at the wrong ones on the back, that’s why you do see white and not black). Here is another idea: Simplify the texture you are using. Make sure the front of the model is say, blue, and the back is red. Then try another screenshot, if one part is blue and one part is red when viewed from the front, you are clearly in trouble on the normals.



Please note by the way, I’m trying to help you solve the problem of the model looking like it rotated instead of symmetric, not the question at the start of this post about moving UV coords, you should do that after this of course :wink:



By the way:

[java]for (int i = 0; i < normalArray.length; i += 3)

{

normalArray *= -1;

normalArray *= -1;

normalArray *= -1;

}[/java]

What’s the logic in that, stepping through the array by three and then for each value from 0 to 3 multiply by hand? :stuck_out_tongue: I think you were a bit confused there or I am missing something hehe.

Hi, i created a method that displays the model’s normals to help me fix them.



Unflipped Normals

These is how the normals look if i dont change them at all.



Normals multiplied by -1

This proves that if you multiply normals by -1, then u dont “invert” them, so initial method was wrong.



Mirrored Normals

To mirror the normal you have to find its mirrored point :



[java]

/**

  • Symmetry formula from Koen Samyn : http://knol.google.com/k/mirroring-a-point-on-a-3d-plane#
  • Same info on wikipedia : http://en.wikipedia.org/wiki/Reflection_(mathematics)

    *
  • @param p1 the Point you want to get mirrored
  • @param p the planeOrigin e.g (0,0,0)
  • @param n the planeNormal e.g Vector3f.UNIT_Z (vector that points upward from plane)

    */

    public Vector3f getSummetricPosition(Vector3f p1, Vector3f p, Vector3f n)

    {

    if (!n.isUnitVector())

    {

    throw new IllegalArgumentException(“n " + n.toString() + " is not a unit vector”);

    }

    Vector3f u = p1.subtract§;

    float distance = u.dot(n);

    Vector3f pm = p1.subtract(n.mult(2 * distance));

    return pm;

    }[/java]



    The model still looks like this.

    So that means that i have a way to mirror the uv coordinates.

Tada fixed !!!



i only changed the indexes order e.g instead of having 1,2,3 i used 3,2,1.



[java]

public void flipIndexes(Mesh mesh)

{

VertexBuffer indexes = mesh.getBuffer(Type.Index);

short[] indexArray = Utilities.getShortArray((ShortBuffer) indexes.getData());



for (int i = 0; i < indexArray.length; i += 3)

{

short index1 = indexArray;

short index2 = indexArray;

short index3 = indexArray;



indexArray = index3;

indexArray = index2;

indexArray = index1;

}

indexes.updateData(BufferUtils.createShortBuffer(indexArray));

}[/java]



Unshaded Golem front

Unshaded Golem back



Jme took care of the holes automatically, i didnt write a single line of code to hide them. No matter how close you go or whatever angle, you wont see the holes.



Poor golem it looks bad when i use “Common/MatDefs/Light/Lighting.j3md”, so no normal maps for it :frowning:

Golem with normal maps front

Golem with normal maps back



i will refactor my code to make it human readable, and will contribute it to jme, so that others can use summetry.

For the lighting thing you may need to use TangentBinormalGenerator.

Also jME does not fix any holes, it renders the exact data you give it. Garbage in → Garbage out style

i was already using TangentBinormalGenerator, its just that the vertices on the symmetry axis are not welded.



So i will also implement “slice along mirror”, and “Weld Seam”, to make it look better.

I am trying to merge 2 meshes so that i can afterwords weld them.

However i get a strange error, the mesh is displayed correctly by when i move upward a little bit it becomes invisible. What am i missing ? It didn’t have that problem before merging them.



My merging idea, i create a new array that contains the first array of mesh1, and then the second array of mesh2 for Position,Normal,TexCoord.

For indexes it contains the first array of mesh1, but for the second array of mesh2 i “move / shift” indexes by numOfVertexElements so that it starts counting from vertex1.length.

I do this because i want my mesh2 indexes to point to mesh2 vertexes not to mesh1 vertexes.



[java]public static Mesh mergeMesh(Mesh mesh1, Mesh mesh2)

{

Mesh mesh = new Mesh();

mesh.setBuffer(Type.Position, 3, merge(mesh1.getFloatBuffer(Type.Position), mesh2.getFloatBuffer(Type.Position)));

mesh.setBuffer(Type.Normal, 3, merge(mesh1.getFloatBuffer(Type.Normal), mesh2.getFloatBuffer(Type.Normal)));

mesh.setBuffer(Type.TexCoord, 2, merge(mesh1.getFloatBuffer(Type.TexCoord), mesh2.getFloatBuffer(Type.TexCoord)));

float numOfVertexElements = mesh1.getBuffer(Type.Position).getNumElements();

short[] index1 = getShortArray(mesh1.getShortBuffer(Type.Index));

short[] index2 = getShortArray(mesh2.getShortBuffer(Type.Index));

short[] resultIndex = new short[index1.length + index2.length];

System.arraycopy(index1, 0, resultIndex, 0, index1.length);

for (int i = 0; i < index2.length; i++)

{

resultIndex[index1.length + i] = (short) (index2 + numOfVertexElements);

}

mesh.setBuffer(Type.Index, 3, resultIndex);

return mesh;

}[/java]

You may need to call mesh.updateBound() to re-generate the model bounding volume

wow nice, it worked !!!

Finished “weld seam”, i still prefer the unshaded, maybe i am too used to wow that has cartoonish characters.

Model with Weld Seam

I tried to make the code work with animations, but the symmetric mesh that i create doesnt play any animations.

Only half mesh plays animations (the original half).



I copied Type.BindPosePosition, Type.BindPoseNormal, Type.BoneWeight, Type.BoneIndex on the symmetric mesh. And it still doesnt play animations. Which means that animation playing is stored somewhere else.



So how do i register the new created nodes to be affected by animations ?



My structure is : node[0] has children 0,1,2,3,4,5 and its symmetric 6,7,8,9,10,11

i play animation like this :

[java]

control = node[0].getControl(AnimControl.class);

if (control != null) //if it has animation

{

control.addListener(this);

channel = control.createChannel();

channel.setAnim("TestHands");

}[/java]

  1. you have no way to specify which nodes “control” affects. Or am i missing something ?
  2. Do i have to attach my nodes in a specific way in node[0]?