How to set the (VertexBuffer.Type.Color) buffer and others (Position) buffer Again and again …?

May be my question isn’t very clear … Let’s me explain:

I want my vertex Color buffer update every frame according to the relative postion of camera and the mesh … the vertices far from the camPos are darker and the near are lighter…

[java]

void initColorBuffer() {

int colorIndex = 0;

colorArray = new float[vertexCount * 4];

System.out.println(“colorArray.length :” + colorArray.length);

for (int i = 0; i < vertexCount; i++) {

colorArray[colorIndex++] = 0;

colorArray[colorIndex++] = 0;

colorArray[colorIndex++] = 0;

colorArray[colorIndex++] = 0;

}

ninjaMesh.setBuffer(Type.Color, vertexCount * 4, colorArray);

colorBuffer = ninjaMesh.getFloatBuffer(VertexBuffer.Type.Color);

System.out.println(“colorBuffer.remaining :” + colorBuffer.remaining());

}

void opps() {

float maxdis = 1000;

Vector3f camPos = cam.getLocation();

vertices = ninjaMesh.getFloatBuffer(VertexBuffer.Type.Position);

vertices.rewind();

float value = 0, valueR = 0, valueG = 0, valueB = 0, valueA = 0;

for (int i = 0; i < vertexCount; i++) {

float posx = vertices.get();

float posy = vertices.get();

float posz = vertices.get();

Vector3f vertexPos = new Vector3f(posx, posy, posz);

float dis = vertexPos.distance(camPos);

if (dis > maxdis) {

value = 0;

} else {

value = (maxdis - dis) / maxdis;

//System.out.println(" value :"+value);

valueR = value;

valueG = value;

valueB = value;

valueA = 1f;

}

}

int colorIndex = 0;

//colorArray=new float[vertexCount4];

for (int i = 0; i < vertexCount; i++) {

//colorArray[colorIndex++] = valueR;

//colorArray[colorIndex++] = valueG/2;

//colorArray[colorIndex++] = valueB/4;

//colorArray[colorIndex++] = 1f;

// Red value (is increased by .2 on each next vertex here)

colorArray[colorIndex++] = 0.1f + (.2f * i);

// Green value (is reduced by .2 on each next vertex)

colorArray[colorIndex++] = 0.9f - (0.2f * i);

// Blue value (remains the same in our case)

colorArray[colorIndex++] = 0.5f;

// Alpha value (no transparency set here)

colorArray[colorIndex++] = 1.0f;

}

colorBuffer.clear();

colorBuffer.put(colorArray);

//ninjaMesh.setBuffer(Type.Color, vertexCount
4, colorBuffer);

}

[/java]



















colorBuffer.clear();

colorBuffer.put(colorArray);



Is it the right way to get the colorBuffer update again ??? Cause I got nothing change in everyframe …

If I add this line









colorBuffer.clear();

colorBuffer.put(colorArray);

ninjaMesh.setBuffer(Type.Color, vertexCount*4, colorBuffer);













Then I get















java.lang.UnsupportedOperationException: Data has already been sent. Cannot setupData again.

at com.jme3.scene.VertexBuffer.setupData(VertexBuffer.java:369)

at com.jme3.scene.Mesh.setBuffer(Mesh.java:520)

at MyTool.animation.HelloAnimation.opps(HelloAnimation.java:288)

at MyTool.animation.HelloAnimation.simpleUpdate(HelloAnimation.java:212)

at com.jme3.app.SimpleApplication.update(SimpleApplication.java:241)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:158)

at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:203)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:221)

at java.lang.Thread.run(Thread.java:619)

I suggest you take a look at shaders for doing this, that will be much faster.



Normaly you can update data by just changing the values in the buffer and use setRefresNeeded().

@EmpirePhoenix : Of course I think about the shader solution but in this implement I want to apply a lot of “not in GPU” calculating …

Thank for your reply !

But can you tell me how “setRefreshNeeded()” work , what objects the method “setRefreshNeeded” is in ?

It should be in the mesh the buffer belongs to

T_T … I can’t find it anywhere in the mesh or buffer …?



May be the method is vanished from lastest JME code (or changed namee?? ). <= really don’t know…

my bad its in the buffer. VertexBuffer.setUpdateNeeded() or to be more specifically in the GLObject

Also when I doing like this

[java]

colorBuffer = ninjaMesh.getFloatBuffer(VertexBuffer.Type.Color);





vertices = ninjaMesh.getFloatBuffer(VertexBuffer.Type.Position);

vertices.rewind();



float value = 0, valueR = 0, valueG = 0, valueB = 0, valueA = 0;



int colorIndex = 0;

for (int i = 0; i < vertexCount; i++) {

float posx = vertices.get();

float posy = vertices.get();

float posz = vertices.get();



Vector3f vertexPos = new Vector3f(posx, posy, posz);

float dis = vertexPos.distance(camPos);

if (dis > maxdis) {

value = 0;



} else {

value = (maxdis - dis) / maxdis;

//System.out.println(" value :"+value);

valueR = value;

valueG = value;

valueB = value;

valueA = 1f;



colorArray[colorIndex++] = valueR;

colorArray[colorIndex++] = valueG/2;

colorArray[colorIndex++] = valueB/4;

colorArray[colorIndex++] = 1f;

}

}



colorBuffer.clear();

colorBuffer.put(colorArray);



ninjaMesh.getBuffer(Type.Color).setUpdateNeeded();

[/java]



not thing change in the scene …<= So may be it is not updated at all ???

I’m really confused about the internal work in the buffer …



colorBuffer = ninjaMesh.getFloatBuffer(VertexBuffer.Type.Color);

may be this line just get a clone of the Color Buffer , not the real one!



so when i put the new data back into it , not thing change ???



… Is there a method to put data into the buffer in a valid way ?

Hm actually it looks right at least for me so far, can you provide a simple testcase ?

Yeah , in fact , it’s a modified version of “HelloAnimation.java” ← I quickly made this one for the test case, my code is too long and has a lot of unnecessary things…

Please give me a run … If it’s normal in your computer , I really don’t know wth happen in mine ! :smiley:

[java]

package jme3test.helloworld;



import com.jme3.animation.AnimChannel;

import com.jme3.animation.AnimControl;

import com.jme3.animation.AnimEventListener;

import com.jme3.animation.LoopMode;

import com.jme3.app.SimpleApplication;

import com.jme3.input.KeyInput;

import com.jme3.input.controls.ActionListener;

import com.jme3.input.controls.KeyTrigger;

import com.jme3.light.DirectionalLight;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.FastMath;

import com.jme3.math.Quaternion;

import com.jme3.math.Vector3f;

import com.jme3.scene.Geometry;

import com.jme3.scene.Mesh;

import com.jme3.scene.Node;

import com.jme3.scene.VertexBuffer;

import com.jme3.scene.VertexBuffer.Type;

import java.nio.FloatBuffer;



/** Sample 7 - how to load an OgreXML model and play an animation,

  • using channels, a controller, and an AnimEventListener. /

    public class HelloAnimation extends SimpleApplication

    implements AnimEventListener {



    Node player;

    private AnimChannel channel;

    private AnimControl control;



    public static void main(String[] args) {

    HelloAnimation app = new HelloAnimation();

    app.start();

    }

    int vertexCount;

    float[] colorArray;

    Geometry ninja;

    Mesh ninjaMesh;

    FloatBuffer colorBuffer;

    FloatBuffer vertices;



    @Override

    public void simpleInitApp() {

    viewPort.setBackgroundColor(ColorRGBA.LightGray);

    initKeys();



    /
    * Add a light source so we can see the model /

    DirectionalLight dl = new DirectionalLight();

    dl.setDirection(new Vector3f(-0.1f, -1f, -1).normalizeLocal());

    rootNode.addLight(dl);



    /
    * Load a model that contains animation /

    player = (Node) assetManager.loadModel("Models/Ninja/Ninja.mesh.xml");





    float PI = FastMath.PI;

    float PI2 = FastMath.PI / 2;

    float[] angles = {0, PI, 0};



    player.setLocalRotation(new Quaternion(angles));

    player.setLocalScale(0.02f);

    rootNode.attachChild(player);



    /
    * Create a controller and channels. */

    control = player.getControl(AnimControl.class);

    control.addListener(this);

    channel = control.createChannel();

    channel.setAnim("Kick");



    // NINJA is Special !

    ninja = (Geometry) player.getChild(0);



    Material matVC = new Material(assetManager, "Common/MatDefs/Misc/VertexColor.j3md");

    matVC.setTransparent(true);

    matVC.getAdditionalRenderState().setWireframe(true);

    ninja.setMaterial(matVC);



    ninjaMesh = ninja.getMesh();

    ninjaMesh.setMode(Mesh.Mode.Points);

    ninjaMesh.setPointSize(4);

    vertexCount = ninjaMesh.getVertexCount();

    colorArray = new float[vertexCount * 4];

    initColorBuffer();





    // FINISH





}
@Override
public void simpleUpdate(float tpf) {

opps();
}

void initColorBuffer() {

vertexCount = ninjaMesh.getVertexCount();
colorArray = new float[vertexCount * 4];
int colorIndex = 0;

System.out.println("vertexCount :" + vertexCount);
//System.out.println("colorArray.length :" + colorArray.length);
for (int i = 0; i < vertexCount; i++) {
// Red value (is increased by .2 on each next vertex here)
colorArray[colorIndex++] = 0.1f;
// Green value (is reduced by .2 on each next vertex)
colorArray[colorIndex++] = 0.9f;
// Blue value (remains the same in our case)
colorArray[colorIndex++] = 0.5f;
// Alpha value (no transparency set here)
colorArray[colorIndex++] = 1.0f;

}

ninjaMesh.setBuffer(Type.Color, vertexCount * 4, colorArray);
ninjaMesh.getBuffer(Type.Color).setUpdateNeeded();
//System.out.println("colorBuffer.remaining :" + colorBuffer.remaining());
//System.out.println("Count :" + ninjaMesh.getBuffer(Type.Color).getNumComponents());

}

void opps() {
float maxdis = 200;
vertexCount = ninjaMesh.getVertexCount();
colorArray = new float[vertexCount * 4];
Vector3f camPos = cam.getLocation();

colorBuffer = ninjaMesh.getFloatBuffer(VertexBuffer.Type.Color);


vertices = ninjaMesh.getFloatBuffer(VertexBuffer.Type.Position);
vertices.rewind();

float value = 0, valueR = 0, valueG = 0, valueB = 0, valueA = 0;

int colorIndex = 0;
for (int i = 0; i < vertexCount; i++) {
float posx = vertices.get();
float posy = vertices.get();
float posz = vertices.get();

Vector3f vertexPos = new Vector3f(posx, posy, posz);
float dis = vertexPos.distance(camPos);
if (dis > maxdis) {
value = 0;

} else {
value = (maxdis - dis) / maxdis;
//System.out.println(" value :"+value);
valueR = value;
valueG = value;
valueB = value;
valueA = 1f;
//System.out.println("value :"+ value );
//System.out.println("colorIndex :"+ colorIndex );
colorArray[colorIndex++] = valueR;
colorArray[colorIndex++] = valueG/2;
colorArray[colorIndex++] = valueB/4;
colorArray[colorIndex++] = 1f;


}
}

//colorBuffer.clear();
//colorBuffer.put(colorArray);

//ninjaMesh.getBuffer(Type.Color).setUpdateNeeded();

}
/** Use this listener to trigger something after an animation is done. */
public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
if (animName.equals("Walk")) {
/** After "walk", reset to "stand". */
channel.setAnim("Kick", 0.50f);
channel.setLoopMode(LoopMode.DontLoop);
channel.setSpeed(1f);
}
}

/** Use this listener to trigger something between two animations. */
public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
// unused
}

/** Custom Keybindings: Mapping a named action to a key input. */
private void initKeys() {
inputManager.addMapping("Walk", new KeyTrigger(KeyInput.KEY_SPACE));
inputManager.addListener(actionListener, "Walk");
}
/** Definining the named action that can be triggered by key inputs. */
private ActionListener actionListener = new ActionListener() {

public void onAction(String name, boolean keyPressed, float tpf) {
if (name.equals("Walk") && !keyPressed) {
if (!channel.getAnimationName().equals("Walk")) {
/** Play the "walk" animation! */
channel.setAnim("Walk", 0.50f);
channel.setLoopMode(LoopMode.Loop);
}
}
}
};
}
[/java]

Umm define normally





vertexCount :781

#

A fatal error has been detected by the Java Runtime Environment:

#

EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00000000442fda50, pid=4976, tid=3604

#

JRE version: 6.0_22-b04

Java VM: Java HotSpot™ 64-Bit Server VM (17.1-b03 mixed mode windows-amd64 )

Problematic frame:

C [atio6axx.dll+0x78da50]

#

An error report file with more information is saved as:

C:workspacesdfshs_err_pid4976.log

#

If you would like to submit a bug report, please visit:

http://java.sun.com/webapps/bugreport/crash.jsp

The crash happened outside the Java Virtual Machine in native code.

See problematic frame for where to report the bug.

#



Oh , sorry, i’ve updated the code , let’s run it again please … The last code is unrunable caused the scale of the model is too big :smiley:

Hm yeah no matter what I try I can’t get the buffer to update, can confirm that.

Just a guess… but you might try looking into how the particle emitter stuff does it. I think it’s constantly updating the mesh.



…though in general, I’d say if you can avoid doing that it will be better. Doing calculations on the GPU is bound to be cheaper then shuttling data across the bus all the time.

In your “oops()” method, you commented out the part that updates the buffer?

Your problem is line 94:

[java]ninjaMesh.setBuffer(Type.Color, vertexCount * 4, colorArray);

[/java]



You have to set the components parameter to 4, as you only have 4 components per colour. VertexCount * 4 is a little bit too colourfull. :wink:



You can update your colours for example by following code (red ninja):



[java]

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

if (i % 4 == 0 || i % 4 == 3)

colorArray = 1.0f;

else

colorArray = 0.0f;

}

FloatBuffer colorBuffer = ninja.getMesh().getFloatBuffer(VertexBuffer.Type.Color);

colorBuffer.clear();

colorBuffer.put(colorArray);

[/java]

2 Likes

Holy #$@# :smiley:

Thanks a lot @empire Phoenix and @thesbu , I’ve mistaken between components and number of Float entries in the Buffer … The code is now working beautifully ! Thank again and again … Case Closed!

Oh , I want to ask one more question about the calculation for a world - position of an animating vertex :

[java]

float posx = vertices.get();

float posy = vertices.get();

float posz = vertices.get();



Vector3f geoPos = ninja.getWorldTranslation();

Vector3f scaleValue = ninja.getLocalScale();



Vector3f vertexPos = new Vector3f(posx, posy, posz);

vertexPos = vertexPos.scaleAdd(1, scaleValue, geoPos);



[/java]



Is it correct???

@Momoko_Fan : thank for you advices…

Yes, one of my quick thought about “updating parts of the mesh” … => I really don’t need as much feature as Blender or Modo … so

  • maybe I can use the vertex selection (modify a specific selection of vertex at one time , it may decrease the calculate for the whole mesh)

    The need of sculpting in a game environment editor is almost for terrain maybe , but in the need of various objects in the game , the creation of object may need mesh painting and sculpting ( or what ever method that modify the mesh such as explode-break them to fragment …etc). So in this attempt , I just try to get something like push, blow, bend , twist vertex or extrude , bevel triangle (quads) … Tell me if you think it’s possible (not very hard one :p)

I recommend using Spatial.getWorldTransform().transformVector()

1 Like