I'm using libgdx trying to draw some curves using this doc.
But when I render, its just a straight line, any ideas why it doesn't curve?
I'm assuming myCatmull.valueAt should populate correct points on curve.
public class IABezier {
Vector2[] points = new Vector2[100];
public IABezier() {
Vector2[] dataSet = new Vector2[2];
dataSet[0] = new Vector2(10.0f, 10.0f);
dataSet[1] = new Vector2(20.0f, 20.0f);
CatmullRomSpline < Vector2 > myCatmull = new CatmullRomSpline < Vector2 > (dataSet, true);
for (int i = 0; i < 100; ++i) {
points[i] = new Vector2();
myCatmull.valueAt(points[i], ((float) i) / ((float) 100 - 1));
}
}
public void draw(ShapeRenderer sRenderer) {
sRenderer.begin(ShapeType.Line);
sRenderer.identity();
for (int i = 0; i < 100 - 1; ++i) {
sRenderer.line(points[i], points[i + 1]);
}
sRenderer.end();
}
}
Rendered ..
A catmullrom spline requires at least four samples. So you'll have to add a few more samples to see the actual curve.
Vector2[] dataSet = new Vector2[6];
dataSet[0] = new Vector2(10.0f, 10.0f);
dataSet[1] = new Vector2(20.0f, 20.0f);
dataSet[2] = new Vector2(20.0f, 10.0f);
dataSet[3] = new Vector2(10.0f, 20.0f);
dataSet[4] = new Vector2(15.0f, 15.0f);
dataSet[5] = new Vector2(25.0f, 25.0f);
Here's an example which you can copy, paste and run.
Related
I'm learning to use LibGDX and my goal is to create a cube, with which you can control the resolution (number of vertices along each face). I already did that, and managed to use MeshBuilder to make it out of 6 different meshes and then render the resulting Mesh successfully using basic shaders :
Cube Mesh
//creates a square face with a normal vector and resolution number of vertices along any edge of the face
public Mesh createFace(Vector3 normal, int resolution) {
//creates 2 vectors perpendicular to each other and to the vector normal
Vector3 axisA = new Vector3(normal.y,normal.z,normal.x);
Vector3 axis = u.crs(normal, axisA);
Vector3 axisB = new Vector3(u.sqrt(axis.x),u.sqrt(axis.y),u.sqrt(axis.z));
//creates the arrays to hold the vertices and triangles
Vector3[] vertices = new Vector3[resolution * resolution];
//code for triangles
short[] triangles = new short[(resolution - 1) * (resolution - 1) * 6];
int triIndex = 0;
//looping over each vertex in the face
for (int y = 0; y < resolution; y++) {
for (int x = 0; x < resolution; x++) {
int vertexIndex = x + y * resolution;
//vector representing how close to the end of the x or y axis the loop is
Vector2 t = new Vector2(x / (resolution - 1f),y / (resolution - 1f));
//calculates the position of the vertex to place on the face
Vector3 mulA = u.mul(axisA, (2*t.x - 1));
Vector3 mulB = u.mul(axisB, (2*t.y-1));
Vector3 point = u.add3(normal, mulA, mulB);
//point = u.normalize(point);
vertices[vertexIndex] = point;
//puts the vertices into triangles
if (x != resolution - 1 && y != resolution - 1) {
triangles[triIndex + 0] = (short) vertexIndex;
triangles[triIndex + 1] = (short) (vertexIndex + resolution + 1);
triangles[triIndex + 2] = (short) (vertexIndex + resolution);
triangles[triIndex + 3] = (short) vertexIndex;
triangles[triIndex + 4] = (short) (vertexIndex + 1);
triangles[triIndex + 5] = (short) (vertexIndex + resolution + 1);
triIndex += 6;
}
}
}
float[] verticeList = u.vectorToList(vertices);
Mesh m = new Mesh(true, resolution * resolution, triangles.length, new VertexAttribute(Usage.Position,3,"a_Position"));
m.setIndices(triangles);
m.setVertices(verticeList);
return m;
}
//generates a cube Mesh with resolution vertices along each face
public Mesh generateFaces(int resolution, float scale) {
MeshBuilder meshBuilder = new MeshBuilder();
meshBuilder.begin(new VertexAttributes(new VertexAttribute (Usage.Position, 3 ,"a_Position")));
Vector3[] faceNormals = {
new Vector3(0,1*scale,0), //up
new Vector3(0,-1*scale,0), //down
new Vector3(-1*scale,0,0), //left
new Vector3(1*scale,0,0), //right
new Vector3(0,0,1*scale), //forward
new Vector3(0,0,-1*scale) //back
};
for (int i = 0; i < faceNormals.length; i++) {
meshBuilder.part("part"+ Integer.toString(i), GL20.GL_TRIANGLES);
meshBuilder.addMesh(createFace(faceNormals[i], resolution));
}
Mesh mesh = meshBuilder.end();
return mesh;
}
u is just a utilities class i created to store some math functions.
I then render it like so:
#Override
public void render () {
camController.update();
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Gdx.gl.glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
shader.bind();
shader.setUniformMatrix("matViewProj", cam.combined);
//rendering mesh
mesh1.render(shader, GL20.GL_LINE_STRIP);
[...]
}
I now want to make a model out of that mesh where each of the 6 faces will have a different color.
I thus tried to do it using a ModelBuilder following the LibGDX wiki, like so:
public Model generateModel(int resolution, float scale, Color[] colors) {
Vector3[] faceNormals = {
new Vector3(0,1*scale,0), //up
new Vector3(0,-1*scale,0), //down
new Vector3(-1*scale,0,0), //left
new Vector3(1*scale,0,0), //right
new Vector3(0,0,1*scale), //forward
new Vector3(0,0,-1*scale) //back
};
ModelBuilder modelBuilder = new ModelBuilder();
modelBuilder.begin();
for (int i = 0; i < faceNormals.length; i++) {
Mesh mesh = createFace(faceNormals[i], resolution);
MeshPart part = new MeshPart("part"+Integer.toString(i),mesh, 0, mesh.getNumVertices() ,GL20.GL_TRIANGLES);
modelBuilder.node().parts.add(new NodePart(part, new Material(ColorAttribute.createDiffuse(colors[i]))));
}
Model m = modelBuilder.end();
return m;
}
And then i rendered it using a ModelBatch and ModelInstance :
#Override
public void create () {
//creates an environment to handle lighting and such
environment = new Environment();
environment.set(new ColorAttribute(ColorAttribute.AmbientLight,0.4f,0.4f,0.4f,1f));
environment.add(new DirectionalLight().set(0.8f,0.8f,0.8f,-1f,-0.8f,-0.2f));
modelBatch = new ModelBatch();
//handling the inputProcessors of the camera and stage(UI)
multiplexer = new InputMultiplexer();
stage = new Stage();
multiplexer.addProcessor(stage);
scroll = new ScrolledInputProcessor();
multiplexer.addProcessor(scroll);
//camera (3D inputProcessor)
cam = new PerspectiveCamera(67,Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
cam.position.set(10f,10f,10f);
cam.lookAt(0,0,0);
cam.near = 1f;
cam.far = 300f;
cam.update();
camController = new CameraInputController(cam);
multiplexer.addProcessor(camController);
//shaders for every vertex and every pixel(fragment)
shader = new ShaderProgram(Gdx.files.internal("shader/vertexshader.glsl").readString() ,Gdx.files.internal("shader/fragmentshader.glsl").readString());
shader2 = new ShaderProgram(Gdx.files.internal("shader/vertexshader.glsl").readString() ,Gdx.files.internal("shader/fragmentshader2.glsl").readString());
//The 2D box encompassing the screen (UI)
table = new Table();
table.setFillParent(true);
stage.addActor(table);
//skins for UI
skin = new Skin(Gdx.files.internal("uiskin.json"));
//making a slider and dressing it in the skin
Drawable knobDown = skin.newDrawable("default-slider-knob", Color.GRAY);
SliderStyle sliderStyle = skin.get("default-horizontal", SliderStyle.class);
sliderStyle.knobDown = knobDown;
slider = new Slider(3.0f, 70.0f, 1.0f, false, sliderStyle);
table.right().top();
table.add(slider).row();
//creates the unit cube and unit sphere
model = generateModel(res, 1, colors);
instance = new ModelInstance(model);
font = new BitmapFont(Gdx.files.internal("uiskin.fnt"));
batch = new SpriteBatch();
Gdx.input.setInputProcessor(multiplexer);
}
#Override
public void render () {
camController.update();
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Gdx.gl.glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
shader.bind();
shader.setUniformMatrix("matViewProj", cam.combined);
modelBatch.begin(cam);
modelBatch.render(instance, environment);
modelBatch.end();
batch.begin();
font.draw(batch, "Zoom Level : " + zoomLevel, 1000f, 100f);
batch.end();
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
}
However, when i run the program, nothing is rendered, just the gray void.
Gray void of nothingness
My question is: How do I get my model to render?
I want to place some objects (ModelInstance) on the floor (also a ModelInstance) of my game world. To get the position for these objects, I let a Ray intersect the floor. The point of intersection should then be the required position.
My plan is to set the origin of the ray below the floor, so that the direction of the ray goes straight up and hits the floor from below. Both ModelInstances are .g3db Models made in Blender.
Vector3 dir = new Vector3(0, 10, 0); //Vector points upwards
Ray ray = new Ray(new Vector3(), dir.cpy());
Mesh mesh = landscape.model.meshes.first(); //The floor ModelInstance, has only a single mesh
int fac = mesh.getVertexSize();
float[] verts = new float[mesh.getNumVertices() * fac];
short[] inds = new short[mesh.getNumIndices()];
mesh.getVertices(verts);
mesh.getIndices(inds);
for (int j = 0; j < 10; j++) { //add 10 objects to the floor
Vector3 out = new Vector3(- 15, -50f, - j * 5);
ray.origin.set(out.cpy()); //set the origin of the vector below the floor
if (Intersector.intersectRayTriangles(ray, verts, inds, fac, out)) {
System.out.println(j + " out = " + out); //out should be the position for my objects
}
}
The output of the intersectRayTriangles Method is exactly the initial position below the floor. But this point is not anywhere close to the floor. How do I get the proper point of intersection?
I finally found a (semi optimal) solution which works.
landscape is a ModelInstance, created with Blender.
ArrayList<Vector3> vertices = new ArrayList<>();
landscape.calculateTransforms();
Renderable rend = new Renderable();
Mesh mesh = landscape.getRenderable(rend).meshPart.mesh;
int vertexSize = mesh.getVertexSize() / 4;
float[] verts = new float[mesh.getNumVertices() * vertexSize];
short[] inds = new short[mesh.getNumIndices()];
mesh.getVertices(verts);
mesh.getIndices(inds);
for (int i = 0; i < inds.length; i++) {
int i1 = inds[i] * vertexSize;
Vector3 v = new Vector3(verts[i1], verts[i1 + 1], verts[i1 + 2]);
v.set(v.prj(rend.worldTransform));
vertices.add(v);
}
Vector3 dir = new Vector3(0, 10, 0);
Vector3 pos = new Vector3(random.nextFloat(),random.nextFloat(),random.nextFloat());
Ray ray = new Ray(pos, dir.cpy());
for (int i = 0; i < vertices.size() - 3; i+=3){
if (Intersector.intersectRayTriangle(ray, vertices.get(i), vertices.get(i + 1), vertices.get(i + 2), pos)) {
//pos now contains the correct coordinates
break;
}
}
Note that the y-Axis faces upwards
Im trying to write a class that draws a square shape with 4 vertexes. I want each vertex to have its own velocity and path for each iteration in the drawloop. It seems to work for a few iterations until it gets "stuck" and Im having trouble understanding why that is. Any help or information regarding this is helpful, I suspect I dont have a full grasp of using vectors properly.Heres an image of when the code is running.
void draw() {
p.display();
//Stop loop setting
if (loop == 0) {
noLoop();
}
}
//----------------------------------------------------------------//
class Pillar
{
PVector v1Velocity,v2Velocity,v3Velocity,v4Velocity,
v1Pos,v2Pos,v3Pos,v4Pos,
v1End,v2End,v3End,v4End,
v1Acceleration,v2Acceleration,v3Acceleration,v4Acceleration,
origin;
float life,scale,randDegrees1,randDegrees2,randDegrees3,randDegrees4,maxVelocity;
Pillar (float _x, float _y, float _scale) {
scale = _scale; // scale of pillar
origin = new PVector(_x,_y); //pillar point of origin
v1Pos = new PVector(origin.x-(scale*1.5),origin.y); //vertex 1 start left
v2Pos = new PVector(origin.x,origin.y-scale); //vertex 2 start top
v3Pos = new PVector(origin.x+(scale*1.5),origin.y); //vertex 3 start right
v4Pos = new PVector(origin.x,origin.y+scale); //vertex 4 start bottom
v1End = new PVector(origin.x+random(50,200),origin.y-random(50,200));
v2End = new PVector(origin.x+random(50,200),origin.y-random(50,200));
v3End = new PVector(origin.x+random(50,200),origin.y-random(50,200));
v4End = new PVector(origin.x+random(50,200),origin.y-random(50,200));
randDegrees1 = random(360);
randDegrees2 = random(360);
randDegrees3 = random(360);
randDegrees4 = random(360);//Fixa denna.
v1Velocity = new PVector(cos(radians(randDegrees1)),sin(radians(randDegrees1)));
v2Velocity = new PVector(cos(radians(randDegrees2)),sin(radians(randDegrees2)));
v3Velocity = new PVector(cos(radians(randDegrees3)),sin(radians(randDegrees3)));
v4Velocity = new PVector(cos(radians(randDegrees4)),sin(radians(randDegrees4)));
maxVelocity = 5;
life = 100;
}
void calculateVector() {
v1Acceleration = PVector.sub(v1End,v1Pos);
v1Velocity.add(v1Acceleration);
v2Acceleration = PVector.sub(v2End,v2Pos);
v2Velocity.add(v2Acceleration);
v3Acceleration = PVector.sub(v3End,v3Pos);
v3Velocity.add(v3Acceleration);
v4Acceleration = PVector.sub(v4End,v4Pos);
v4Velocity.add(v4Acceleration);
v1Acceleration.setMag(life);
v2Acceleration.setMag(life);
v3Acceleration.setMag(life);
v4Acceleration.setMag(life);
v1Velocity.limit(maxVelocity);
v2Velocity.limit(maxVelocity);
v3Velocity.limit(maxVelocity);
v4Velocity.limit(maxVelocity);
v1Pos.add(v1Velocity);
v2Pos.add(v2Velocity);
v3Pos.add(v3Velocity);
v4Pos.add(v4Velocity);
life -= 1;
}
void display () {
beginShape();
stroke(0,0,0,50);
vertex(v1Pos.x,v1Pos.y);
vertex(v2Pos.x,v2Pos.y);
vertex(v3Pos.x,v3Pos.y);
vertex(v4Pos.x,v4Pos.y);
endShape(CLOSE);
calculateVector();
}
}
Sprite bucketImage, background, r1, r2, r5,
r10, r20, r50, r100, r200, r500, k1, k2, k5, k10, k20, k50;
I create objects in the method called spawnRaindrop(). I have an array of sprites and I want to sprites were changed in the cycle as it is now, it works, but the images are merged with each other.
sprites = new Sprite[15];
r1 = new Sprite(atlas.findRegion("r1"));
r1.flip(false, true);
r2 = new Sprite(atlas.findRegion("r2"));
r2.flip(false, true);
r5 = new Sprite(atlas.findRegion("r5"));
r5.flip(false, true);
r10 = new Sprite(atlas.findRegion("r10"));
r10.flip(false, true);
r20 = new Sprite(atlas.findRegion("r20"));
r20.flip(false, true);
r50 = new Sprite(atlas.findRegion("r50"));
r50.flip(false, true);
r100 = new Sprite(atlas.findRegion("r100"));
r100.flip(false, true);
r200 = new Sprite(atlas.findRegion("r200"));
r200.flip(false, true);
r500 = new Sprite(atlas.findRegion("r500"));
r500.flip(false, true);
k1 = new Sprite(atlas.findRegion("k1"));
k1.flip(false, true);
k2 = new Sprite(atlas.findRegion("k2"));
k2.flip(false, true);
k5 = new Sprite(atlas.findRegion("k5"));
k5.flip(false, true);
k10 = new Sprite(atlas.findRegion("k10"));
k10.flip(false, true);
k20 = new Sprite(atlas.findRegion("k20"));
k20.flip(false, true);
k50 = new Sprite(atlas.findRegion("k50"));
k50.flip(false, true);
sprites[0] = r1;
sprites[1] = r2;
sprites[2] = r5;
sprites[3] = r10;
sprites[4] = r20;
sprites[5] = r50;
sprites[6] = r100;
sprites[7] = r200;
sprites[8] = r500;
sprites[9] = k1;
sprites[10] = k2;
sprites[11] = k5;
sprites[12] = k10;
sprites[13] = k20;
sprites[14] = k50;
Create game object
private void spawnRaindrop() {
Rectangle raindrop = new Rectangle();
raindrop.x = MathUtils.random(0, 800 - 100);
raindrop.y = 480;
raindrop.width = 100;
raindrop.height = 100;
raindrops.add(raindrop);
lastDropTime = TimeUtils.nanoTime();
}
Create and draw array sprite
game.batch.draw(bucketImage, bucket.x, bucket.y);
for (Rectangle raindrop : raindrops) {
for (int i = 0; i < sprites.length - 1; i++) {
game.batch.draw(sprites[i], raindrop.x, raindrop.y);
}
}
game.batch.end();
RESULT:
I attached the picture, and it can be seen that the images accumulate on each other
It looks like your problem is that you are using the same raindrop.x and raindrop.y coordinates for all sprites!
for (Rectangle raindrop : raindrops)
{
for (int i = 0; i < sprites.length - 1; i++)
{
// The following will draw ALL sprites at the same location!
game.batch.draw(sprites[i], raindrop.x, raindrop.y);
}
}
What you can try is to create a new class called (for example): Raindrops and then in this class maintain a single x,y coordinate for each individual image:
class Raindrop
{
Vector2 coordinates;
Sprite sprite;
}
Then in your spawnRaindrop method, create an array of these Raindrop's and an individual (random?) image for each.
EDIT: I wrote the following code directly here without testing anything, so it will most likely have some errors, but nothing you shouldn't be able to fix yourself...
// This goes into your initialisation method
String regions[] = {"r1", "r2", "r5", "r10", "etc etc etc"}
Raindrop raindrops[] = new Raindrop[15];
for ( int i = 0; i < raindrops.length; i++ )
{
raindrop[i] = new Raindrop();
raindrop[i].coordinate.x = MathUtils.random(screenWidth);
raindrop[i].coordinate.y = MathUtils.random(screenHeight);
raindrop[i].sprite = atlas.findRegion(regions[(int)MathUtils.random(regions.length)]);
}
Then your main loop should look something like this:
game.batch.draw(bucketImage, bucket.x, bucket.y);
for ( Raindrop raindrop : raindrops )
{
game.batch.draw(raindrop.sprite, raindrop.coordinate.x, raindrop.coordinate.y);
}
game.batch.end();
I've built this L-System in Processing using toxiclib and I want to connect each point which is specified to each intersection in the branching of the tree. I've written a separate sketch in which I'm trying to create a triangle mesh by connecting the three closest points, I've been able to connect three points but I want it to be able to go through all the Vertices in an arraylist and then connect three closest points until I have a mesh out of all the vertices in the array. I also need to be able to convert this whole sketch into a function where by I can feed it into my L-System and then it will return the whole system with all the points connected in order to create a mesh. Essentially this is so I can then texture and maybe possibly apply Shaders to it if possible. I think that I might be attempting a harder way of approaching this for I believe toxiclibs or HEMESH libraries could do all of this for me, but I've been unable to figure it out. Any help would be much appreciated.
Here's the code for the sketch I wrote to try and connect all the points into a mesh.
import peasy.*;
float min = 1000;
ArrayList <PVector> loc = new ArrayList <PVector> ();
ArrayList <PVector> locSort = new ArrayList <PVector> ();
float [] minDists;
int [] minIdxs;
PeasyCam cam;
void setup() {
size(600, 600, OPENGL);
cam = new PeasyCam(this, 100);
for (int i=0; i<50; i++) {
loc.add(new PVector(random(-50, 50), random(-50, 50), random(-50, 50)));
}
minDists = new float[3];
minIdxs = new int[3];
for (int i = 0; i < 3; i ++)minDists[i] = 1000;
for (int i=0; i<loc.size(); i++) {
for (int j=0; j<loc.size (); j++) {
PVector vi= loc.get(i);
// loc.remove(i);
PVector vj= loc.get(j);
// loc.remove(j);
float c = vi.dist(vj);
for (int k = 0; k < 3; k++) {
if (c < minDists[k] && c > 0) {
if (k == 0) {
minDists[2] = minDists[1];
minDists[1] = minDists[0];
} else if (k == 1) {
minDists[2] = minDists[1];
}
println(k, c);
minDists[k] = c;
minIdxs[k] = j;
break;
}
}
}
}
}
void draw() {
background(255);
for (PVector v : loc) {
pushMatrix();
translate(v.x, v.y, v.z);
fill(0);
noStroke();
sphere(1);
popMatrix();
}
for (int i = 0; i < 3; i ++) {
PVector p1 = loc.get(minIdxs[i]);
PVector p2 = loc.get(minIdxs[(i+1)%3]);
stroke(255, 0, 0);
line(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
}
}
Also the L-System was created by following this tutorial: https://www.youtube.com/watch?v=qF8LGLVrwfo