libgdx: How do i get the result of an orthographic camera through another orthographic camera? - libgdx

I would like to have a TV screen on my stage. I have a master scene containing the TV screen and some other things (some sprites) and the scene corresponding to what I want to render in the TV.
So I would like to render the TV scene through an OrthographicCamera and then put the result in something like a sprite which can then be rendered through the master orthographic camera, how to do that?
I know that one can use multiple camera in multiple viewports but these are directly rendered on the pixels of my computer screen.
Any advice would be much appreciated

This can be achieved by rendering the scene from the perspective of a screen camera to a FrameBuffer and then taking the TextureRegion from the FrameBuffer and rendering that to screen and then render the scene again.
For example:
In the above example the cyan rect shows what the in-scene camera sees, and this is rendered to the grey box, it is possible to move both the scene camera and the main camera independentely.
By creating and grabbing the TextureRegion from a FrameBuffer
screenFrameBuffer = new FrameBuffer(Pixmap.Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(),true);
screenTexture = new TextureRegion(screenFrameBuffer.getColorBufferTexture());
screenTexture.flip(false, true);
all render calls can be made to affect only the screenFrameBuffer by calling screenFrameBuffer.begin(), after screenFrameBuffer.end() is called the next draw call will again affect the actual screen/window.
So in in the render method you can first draw your scene to the FrameBuffer
screenFrameBuffer.begin();
renderScene(screenCamera, Color.DARK_GRAY);
screenFrameBuffer.end();
And then draw it again, followed by the "screen" as a sprite:
renderScene(sceneCamera, Color.BLACK);
batch.setProjectionMatrix(sceneCamera.combined);
batch.begin();
batch.draw(screenTexture, -sceneCamera.viewportWidth / 2.0f,-sceneCamera.viewportHeight / 2.0f,0,0,screenCamera.viewportWidth,screenCamera.viewportHeight,1.0f, 1.0f, 0.0f);
batch.end();
Complete source code for the gif above is:
package com.bornander.sandbox;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.FrameBuffer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.RandomXS128;
import com.badlogic.gdx.math.Vector2;
public class MyGdxGame implements ApplicationListener {
public static class Ball {
public Vector2 position = new Vector2();
public Vector2 velocity = new Vector2();
public float size = 1.0f;
public Color color = new Color();
public void render(ShapeRenderer shapeRenderer) {
shapeRenderer.setColor(color);
shapeRenderer.circle(position.x, position.y, size, 16);
}
public void update() {
position.x += velocity.x * Gdx.graphics.getDeltaTime();
position.y += velocity.y * Gdx.graphics.getDeltaTime();
}
}
static RandomXS128 rnd = new RandomXS128();
OrthographicCamera sceneCamera;
OrthographicCamera screenCamera;
ShapeRenderer shapeRenderer;
SpriteBatch batch;
FrameBuffer screenFrameBuffer;
TextureRegion screenTexture;
Ball[] balls;
private static float rnd(float min, float max) {
return min + rnd.nextFloat() * (max - min);
}
#Override
public void create() {
float aspectRatio = (float) Gdx.graphics.getWidth() / (float)Gdx.graphics.getHeight();
sceneCamera = new OrthographicCamera(100.0f, 100.0f / aspectRatio);
screenCamera = new OrthographicCamera(32.0f, 32.0f / aspectRatio);
batch = new SpriteBatch();
screenFrameBuffer = new FrameBuffer(Pixmap.Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(),true);
screenTexture = new TextureRegion(screenFrameBuffer.getColorBufferTexture());
screenTexture.flip(false, true);
shapeRenderer = new ShapeRenderer();
balls = new Ball[128];
for(int i = 0; i < balls.length; ++i) {
balls[i] = new Ball();
balls[i].position.set(0, 0);
balls[i].velocity.set(rnd(-4, 4), rnd(-4, 4));
balls[i].size = rnd(1, 1);
balls[i].color.set(rnd(0.5f, 1.0f), rnd(0.5f, 1.0f), rnd(0.5f, 1.0f), 1.0f);
}
}
private void renderScene(Camera camera, Color background) {
camera.update();
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Gdx.gl.glClearColor(background.r, background.g, background.b, background.a);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
shapeRenderer.setProjectionMatrix(camera.combined);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
for(int i = 0; i < balls.length; ++i) {
balls[i].render(shapeRenderer);
}
shapeRenderer.end();
}
#Override
public void render() {
float cs = 8.0f;
for(int i = 0; i < balls.length; ++i)
balls[i].update();
if (Gdx.input.isKeyPressed(Input.Keys.LEFT))
sceneCamera.position.x -= cs * Gdx.graphics.getDeltaTime();
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT))
sceneCamera.position.x += cs * Gdx.graphics.getDeltaTime();
if (Gdx.input.isKeyPressed(Input.Keys.UP))
sceneCamera.position.y -= cs * Gdx.graphics.getDeltaTime();
if (Gdx.input.isKeyPressed(Input.Keys.DOWN))
sceneCamera.position.y += cs * Gdx.graphics.getDeltaTime();
if (Gdx.input.isKeyPressed(Input.Keys.A))
screenCamera.position.x -= cs * Gdx.graphics.getDeltaTime();
if (Gdx.input.isKeyPressed(Input.Keys.D))
screenCamera.position.x += cs * Gdx.graphics.getDeltaTime();
if (Gdx.input.isKeyPressed(Input.Keys.W))
screenCamera.position.y -= cs * Gdx.graphics.getDeltaTime();
if (Gdx.input.isKeyPressed(Input.Keys.S))
screenCamera.position.y += cs * Gdx.graphics.getDeltaTime();
// Render to framebuffer, clear the background to DARK_GRAY
screenFrameBuffer.begin();
renderScene(screenCamera, Color.DARK_GRAY);
screenFrameBuffer.end();
// Render to window/screen, clear backgroun to BLACK
renderScene(sceneCamera, Color.BLACK);
// Draw the framebuffer's texture as a sprite using a normal SpriteBatch
batch.setProjectionMatrix(sceneCamera.combined);
batch.begin();
batch.draw(screenTexture, -sceneCamera.viewportWidth / 2.0f,-sceneCamera.viewportHeight / 2.0f,0,0,screenCamera.viewportWidth,screenCamera.viewportHeight,1.0f, 1.0f, 0.0f);
batch.end();
// This just draws the outline of what the screen camera looks at
shapeRenderer.setProjectionMatrix(sceneCamera.combined);
shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
shapeRenderer.setColor(Color.CYAN);
shapeRenderer.rect(
screenCamera.position.x - screenCamera.viewportWidth / 2.0f,
screenCamera.position.y - screenCamera.viewportHeight / 2.0f,
screenCamera.viewportWidth,
screenCamera.viewportHeight
);
shapeRenderer.end();
}
#Override
public void dispose() {
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
}

Related

Libgdx : GestureListener - pan not working properly

I am new to libgdx and trying to move a circle vy draging it. But its not working properly.
class deceleration is as follows -
public class gScreen1 extends ScreenAdapter
implements GestureDetector.GestureListener {
private static final float WORLD_WIDTH = 640;
private static final float WORLD_HEIGHT = 480;
...
#Override
public void show() {
super.show();
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.position.set(WORLD_WIDTH / 2, WORLD_HEIGHT / 2, 0);
camera.update();
viewport = new FitViewport(WORLD_WIDTH, WORLD_HEIGHT, camera);
shapeRenderer = new ShapeRenderer();
batch = new SpriteBatch();
}
private void drawGrid() {
Gdx.gl.glLineWidth(2);
shapeRenderer.setProjectionMatrix(camera.projection);
shapeRenderer.setTransformMatrix(camera.view);
shapeRenderer.setColor(Color.YELLOW);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
size = points.length;
for (int i = 0; i < size; i++) {
shapeRenderer.circle(pointsr[i].x , pointsr[i].y ,10);
}
shapeRenderer.end();
}
#Override
public void render(float delta) {
super.render(delta);
clearScreen();
drawGrid();
}
#Override
public boolean pan(float x1, float y1, float deltaX, float deltaY) {
Vector3 tmpCoords = new Vector3(x1,y1, 0);
camera.unproject(tmpCoords);
int x = (int)tmpCoords.x;
int y = (int)tmpCoords.y;
for( i = 0; i < size ; i++) {
int x2 = pointsr[i].x;
int y2 = pointsr[i].y;
if( ((x2 -x)*(x2 -x) + (y2 -y)*(y2 -y) ) < 400 )
break;
}
if( i < size ) {
pointsr[i].x += deltaX;
pointsr[i].y += deltaY;
}
}
Circles are not following movement of finger, some time they move a little bit but in opposite y direction of touch movement.

How to achieve the following effect with libGDX?

I'm developping a game with libGDX. I have a question: Know the initial coordinates and target coordinates, as the picture shows, how to achieve the parabolic effect of the bullet ? to achieve the operation of shells . Who can teach me ? or tell me some tutorial. Tks
picture
You need to add some physics to your app (ex. Box2d). Then you 'throw' canon ball with some velocity and some direction/angle.
Physics engine do rest for you.
Here you have tutorial for box2d: https://www.youtube.com/watch?v=vXovY2KTing
Very very basic example for throw something without box2d. For your example you need to calculate right 'power' for target position.
public class SampleApp extends ApplicationAdapter
{
Sprite sprite;
Vector2 velocity = new Vector2(0, 0);
Vector2 terminateVelocity = new Vector2(2000, 2000);
Vector2 friction = new Vector2(200, 300);
Vector2 position = new Vector2(0, 0);
Vector2 launchPower = new Vector2(0, 0);
boolean shotNow;
#Override
public void render()
{
update(Gdx.graphics.getDeltaTime());
// ...
// here render your stuff
}
public void shot(float power)
{
// Calculate x launch power
launchPower.x = ((power - sprite.getX() + sprite.getWidth()*0.5f) / 2f) + velocity.x;
// We want to end our fly at ground
launchPower.y = ((0 - sprite.getY()) / 2f) + velocity.y;
// Setup start position
position.x = sprite.getX();
position.y = sprite.getY();
// Add some acc to velocity
velocity.add(launchPower);
shotNow = true;
}
public void update(float dt)
{
if (Gdx.input.justTouched()) {
shot(900);
}
// Very basic sprite movement.
// For best results you should implement more physics (acceleration etc.)
if (shotNow && position.y > 0) {
// Friction/gravity
velocity.x = MathUtils.clamp(velocity.x - friction.x * dt, -terminateVelocity.x, terminateVelocity.x);
velocity.y = MathUtils.clamp(velocity.y - friction.y * dt, -terminateVelocity.y, terminateVelocity.y);
position.add(velocity.x * dt, velocity.y * dt);
sprite.setPosition(position.x, position.y);
}
}
}

Dragging a texture (without jump)

How can I drag a texture (image) without making it jump and centering itself on the mouse cursor (what I have below in my code)?
When I click on the texture, nothing should happen, and when I drag, the mouse cursor should stay in place (relative to the edges of the texture).
Example: https://s31.postimg.org/ojapwbj6j/Untitled_1.jpg
SpriteBatch batch;
Texture texture;
OrthographicCamera camera;
Vector3 spritePosition = new Vector3();
float offsetX, offsetY;
Vector3 input;
#Override
public void create () {
batch = new SpriteBatch();
texture = new Texture("badlogic.jpg");
camera = new OrthographicCamera();
camera.setToOrtho(false);
}
#Override
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw(texture, spritePosition.x, spritePosition.y);
batch.end();
if (Gdx.input.justTouched()){
int x1 = Gdx.input.getX();
int y1 = Gdx.input.getY();
input = new Vector3(x1, y1, 0);
camera.unproject(input);
offsetX = x1 - spritePosition.x;
offsetY = y1 - spritePosition.y;
}
if (Gdx.input.isTouched()) {
spritePosition.set(Gdx.input.getX() - offsetX, Gdx.input.getY() - offsetY, 0);
}
}
What you need to do is work out the offset of the mouse position relative to your image, and subtract that, rather than half the width / height as you're doing at the moment.
Here's some very rough pseudocode to show what I mean - You'll need to rewrite as Java...
if Gdx.input.justTouched {
get mouse position from Gdx.input
camera.unproject it into cameraX and cameraY
offsetX = cameraX - imageX
offsetY = cameraY - imageY
}
if Gdx.input.isTouched {
spritePisition.set(Gdx.input.getX() - offsetX, Gdx.input.getY - offsetY)
}
Why are you using camera.unproject?
Try this:
Override
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(texture, spritePosition.x, spritePosition.y);
batch.end();
if (Gdx.input.isTouched()) {
spritePosition.set(Gdx.input.getX() - texture.getWidth() / 2, Gdx.input.getY() + texture.getHeight() / 2, 0);
}
}

Spawning random different objects at random locations

I am making a game where there are different objects fall from the upper part of the screen to the lower part of the screen. I am having problems with how can I choose what TextureRegion randomly to be spawned and not to change the already spawned TextureRegions. When I run the game lets say that the electronRegion is spawned first then when the next is spawned and let's say it's an antiprotonRegion the first electronRegion changes to antiprotonRegion that I don't want.
Here is my game class:
public class GameScreenTest implements Screen {
...
#Override
public void render(float delta) {
camera.update();
game.batch.setProjectionMatrix(camera.combined);
game.batch.begin();
game.batch.disableBlending();
game.batch.draw(background, 0, 0);
game.batch.enableBlending();
for(Particles particle: particles) {
particlesControl.draw(particle.x, particle.y);
}
game.batch.end();
if(TimeUtils.millis() - lastDropTime > 500) {
particlesControl.spawn();
particlesControl.update();
}
Iterator<Particles> iter = particles.iterator();
while(iter.hasNext()) {
Particles particle = iter.next();
particle.y -= 200 * Gdx.graphics.getDeltaTime();
if(particle.y + particle.height < 0) {
iter.remove();
}
}
}
...
private class Particles {
private int width;
private int height;
private int x;
private int y;
private Particles() {
}
private void spawn() {
Particles particle = new Particles();
particle.x = MathUtils.random(0, 480 - width);
particle.y = 800;
particle.width = width;
particle.height = height;
particles.add(particle);
lastDropTime = TimeUtils.millis();
}
private void update() {
choice = MathUtils.random(1, 4);
switch(choice) {
case 1:
chosen = new TextureRegion(protonRegion);
width = 75;
height = 75;
break;
case 2:
chosen = new TextureRegion(electronRegion);
width = 75 / 2;
height = 75 / 2;
break;
case 3:
chosen = new TextureRegion(antiprotonRegion);
width = 75;
height = 75;
break;
case 4:
chosen = new TextureRegion(antielectronRegion);
width = 75 / 2;
height = 75 / 2;
break;
}
}
private void draw(int x, int y) {
game.batch.draw(chosen, x, y, width, height);
}
}
I want to know why does all the spawned objects change every time a random choice is taken, and of course, how to solve this problem. Thank You.
Tray this:
public class GameScreenTest implements Screen {
final AntimatterBlast game;
private Texture gameObjects;
private TextureRegion electronRegion;
private TextureRegion antielectronRegion;
private TextureRegion protonRegion;
private TextureRegion antiprotonRegion;
//===========================================//
//remove private TextureRegion chosen;
//===========================================//
private TextureRegion background;
private Music gameMusic;
private OrthographicCamera camera;
private Array<Particles> particles;
private Particles particlesControl;
private long lastDropTime;
private int choice;
public GameScreenTest(final AntimatterBlast game) {
this.game = game;
gameObjects = new Texture(Gdx.files.internal("GameObjects.png"));
electronRegion = new TextureRegion(gameObjects, 105, 103, 50, 50);
antielectronRegion = new TextureRegion(gameObjects, 105, 155, 46, 46);
protonRegion = new TextureRegion(gameObjects, 6, 6, 100, 100);
antiprotonRegion = new TextureRegion(gameObjects, 6, 108, 90, 90);
background = new TextureRegion(gameObjects, 0, 204, 480, 800);
gameMusic = Gdx.audio.newMusic(Gdx.files.internal("DST-ElektroHauz.mp3"));
gameMusic.setLooping(true);
camera = new OrthographicCamera();
camera.setToOrtho(false, 480, 800);
particles = new Array<Particles>();
particlesControl = new Particles();
//===========================================//
//choice = MathUtils.random(1, 4); //remove
//chosen = new TextureRegion(protonRegion); //remove
//===========================================//
}
#Override
public void render(float delta) {
camera.update();
game.batch.setProjectionMatrix(camera.combined);
game.batch.begin();
game.batch.disableBlending();
game.batch.draw(background, 0, 0);
game.batch.enableBlending();
for(Particles particle: particles) {
//===========================================//
particlesControl.draw(particle.chosen, particle.x, particle.y);
//change
//particlesControl.draw(particle.x, particle.y);
//===========================================//
}
game.batch.end();
if(TimeUtils.millis() - lastDropTime > 500) {
//===========================================//
particlesControl.spawn();
//===========================================//
//===========================================//
//remove particlesControl.update();
//===========================================//
}
Iterator<Particles> iter = particles.iterator();
while(iter.hasNext()) {
Particles particle = iter.next();
particle.y -= 200 * Gdx.graphics.getDeltaTime();
if(particle.y + particle.height < 0) {
iter.remove();
}
}
}
#Override
public void resize(int width, int height) {
}
#Override
public void show() {
gameMusic.play();
particlesControl.spawn();
}
#Override
public void hide() {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void dispose() {
gameObjects.dispose();
gameMusic.dispose();
}
private class Particles {
//===========================================//
private TextureRegion chosen; //add variable
//===========================================//
private int width;
private int height;
private int x;
private int y;
private Particles() {
}
private void spawn() {
Particles particle = new Particles();
particle.x = MathUtils.random(0, 480 - width);
particle.y = 800;
particle.width = width;
particle.height = height;
//===========================================//
particle.selectTexture();
//===========================================//
lastDropTime = TimeUtils.millis();
//===========================================//
selectTexture(); //add call
//===========================================//
particles.add(particle);
}
//===========================================//
private void selectTexture() { //change name, but is not nesesari
//===========================================//
choice = MathUtils.random(1, 4);
switch(choice) {
case 1:
//===========================================//
//change
//chosen = new TextureRegion(antielectronRegion);
//if you are not going to change or modific TextureRegion
//independet other the textureRegion,
//I think you could use it well.It is just an idea
chosen = protonRegion;
//===========================================//
width = 75;
height = 75;
break;
case 2:
//===========================================//
//change
//chosen = new TextureRegion(antielectronRegion);
//if you are not going to change or modific TextureRegion
//independet other the textureRegion,
//I think you could use it well.It is just an idea
chosen = electronRegion;
//===========================================//
width = 75 / 2;
height = 75 / 2;
break;
case 3:
//===========================================//
//change
//chosen = new TextureRegion(antielectronRegion);
//if you are not going to change or modific TextureRegion
//independet other the textureRegion,
//I think you could use it well.It is just an idea
chosen = antiprotonRegion;
//===========================================//
width = 75;
height = 75;
break;
case 4:
//===========================================//
//change
//chosen = new TextureRegion(antielectronRegion);
//if you are not going to change or modific TextureRegion
//independet other the textureRegion,
//I think you could use it well.It is just an idea
chosen = antielectronRegion;
//===========================================//
width = 75 / 2;
height = 75 / 2;
break;
}
}
//===========================================//
private void draw(TextureRegion chosen, int x, int y) {
game.batch.draw(chosen, x, y, width, height);
//===========================================//
}
}
}
Like I said in the previous comment the texture (chosen) is in the GameScreenTest and you are using it in the inner class so every single instance of the Particles class will share the same texture.
Not error causing but it might help you to organize the code and make it more readable and by all means you are not obligated to make them just take them as suggestions:
Naming conventions
Naming the class Particles make it seem like the class represents more than 1 Particle, but in fact it represents a single Particle maybe name it only Particle.
Separating the game logic
Make the Particle class deal only with its own problems and don't use it to generate other particles and to add it to an outer class.
Using the constructor since it is already there
Give the Particle the texture that it should use and maybe the coordinates.
Drawing "dead" particle
You are drawing first and asking questions later depending on your game it might feel weird since you will always draw a frame while it no longer exists.
Not really sure on this one
But you might be able to reuse the textures regions instead of a creating a new one of the same texture for every single particle

libgdx - group transformation

I'm new in LibGDX.
I created group with actors in show method and add listener (where i calculate rotation matrix) and want to rotate all actors from group with batch.setTransformMatrix(matrixResult); but nothing happens. How can I force to rotate all actors of group?
#Override
public void show() {
camera = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.position.set(0f, 0f, - 120);
camera.lookAt(0,0,0);
camera.near = 0.1f;
camera.far = 300f;
camera.update();
stage = new Stage();
shader = new ShaderProgram(vertexShader, fragmentShader);
myBatch = new SpriteBatch();
shapeRenderer = new ShapeRenderer();
sphere = BuildSphere(5, 100);
group = new Group(){
#Override
public void draw(Batch batch, float parentAlpha) {
batch.setTransformMatrix(matrixResult);
super.draw(batch, parentAlpha);
}
};
group.setTouchable(Touchable.enabled);
group.addListener(new InputListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y,
int pointer, int button) {
Gdx.app.log("MOUSE_X_BEG", Float.toString(x));
Gdx.app.log("MOUSE_Y_BEG", Float.toString(y));
begX = x;
begY = y;
return true;
}
#Override
public void touchDragged(InputEvent event, float x, float y,
int pointer) {
endX = x;
endY = y;
//isRotate = true;
float translationX = endX-begX;
float translationY = begY-endY;
float length = (float)Math.sqrt(Math.pow(translationX,2) + Math.pow(translationY,2));
Vector3 axis = new Vector3(0, 0, 0);
if(length>0){
if(begX-endX == 0){
axis.x = 1;
}else{
float angle = (float) (Math.atan(translationY/translationX) + Math.PI/2.0*(translationX <0 ? -1 : 1));
axis.z = 1;
axis.x = (float) Math.cos(angle);
axis.y = (float) Math.sin(angle);
}
}
quaternion = new Quaternion(axis, 0.02f*length);
Matrix4 rotation = new Matrix4(quaternion);
matrixResult = rotation.mul(matrixRotationOld);
matrixRotationOld = matrixResult;
}
});
//group.setBounds(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
for (CenterCoordinate cenCoordinate : sphere.getPolygonCenterCoordinates()) {
Vector3 vector = cenCoordinate.getCartesianCenter();
Polygon polygon = new Polygon(1, cenCoordinate.getType().getCode(), cenCoordinate.getRadius(), cenCoordinate.getPsi(),
cenCoordinate.getKsi(), vector, cenCoordinate.getRotation());
group.addActor(polygon);
}
stage.addActor(group);
Gdx.input.setInputProcessor(stage);
}
Polygon extends Actor draw method :
#Override
public void draw(Batch batch, float parentAlpha) {
translation.setToTranslation(vertex.x, vertex.y, vertex.z);
matrix.mul(translation);
shader.begin();
shader.setUniformMatrix("u_worldView", matrix);
mesh.render(shader, GL20.GL_LINE_LOOP, 1, mesh.getNumVertices()-1);
shader.end();
matrix.idt();
}
Rotating the batch will not rotate the group. If you want to rotate everything i would suggest to rotate the camera of the Stage and set the Stages SpriteBatchs ProjectionMatrix to cam.combined. But to rotate only the Group use the rotateBy(degrees) or setRotation(degrees) method.
Rotating the SpriteBatch or the camera is actually only a change of the view, but rotating the Actor (in your case the Group) changes the logic of them.
In the draw() method you then will need to take care about this rotation and then you will have the result you want.