libgdx: how do you position a 3d model instance with Othographic Camera? - libgdx

I have a Screen class that uses Othographic Camera and want to put a 3d model on it.
#Override
public void show() {
....
mCamera = new OrthographicCamera();
mCamera.setToOrtho(false, width * sclWidth, height * sclWidth);
....
//3d instance initialization
modelBatch = new ModelBatch();
ModelBuilder modelBuilder = new ModelBuilder();
model = modelBuilder.createBox(0.5f,0.5f,0.5f, new Material(ColorAttribute.createDiffuse(Color.GREEN)), VertexAttributes.Usage.Position| VertexAttributes.Usage.Normal);
modelInstance = new ModelInstance(model, 128,128,128);
modelInstance.transform.set(mCamera.invProjectionView);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(63 / 255f, 128 / 255f, 70 / 255f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
//mCamera.rotateAround(Vector3.Zero, new Vector3(0,1,0),1f);
mCamera.update();
mBatch.setProjectionMatrix(mCamera.combined);
mBatch.begin();
mBatch.draw(img, 128*10, 0);
mBatch.end();
modelBatch.begin(mCamera);
modelBatch.render(modelInstance);
modelBatch.end();
}
It is in 2d view and I can put any 2d sprite with x and y on the screen according to the screen width and height.
However when doing 3d models, it is completely different.
The 3d model is stretched according to the camera screen and rendered in the center of the screen. I couldn't find the 3d model setX or setY/SetZ functions.
How should the 3d model be positioned and what functions should I use? Any advice or direction to tutorials will be thankful.
update:
camera position: (768.0,192.0,0.0)
Camera projection: [0.0012019231|0.0|0.0|-0.0]
[0.0|0.0021378205|0.0|-0.0]
[0.0|0.0|-0.02|-1.0]
[0.0|0.0|0.0|1.0]

First of all, you instantiated your model instance at coordinates 128, 128, 128. I'm not sure where you have your camera positioned, but if you want a centered object, the X and Y of the model instance should match those of the camera position.
Also, if you want the entire model to be visible, you need to move it away in the Z direction. The camera looks down the -Z axis, so a model instance's position's Z must be less than the Z position of the camera to be visible.
Your main issue is this line, which should be removed:
modelInstance.transform.set(mCamera.invProjectionView);
You definitely do not want to apply the camera's projection matrix and use it as the model's transform matrix.
A vertex position is typically (as in ModelBatch's default shader) mapped from world coordinates to screen coordinates by multiplying its position by a series of matrices. The transform matrix describes the ModelInstance's position, rotation, and scale, so it translates the original model's vertex positions into world space. The view matrix then translates the vertex to it's camera-relative location (camera space, aka view space). And then the projection matrix translates the vertex to screen space (projects it to the rectangular screen). Since the view and projection matrices are both defined by the camera, the can be pre-multiplied and passed to the batch all at once (camera.combined).
In the shader, each vertex position is multiplied by the matrices to get it into screen space.
So to move a model instance around in the world, you perform actions on its transform matrix, such as modelInstance.transform.translate(x,y,z). You generally should never need to call set on it. The line modelBatch.begin(mCamera); takes care of the camera.combined matrix for you under the hood.
When working with SpriteBatch in 2D, you are placing sprites directly in world space, since there is no source Model with defined vertex positions. This is why there is normally no need to use a transform matrix when using SpriteBatch (although it can be used to move the entire plane of sprites into some place in 3D world space).

Related

HTML5 Canvas save() and restore() performance

So the issue that I'm having is that in developing an HTML5 canvas app I need to use a lot of transformations (i.e. translate, rotate, scale) and therefore a lot of calls being made to context.save() and context.restore(). The performance drops very quickly even with drawing very little (because the save() and restore() are being called as many times as possible in the loop). Is there an alternative to using these methods but still be able to use the transformations? Thank you!
Animation and Game performance tips.
Avoid save restore
Use setTransform as that will negate the need for save and restore.
There are many reasons that save an restore will slow things down and these are dependent on the current GPU && 2D context state. If you have the current fill and/or stroke styles set to a large pattern, or you have a complex font / gradient, or you are using filters (if available) then the save and restore process can take longer than rendering the image.
When writing for animations and games performance is everything, for me it is about sprite counts. The more sprites I can draw per frame (60th second) the more FX I can add, the more detailed the environment, and the better the game.
I leave the state open ended, that is I do not keep a detailed track of the current 2D context state. This way I never have to use save and restore.
ctx.setTransform rather than ctx.transform
Because the transforms functions transform, rotate, scale, translate multiply the current transform, they are seldom used, as i do not know what the transform state is.
To deal with the unknown I use setTransform that completely replaces the current transformation matrix. This also allows me to set the scale and translation in one call without needing to know what the current state is.
ctx.setTransform(scaleX,0,0,scaleY,posX,posY); // scale and translate in one call
I could also add the rotation but the javascript code to find the x,y axis vectors (the first 4 numbers in setTransform) is slower than rotate.
Sprites and rendering them
Below is an expanded sprite function. It draws a sprite from a sprite sheet, the sprite has x & y scale, position, and center, and as I always use alpha so set alpha as well
// image is the image. Must have an array of sprites
// image.sprites = [{x:0,y:0,w:10,h:10},{x:20,y:0,w:30,h:40},....]
// where the position and size of each sprite is kept
// spriteInd is the index of the sprite
// x,y position on sprite center
// cx,cy location of sprite center (I also have that in the sprite list for some situations)
// sx,sy x and y scales
// r rotation in radians
// a alpha value
function drawSprite(image, spriteInd, x, y, cx, cy, sx, sy, r, a){
var spr = image.sprites[spriteInd];
var w = spr.w;
var h = spr.h;
ctx.setTransform(sx,0,0,sy,x,y); // set scale and position
ctx.rotate(r);
ctx.globalAlpha = a;
ctx.drawImage(image,spr.x,spr.y,w,h,-cx,-cy,w,h); // render the subimage
}
On just an average machine you can render 1000 +sprites at full frame rate with that function. On Firefox (at time of writing) I am getting 2000+ for that function (sprites are randomly selected sprites from a 1024 by 2048 sprite sheet) max sprite size 256 * 256
But I have well over 15 such functions, each with the minimum functionality to do what I want. If it is never rotated, or scaled (ie for UI) then
function drawSprite(image, spriteInd, x, y, a){
var spr = image.sprites[spriteInd];
var w = spr.w;
var h = spr.h;
ctx.setTransform(1,0,0,1,x,y); // set scale and position
ctx.globalAlpha = a;
ctx.drawImage(image,spr.x,spr.y,w,h,0,0,w,h); // render the subimage
}
Or the simplest play sprite, particle, bullets, etc
function drawSprite(image, spriteInd, x, y,s,r,a){
var spr = image.sprites[spriteInd];
var w = spr.w;
var h = spr.h;
ctx.setTransform(s,0,0,s,x,y); // set scale and position
ctx.rotate(r);
ctx.globalAlpha = a;
ctx.drawImage(image,spr.x,spr.y,w,h,-w/2,-h/2,w,h); // render the subimage
}
if it is a background image
function drawSprite(image){
var s = Math.max(image.width / canvasWidth, image.height / canvasHeight); // canvasWidth and height are globals
ctx.setTransform(s,0,0,s,0,0); // set scale and position
ctx.globalAlpha = 1;
ctx.drawImage(image,0,0); // render the subimage
}
It is common that the playfield can be zoomed, panned, and rotated. For this I maintain a closure transform state (all globals above are closed over variables and part of the render object)
// all coords are relative to the global transfrom
function drawGlobalSprite(image, spriteInd, x, y, cx, cy, sx, sy, r, a){
var spr = image.sprites[spriteInd];
var w = spr.w;
var h = spr.h;
// m1 to m6 are the global transform
ctx.setTransform(m1,m2,m3,m4,m5,m6); // set playfield
ctx.transform(sx,0,0,sy,x,y); // set scale and position
ctx.rotate(r);
ctx.globalAlpha = a * globalAlpha; (a real global alpha)
ctx.drawImage(image,spr.x,spr.y,w,h,-cx,-cy,w,h); // render the subimage
}
All the above are about as fast as you can get for practical game sprite rendering.
General tips
Never use any of the vector type rendering methods (unless you have the spare frame time) like, fill, stroke, filltext, arc, rect, moveTo, lineTo as they are an instant slowdown. If you need to render text create a offscreen canvas, render once to that, and display as a sprite or image.
Image sizes and GPU RAM
When creating content, always use the power rule for image sizes. GPU handle images in sizes that are powers of 2. (2,4,8,16,32,64,128....) so the width and height have to be a power of two. ie 1024 by 512, or 2048 by 128 are good sizes.
When you do not use these sizes the 2D context does not care, what it does is expand the image to fit the closest power. So if I have an image that is 300 by 300 to fit that on the GPU the image has to be expanded to the closest power, which is 512 by 512. So the actual memory footprint is over 2.5 times greater than the pixels you are able to display. When the GPU runs out of local memory it will start switching memory from mainboard RAM, when this happens your frame rate drops to unusable.
Ensuring that you size images so that you do not waste RAM will mean you can pack a lot more into you game before you hit the RAM wall (which for smaller devices is not much at all).
GC is a major frame theef
One last optimisation is to make sure that the GC (garbage collector) has little to nothing to do. With in the main loop, avoid using new (reuse and object rather than dereference it and create another), avoid pushing and popping from arrays (keep their lengths from falling) keep a separate count of active items. Create a custom iterator and push functions that are item context aware (know if an array item is active or not). When you push you don't push a new item unless there are no inactive items, when an item becomes inactive, leave it in the array and use it later if one is needed.
There is a simple strategy that I call a fast stack that is beyond the scope of this answer but can handle 1000s of transient (short lived) gameobjects with ZERO GC load. Some of the better game engines use a similar approch (pool arrays that provide a pool of inactive items).
GC should be less than 5% of your game activity, if not you need to find where you are needlessly creating and dereferencing.

How to detect if a texture has been touched libgdx WITHOUT scene2d

I want to know if there is a away to detect a touch on a certain texture without using scene2d. The Gdx.input.isTouched() detects a touch on the WHOLE screen, is there a way i could use something that detects a touch on a texture without scene2d?
Of course there is, I also never use screne2d.
in your update method
if(Gdx.input.isTouched())
{
Vector3 tmp=new Vector3(Gdx.input.getX(),Gdx.input.getY();
camera.unproject(tmp);
Rectangle textureBounds=new Rectangle(textureX,textureY,textureWidth,textureHeight);
// texture x is the x position of the texture
// texture y is the y position of the texture
// texturewidth is the width of the texture (you can get it with texture.getWidth() or textureRegion.getRegionWidth() if you have a texture region
// textureheight is the height of the texture (you can get it with texture.getHeight() or textureRegion.getRegionhHeight() if you have a texture region
if(textureBounds.contains(tmp.x,tmp.y))
{
// you are touching your texture
}
}

Is it more efficient to draw a circle with ccCircle?

I'm hoping to create about 50-80 'balls' on the screen and each ball is an object of a class extending CCNode. Each ball will be about 20 x 20px.
Would it be more efficient to
override void draw() and use ccDrawCircle()
or make a picture and make a CCSprite with it (it'll needed be added to the node)?
Most effective way to draw multiple nodes, that use single material (texture) is CCSpriteBatchNode.
// we create base bach node with texture
CCSpriteBatchNode *batch = CCSpriteBatchNode::create(textureFile, 50 /* initial capacity of node */);
// then we create our sprites with the same texture
CCSprite::sprite = CCSprite::create(textureFile);
batch->addChild(sprite);
CCSpriteBatchNode can contain only CCSprites with the same texture, that used for batch node, but all sprites are drawed in single function call (batch drawing).
Color and opacity of every sprite can be changed. To colorize sprites you can create white-colored texture of ball. When you use setColor method, white color will be transformed to color, that specified in setColor

Proper using of scene2d's Stage in a game with a huge world

If the whole "game world" is thousands of times wider than a viewport, and if I want to use scene2d to manage game objects as Actors, should I create Stage object as wide as the whole world, or should the Stage be some area around current viewport but not the whole world?
In other words, does a Stage with greater width and height consume more memory itself, even if I render objects only on a small viewport-sized part of it?
I think you misunderstood what exactly a Stage is. A Stage doesn't really have a size itself. You don't specify a width or height or the Stage, you only specify the width and height of the viewport. The viewport is like a window, which shows only a part of your world, aka scene. A Stage is a 2D scene graph and it "grows" with your Actors. The more Actors you have, the bigger (memory wise) your Stage is, but it doesn't depend on how far spreaded your Actors actually are. If they are very far spreaded and you only display a very small part of your whole Stage, it will be handled very efficient, because a scene graph sub-divides this huge space to be able to very quickly decide whether to ignore a certain Actor, or draw it on the Screen.
That means a Stage is actually exactly what you need for this kind of situation and you should probably not have any problems, FPS and memory wise. But of course if your Stage is 1000s of times the size of your viewport and you know yourself that certain Actors aren't displayed soon, then it might make sense to not add them to the Stage yet.
A stage is only a root node that will hold all the actors. It's role is to call methods for its children (like draw and act); thus only the number and complexity of actor have an impact on memory and frame rate.
For your situation a culling method is certainly required. The simplest one would be to check if an actor is in the viewport and if not skip drawing him. Create a custom actor and add this code: source
public void draw (SpriteBatch batch, float parentAlpha) {
// if this actor is not within the view of the camera we don't draw it.
if (isCulled()) return;
// otherwise we draw via the super class method
super.draw(batch, parentAlpha);
}
Rectangle actorRect = new Rectangle();
Rectangle camRect = new Rectangle();
boolean visible;
private boolean isCulled() {
// we start by setting the stage coordinates to this
// actors coordinates which are relative to its parent
// Group.
float stageX = getX();
float stageY = getY();
// now we go up the hierarchy and add all the parents'
// coordinates to this actors coordinates. Note that
// this assumes that neither this actor nor any of its
// parents are rotated or scaled!
Actor parent = this.getParent();
while (parent != null) {
stageX += parent.getX();
stageY += parent.getY();
parent = parent.getParent();
}
// now we check if the rectangle of this actor in screen
// coordinates is in the rectangle spanned by the camera's
// view. This assumes that the camera has no zoom and is
// not rotated!
actorRect.set(stageX, stageY, getWidth(), getHeight());
camRect.set(camera.position.x - camera.viewportWidth / 2.0f,
camera.position.y - camera.viewportHeight / 2.0f,
camera.viewportWidth, camera.viewportHeight);
visible = (camRect.overlaps(actorRect));
return !visible;
}
If you need to improve performance even further you can switch to manually deciding what is visible and what not (ex when moving the camera). This would be faster because all those culling calculations are executed at EVERY frame, for EVERY actor. So although it's a lot faster to do some math instead of drawing, a big number of actors would give a huge amount of unwanted calls.

WebGL: canvas coordinates to 3d coords

I am trying to find the "left" border of my WebGL view port because I would like to draw a number of debug information there. (an axis mini map like most modeling programs have)
I certainly can get the width and height of the canvas containing the WebGL viewport.
I would really like to know how I would go about calculating 2d canvas coordinates to 3d coordinates? What would be the best approach to find the left border in the 3d viewport?
Anyone looking into this should read
http://webglfactory.blogspot.com/2011/05/how-to-convert-world-to-screen.html or take a look at GluProject() and GluUnproject()
To clarify datenwolf's answer, the coordinate mapping between your 3D space and 2D canvas is exactly what you want it to be. You control it with gl.viewport and the matrices that you pass to your shader.
gl.viewport simply blocks out a rectangle of pixels on your canvas that you are drawing to. Most of the time this matches the dimensions of your canvas exactly, but there are some scenarios where you only want to draw to part of it. (Split-screen gaming, for example.) The area of your canvas that you're drawing to will be referred to as the viewport from here on out. You can assume it means the same thing as "canvas" if you'd like.
At it's simplest, the viewport always has an implicit coordinate system from -1 to 1 on both the X and Y axis. This is the space that the gl_Position output by your vertex shader operates in. If you output a vertex at (-1, -1) it will be in the bottom left corner of your viewport. a vertex at (1, 1) will be in the top right. (Yes, I'm ignoring depth for now) Using this, you could construct geometry designed to map to that space and draw it without any matrix transforms at all, but that can be a bit awkward.
To make life easier, we use projection matrices. A projection matrix is simply one that transforms your geometry from some arbitrary 3D space into that -1 to 1 space required by the viewport. The most common one is a perspective matrix. How you create it will look a bit different depending on the library you use, but typically it's something like this:
var fov = 45;
var aspectRatio = canvas.width/canvas.height;
var near = 1.0;
var far = 1024.0;
var projectionMat = mat4.perspective(fov, aspect, near, far);
I'm not going to get into what all those values mean, but you can clearly see that we're using the canvas width and height to help set up this projection. That allows it to not look stretched or squashed depending on the canvas size. What it all boils down to, however, is that taking any 3D point in space and multiplying it by this matrix will produce a point that maps to that -1 to 1 space, taking into account distance from the 'camera' and everything else. (It may actually fall outside of that bounds, but that simply means it's off camera.) It's what makes our 3D scenes look 3D.
It's also possible to create an projection matrix specifically for drawing 2D geometry, though. This is called an orthographic matrix, and the setup typically looks something like this:
var left = 0;
var top = 0;
var right = canvas.width;
var bottom = canvas.height;
var near = 1.0;
var far = 1024.0;
var projectionMat = mat4.ortho(left, right, bottom, top, near, far);
This matrix is different than the perspective matrix in that it ignores the z component of your position entirely. Instead, this matrix transforms flat coordinates, like pixels, into the -1 to 1 range. As such, your scenes don't look 3D but it's easier to control exacty where things appear on screen. So, using the matrix above, if we give it a vertex at (16, 16, 0) it will appear at (16, 16) on our canvas (assuming the viewport is the same dimensions as the canvas). As such, when you want to draw things like flat UI elements this is the type of matrix you want!
The nice part is that because these are just values that you pass to a shader you can use completely different matrices from one draw call to the next. Typically you'll draw all of your 3D geometry with a perspective matrix, then all of your UI with a orthographic matrix.
Apologies if that was a bit rambling. I've never been terribly good at explaining all that math-y stuff.
I am trying to find the "left" border of my WebGL view port because I would like to draw a number of debug information there. (an axis mini map like most modeling programs have) I certainly can get the width and height of the canvas containing the WebGL viewport.
Just switch the viewport and projection for those parts. You can change them anytime.
See http://games.greggman.com/game/webgl-fundamentals
Basically if you want to draw in 2D use a 2D shader, don't try messing with a 3D shader.
WebGL draws in clipspace so all you need to do is convert from pixels to clip space.
attribute vec2 a_position;
uniform vec2 u_resolution;
void main() {
// convert positions from pixels to 0.0 to 1.0
vec2 zeroToOne = a_position / u_resolution;
// convert from 0->1 to 0->2
vec2 zeroToTwo = zeroToOne * 2.0;
// convert from 0->2 to -1->+1 (clipspace)
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
}
Why not just use some overlaid HTML?
<html>
<head>
<style>
#container {
position: relative;
}
#debugInfo {
position: absolute;
top: 0px;
left: 0px;
background-color: rgba(0,0,0,0.7);
padding: 1em;
z-index: 2;
color: white;
}
</style>
</head>
<body>
<div id="container">
<canvas></canvas>
<div id="debugInfo">There be info here!</div>
</div>
</body>
</html>
You can then update it with
var debugInfo = document.getElementById("debugInfo");
debugInfo.innerHTML = "some info";