Sombrero's function

Hi guyz,
I have a problem and I want to ask you, if you can help me.

I’m trying to make something like “Sombrero’s function”, but I have a problem with making this function.
There is my projekt:

package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapText;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.VertexBuffer;
import com.jme3.util.SkyFactory;
import java.util.Random;

public class Main extends SimpleApplication {

private Node map;
//Vertices of loaded water patch
VertexBuffer vertices;
//Wave map constants to control waves
int currmap = 0;
int nextmap = 1;
//Value of ripple (lenght)
float waterDampen = 60.0f;
//Our water plane tiles number along X and Y axes
int numTilesX = 100;
int numTilesY = 100;
//Number of vertices along individual axes
int numVertsX = numTilesX + 1;
int numVertsY = numTilesY + 1;
int vertindex = 0;
//Water wave map, deformation update will happen as well as waves propagation
float[][][] waveMap = new float[2][numVertsX + 2][numVertsY + 2];
//don't askme now == remake in some time
Random ran = new Random();
int tileX = (0 + ran.nextInt(numTilesX + 1)) + 1;
int tileY = (0 + ran.nextInt(numTilesY + 1)) + 1;
//Light
private DirectionalLight dl = new DirectionalLight();
private AmbientLight am = new AmbientLight();

public static void main(String[] args) {
    Main app = new Main();
    app.start();
}

@Override
public void simpleInitApp() {
    createSky();
    createWaterSurface();
    createLight();
    initCrossHairs();
    initKeys();
    cam.setLocation(new Vector3f(0.13642268f, 3.4800892f, 11.605716f));
}

private void createSky() {
    rootNode.attachChild(SkyFactory.createSky(assetManager, "Textures/Sky/Bright/BrightSky.dds", false));
}

private void createWaterSurface() {
    map = (Node) assetManager.loadModel("Scenes/my_water_surface.j3o");
    vertices = ((Geometry) map.getChild("Plane1")).getMesh().getBuffer(VertexBuffer.Type.Position);
    map.setLocalTranslation(new Vector3f(1, -10, 0));
    rootNode.attachChild(map);
}

private void createLight() {
    dl.setColor(ColorRGBA.White.clone().multLocal(2));
    dl.setDirection(new Vector3f(-1, -1, -1).normalize());
    rootNode.addLight(dl);
    am.setColor(ColorRGBA.White.mult(2));
    rootNode.addLight(am);
}

protected void initCrossHairs() {
    setDisplayStatView(false);
    guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
    BitmapText ch = new BitmapText(guiFont, false);
    ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
    ch.setText("+");
    ch.setLocalTranslation(settings.getWidth() / 2 - ch.getLineWidth() / 2,
            settings.getHeight() / 2 + ch.getLineHeight() / 2, 0);
    guiNode.attachChild(ch);
}

private void initKeys() {
    inputManager.addMapping("Shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
    inputManager.addListener(actionListener, "Shoot");
}
private ActionListener actionListener = new ActionListener() {
    public void onAction(String name, boolean keyPressed, float tpf) {
        if (name.equals("Shoot") && !keyPressed) {
            CollisionResults results = new CollisionResults();
            Ray ray = new Ray(cam.getLocation(), cam.getDirection());
            map.collideWith(ray, results);
            if (results.size() > 0) {
                waveMap[currmap][tileX][tileY] = 10f; //<= setting deepness
            }
        }
    }
};

@Override
public void simpleUpdate(float tpf) {
    for (int countY = 1; countY < numVertsY + 1; countY++) {
        for (int countX = 1; countX < numVertsX + 1; countX++) {
            //calculate wave intensity for this point
            float n = waveMap[currmap][countX - 1][countY] + waveMap[currmap][countX + 1][countY]
                    + waveMap[currmap][countX][countY - 1] + waveMap[currmap][countX][countY + 1];
            n = (n / 2) - waveMap[nextmap][countX][countY];

public static void main(String[] args) {
    Main app = new Main();
    app.start();
}

@Override
public void simpleInitApp() {
    createSky();
    createWaterSurface();
    createLight();
    initCrossHairs();
    initKeys();
    cam.setLocation(new Vector3f(0.13642268f, 3.4800892f, 11.605716f));
}

private void createSky() {
    rootNode.attachChild(SkyFactory.createSky(assetManager, "Textures/Sky/Bright/BrightSky.dds", false));
}

private void createWaterSurface() {
    map = (Node) assetManager.loadModel("Scenes/my_water_surface.j3o");
    vertices = ((Geometry) map.getChild("Plane1")).getMesh().getBuffer(VertexBuffer.Type.Position);
    map.setLocalTranslation(new Vector3f(1, -10, 0));
    rootNode.attachChild(map);
}

private void createLight() {
    dl.setColor(ColorRGBA.White.clone().multLocal(2));
    dl.setDirection(new Vector3f(-1, -1, -1).normalize());
    rootNode.addLight(dl);
    am.setColor(ColorRGBA.White.mult(2));
    rootNode.addLight(am);
}

protected void initCrossHairs() {
    setDisplayStatView(false);
    guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
    BitmapText ch = new BitmapText(guiFont, false);
    ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
    ch.setText("+");
    ch.setLocalTranslation(settings.getWidth() / 2 - ch.getLineWidth() / 2,
            settings.getHeight() / 2 + ch.getLineHeight() / 2, 0);
    guiNode.attachChild(ch);
}

private void initKeys() {
    inputManager.addMapping("Shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
    inputManager.addListener(actionListener, "Shoot");
}
private ActionListener actionListener = new ActionListener() {
    public void onAction(String name, boolean keyPressed, float tpf) {
        if (name.equals("Shoot") && !keyPressed) {
            CollisionResults results = new CollisionResults();
            Ray ray = new Ray(cam.getLocation(), cam.getDirection());
            map.collideWith(ray, results);
            if (results.size() > 0) {
                waveMap[currmap][tileX][tileY] = 10f; //<= setting deepness
            }
        }
    }
};

@Override
public void simpleUpdate(float tpf) {
    for (int countY = 1; countY < numVertsY + 1; countY++) {
        for (int countX = 1; countX < numVertsX + 1; countX++) {
            //calculate wave intensity for this point
            float n = waveMap[currmap][countX - 1][countY] + waveMap[currmap][countX + 1][countY]
                    + waveMap[currmap][countX][countY - 1] + waveMap[currmap][countX][countY + 1];
            n = (n / 2) - waveMap[nextmap][countX][countY];

            //dampen
            n = n - (n / waterDampen);
            waveMap[nextmap][countX][countY] = n;

            //set Point Height
            vertindex = ((countY - 1) * numVertsX) + countX;

            //set height of corresponding vertex trough vertex buffer
            vertices.setElementComponent(vertindex, 1, n);
        }
    }
    //swap the wave maps
    currmap = (currmap + 1) % 2;
    nextmap = (nextmap + 1) % 2;
}

It is crasing on line “vertices.setElementComponent(vertindex, 1, n);” and I don’t have an idea why. Can you please help me solve this problem? I’m not sure if you will need model “my_water_surface.j3o” so if you will need it, just ask me, I can send it to you anywhere you will need.

If you can help me, I will be really glad to.

Thanks
Sebastian

Edit: fixed the code because OP couldn’t.

post the entire exception

java.lang.IndexOutOfBoundsException
at java.nio.Buffer.checkIndex(Buffer.java:532)
at java.nio.DirectFloatBufferU.put(DirectFloatBufferU.java:300)
at com.jme3.scene.VertexBuffer.setElementComponent(VertexBuffer.java:762)
at mygame.Main.simpleUpdate(Main.java:126)
at com.jme3.app.SimpleApplication.update(SimpleApplication.java:242)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)
at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:185)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:228)
at java.lang.Thread.run(Thread.java:744)

For code blocks, begin with three back ticks ` and end with three back ticks… else it’s pretty unreadable.

``package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapText;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.VertexBuffer;
import com.jme3.util.SkyFactory;
import java.util.Random;

public class Main extends SimpleApplication {

    private Node map;
//Vertices of loaded water patch
    VertexBuffer vertices;
//Wave map constants to control waves
    int currmap = 0;
    int nextmap = 1;
//Value of ripple (lenght)
    float waterDampen = 60.0f;
//Our water plane tiles number along X and Y axes
    int numTilesX = 100;
    int numTilesY = 100;
//Number of vertices along individual axes
    int numVertsX = numTilesX + 1;
    int numVertsY = numTilesY + 1;
    int vertindex = 0;
//Water wave map, deformation update will happen as well as waves propagation
    float[][][] waveMap = new float[2][numVertsX + 2][numVertsY + 2];
//don't askme now == remake in some time
    Random ran = new Random();
    int tileX = (0 + ran.nextInt(numTilesX + 1)) + 1;
    int tileY = (0 + ran.nextInt(numTilesY + 1)) + 1;
//Light
    private DirectionalLight dl = new DirectionalLight();
    private AmbientLight am = new AmbientLight();

    public static void main(String[] args) {
        Main app = new Main();
        app.start();
    }

    @Override
    public void simpleInitApp() {
        createSky();
        createWaterSurface();
        createLight();
        initCrossHairs();
        initKeys();
        cam.setLocation(new Vector3f(0.13642268f, 3.4800892f, 11.605716f));
    }

    private void createSky() {
        rootNode.attachChild(SkyFactory.createSky(assetManager, "Textures/Sky/Bright/BrightSky.dds", false));
    }

    private void createWaterSurface() {
        map = (Node) assetManager.loadModel("Scenes/my_water_surface.j3o");
        vertices = ((Geometry) map.getChild("Plane1")).getMesh().getBuffer(VertexBuffer.Type.Position);
        map.setLocalTranslation(new Vector3f(1, -10, 0));
        rootNode.attachChild(map);
    }

    private void createLight() {
        dl.setColor(ColorRGBA.White.clone().multLocal(2));
        dl.setDirection(new Vector3f(-1, -1, -1).normalize());
        rootNode.addLight(dl);
        am.setColor(ColorRGBA.White.mult(2));
        rootNode.addLight(am);
    }

    protected void initCrossHairs() {
        setDisplayStatView(false);
        guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
        BitmapText ch = new BitmapText(guiFont, false);
        ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
        ch.setText("+");
        ch.setLocalTranslation(settings.getWidth() / 2 - ch.getLineWidth() / 2,
                settings.getHeight() / 2 + ch.getLineHeight() / 2, 0);
        guiNode.attachChild(ch);
    }

    private void initKeys() {
        inputManager.addMapping("Shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
        inputManager.addListener(actionListener, "Shoot");
    }
    private ActionListener actionListener = new ActionListener() {
        public void onAction(String name, boolean keyPressed, float tpf) {
            if (name.equals("Shoot") && !keyPressed) {
                CollisionResults results = new CollisionResults();
                Ray ray = new Ray(cam.getLocation(), cam.getDirection());
                map.collideWith(ray, results);
                if (results.size() > 0) {
                    waveMap[currmap][tileX][tileY] = 10f; //<= setting deepness
                }
            }
        }
    };

    @Override
    public void simpleUpdate(float tpf) {
        for (int countY = 1; countY < numVertsY + 1; countY++) {
            for (int countX = 1; countX < numVertsX + 1; countX++) {
                //calculate wave intensity for this point
                float n = waveMap[currmap][countX - 1][countY] + waveMap[currmap][countX + 1][countY]
                        + waveMap[currmap][countX][countY - 1] + waveMap[currmap][countX][countY + 1];
                n = (n / 2) - waveMap[nextmap][countX][countY];

                //dampen
                n = n - (n / waterDampen);
                waveMap[nextmap][countX][countY] = n;

                //set Point Height
                vertindex = ((countY - 1) * numVertsX) + countX;

                //set height of corresponding vertex trough vertex buffer
                vertices.setElementComponent(vertindex, 1, n);
            }
        }
        //swap the wave maps
        currmap = (currmap + 1) % 2;
        nextmap = (nextmap + 1) % 2;
    }
}

can’t do more probably :confused:

Just select the stuff and press the “</>” button on top (did that for you now)

By the way, this is where your bug is. I’m not sure what line 126 is but that’s where you are exceeding the buffer size.

hmm you could simply try …catch it to maybe visually see your issue or you print out the indices of your algorithm in simpleUpdate and you will see that somewhere your are calculating the wrong index

int countX = 1; countX < numVertsX + 1; //-> countX is at the end numVertsX

vertindex = ((countY - 1) * numVertsX) + countX; // countX will select the nextLine because it is overflowen

Or… just run it in the debugger and see everything when the crash happens.

Ok I did some researche and I found this:
there is number 1392 which is number of elements in my scene (vectors)
while vertindex has this value (1392) there is exception. Index is counted *3(RGB? I have no idea), which is 4176. Variable vertices has 4176 elements from the start of the program. class VertexBuffer says, that it has limit 4176 and capacity also 4176.
And exceeding the limit for vertindex 4176 in methode Buffer.checkIndex[531] causes exception.

Now I know where is the problem but I don’t have idea how to solve this problem. Maybe I should make new scene in blender? Use some tutorial to make water surface?

Thanks guyz

I recommend you to remove all +1 and -1 you have in your loops, it will be much easier then.

If there are 1392 elements then index 1392 is one after the end. Indexes start at 0.

Just wondering, are you trying to procedurally generate hats? :smiley:

Thing is I don’t have an idea how to fix it. Maybe there is a miskate in my scene, not in algorithm. I don’t know, what do you think?

I think if you are trying to set a value to index 1392 and the buffer is only 1392 elements long then your math is definitely wrong somewhere.

This is the time where you roll up your sleeves and do some debugging. Either put in a bunch of printlns to verify all of the assumptions you’ve made or step through the code in a debugger. Some assumption (or assumptions) is wrong and you need to find it.

This is the worst kind of debugging for someone else to do for you because everything is an assumption for us… including that you’ve coded the algorithm right in the first place. I think scratching an eye out would be less painful.

maybe this would help you to understand what am I doing :smile:

If this were my code, I’d be putting printlns in my loops to verify my assumptions.

Get to work! :slight_smile:

Edit: or I’d take a step back to something simpler… say just trying to get a plain grid to work or something.

Thanks, I’m going to work.
I have whole Christmas holiday to do it :smiley:

I’m back :smiley: Actually I made code function, so there were problem in blender scene. (I made new one)

Now there is code:

    package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapText;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.VertexBuffer;
import com.jme3.util.SkyFactory;
import java.util.Random;

public class Main extends SimpleApplication {

    private Node map;
//Vertices of loaded water patch
    VertexBuffer vertices;
//Wave map constants to control waves
    int currmap = 0;
    int nextmap = 1;
//Value of ripple (lenght)
    float waterDampen = 60.0f;
//Our water plane tiles number along X and Y axes
    int numTilesX = 100;
    int numTilesY = 100;
//Number of vertices along individual axes
    int numVertsX = numTilesX + 1;
    int numVertsY = numTilesY + 1;
    int vertindex = 0;
//Water wave map, deformation update will happen as well as waves propagation
    float[][][] waveMap = new float[2][numVertsX + 2][numVertsY + 2];
//don't askme now == remake in some time
    Random ran = new Random();
    int tileX = (0 + ran.nextInt(numTilesX + 1)) + 1;
    int tileY = (0 + ran.nextInt(numTilesY + 1)) + 1;
//Light
    private DirectionalLight dl = new DirectionalLight();
    private AmbientLight am = new AmbientLight();

    public static void main(String[] args) {
        Main app = new Main();
        app.start();
    }

    @Override
    public void simpleInitApp() {
        createSky();
        createWaterSurface();
        createLight();
        initCrossHairs();
        initKeys();
        cam.setLocation(new Vector3f(0.12541789f, 7.218303f, 16.560389f));
    }

    private void createSky() {
        rootNode.attachChild(SkyFactory.createSky(assetManager, "Textures/Sky/Bright/BrightSky.dds", false));
    }

    private void createWaterSurface() {
        map = (Node) assetManager.loadModel("Scenes/wate_glass.j3o");
        vertices = ((Geometry) map.getChild("Plane1")).getMesh().getBuffer(VertexBuffer.Type.Position);
        map.setLocalTranslation(new Vector3f(0, 0, 0));
        rootNode.attachChild(map);
    }

    private void createLight() {
        dl.setColor(ColorRGBA.White.clone().multLocal(2));
        dl.setDirection(new Vector3f(-1, -1, -1).normalize());
        rootNode.addLight(dl);
        am.setColor(ColorRGBA.White.mult(2));
        rootNode.addLight(am);
    }

    protected void initCrossHairs() {
        setDisplayStatView(false);
        guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
        BitmapText ch = new BitmapText(guiFont, false);
        ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
        ch.setText("+");
        ch.setLocalTranslation(settings.getWidth() / 2 - ch.getLineWidth() / 2,
                settings.getHeight() / 2 + ch.getLineHeight() / 2, 0);
        guiNode.attachChild(ch);
    }

    private void initKeys() {
        inputManager.addMapping("Shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
        inputManager.addListener(actionListener, "Shoot");
    }
    private ActionListener actionListener = new ActionListener() {
        public void onAction(String name, boolean keyPressed, float tpf) {
            if (name.equals("Shoot") && !keyPressed) {
                CollisionResults results = new CollisionResults();
                Ray ray = new Ray(cam.getLocation(), cam.getDirection());
                map.collideWith(ray, results);
                if (results.size() > 0) {
                    waveMap[currmap][tileX][tileY] = 10f; //<= setting deepness
                }
            }
        }
    };

    @Override
    public void simpleUpdate(float tpf) {
        for (int countY = 1; countY < numVertsY + 1; countY++) {
            for (int countX = 1; countX < numVertsX + 1; countX++) {
                //calculate wave intensity for this point
                float n = waveMap[currmap][countX - 1][countY] + waveMap[currmap][countX + 1][countY]
                        + waveMap[currmap][countX][countY - 1] + waveMap[currmap][countX][countY + 1];
                n = (n / 2) - waveMap[nextmap][countX][countY];

                //dampen
                n = n - (n / waterDampen);
                waveMap[nextmap][countX][countY] = n;

                //set Point Height
                vertindex = ((countY - 1) * numVertsX) + countX;

                //set height of corresponding vertex trough vertex buffer
                vertices.setElementComponent(vertindex, 1, n);
            }
        }
        //swap the wave maps
        currmap = (currmap + 1) % 2;
        nextmap = (nextmap + 1) % 2;
    }
}

Problem is, even it runs everything ok, how can I get verteX and vertexY of camera when I click? If you know what I mean.

Random ran = new Random();
    int tileX = (0 + ran.nextInt(numTilesX + 1)) + 1;
    int tileY = (0 + ran.nextInt(numTilesY + 1)) + 1;

Now I have it made randomly, but I want to make it → where I click, make water ripples.
I didn’t found how to make it.
Here is where it should be initialized:

private void initKeys() {
        inputManager.addMapping("Shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
        inputManager.addListener(actionListener, "Shoot");
    }
    private ActionListener actionListener = new ActionListener() {
        public void onAction(String name, boolean keyPressed, float tpf) {
            if (name.equals("Shoot") && !keyPressed) {
                CollisionResults results = new CollisionResults();
                Ray ray = new Ray(cam.getLocation(), cam.getDirection());
                map.collideWith(ray, results);
                if (results.size() > 0) {
                    waveMap[currmap][tileX][tileY] = 10f; //<= setting deepness
                }
            }
        }
    };

Because now it doesn’t make any water ripples.

Maybe it seems like I will have some free time during Christmas holidays. :smiley:

Put printlns in there to see what’s happening.

STEP 1 any time you hit a wall. Make sure the wall is where you think it is and made of what you think it is. Basic debugging.