I'm creating an android side scrolling game using the libgdx library. I am using immediateModeRenderer20 in GL_TRIANGLE_STRIP mode to render 2D triangle strips that scroll infinitely. The renderering works fine, I have figured out how to use solid colors, gradients and alternating patterns on the strip.
Is there any way to render a triangle strip but overlay it with a .png or a Texture or something like that?
I have looked into the texCoord(...) method in the immediateModeRenderer20 docs but I haven't found any solid examples on how to use it.
If anyone needs any code snippets or images, let me know.
Yes, it's possible, I've recently attempted the same.
The loop for rendering it looks simply:
texture.bind();
immediateModeRenderer20.begin(camera().combined, GL20.GL_TRIANGLE_STRIP);
immediateModeRenderer20.color(new Color(1, 1, 1, 1));
immediateModeRenderer20.texCoord(textureCoordinate.x, textureCoordinate.y);
immediateModeRenderer20.vertex(point.x, point.y, 0f);
immediateModeRenderer20.end();
But the important thing is that you build your texture coordinates to match your triangles. In my case I would draw a rope like this one:
http://imgur.com/i0ohFoO
from a texture of a straight rope. To texture each triangle you will need texture coordinates x and y - remember that textures use different coordinates: from 0.0 to 1.0 for both x and y.
http://imgur.com/wxQ93KO
So your triangle vertex will need textureCoord value of:
x: 0.0, y: 0.0
x: 0.0, y: 1.0
x: triangle length, y: 0.0
x: triangle length, y: 1.0
and so on.
Related
I am trying to Slant/Skew a texture to create some shadows for my game.
I have read over this helpful answer that shows this can be done by passing a matrix to spriteBatch.Begin().
Because my linear algebra skills are not very developed, I am having some troubles meeting my desired results. I am hoping to skew my shadow so it looks similar to the following. Where the shadow is slanted by an angle, but the bottom of the shadow lines up with the (feet in this case) bottom of the sprite.
I originally tied the skew matrix provided in the solution above:
Matrix skew = Matrix.Identity;
skew.M12 = (float)Math.Tan(MathHelper.ToRadians(36.87f));
But this ends up rotation the shadow against the world's origin. I see the solution also notes this, and provides the follow to rotate again the sprite.
Matrix myMatrix = Matrix.CreateTranslation(-100, -100, 0)
* Matrix.CreateScale(2f, 0.5f, 1f)
* Matrix.CreateTranslation(100, 100, 0);
Though I'm not sure where to apply this myMatrix Matrix. I have tried applying it to both the shadow sprite, the castingShadow sprite, and also multiplying them together and applying to the shadow with no luck.
I have also tried using other methods like Matrix.CreateRotationX(MathHelper.ToRadians(0.87f)) with no luck.
There is actually a Matrix.CreateShadow() method too, but it requires a Plane, which I have no semblance of in my game.
Can anyone can help me figure out the required Matrix for this slanting, or point me in the direction of some resources?
Thanks!
Okay, so I found a transform to use to get the desired slant.
Thanks to #David Gouveia and #AndreRussell from this post
Matrix matrix = Matrix.CreateRotationX(MathHelper.ToRadians(60)) *
Matrix.CreateRotationY(MathHelper.ToRadians(30)) *
Matrix.CreateScale(1,1,0);
EDIT:
So the above solution solved how I wanted to slant my texture, but had some weird positioning side effects. To address this, I ended up with a transform like the following:
Matrix slant = Matrix.CreateTranslation(-loc.X + angleX, -loc.Y, 0f) *
Matrix.CreateRotationX(MathHelper.ToRadians(angleX)) *
Matrix.CreateRotationY(MathHelper.ToRadians(30)) *
Matrix.CreateScale(1.4f, 1f, 0) *
Matrix.CreateTranslation(loc.X + angleX, loc.Y, 0f);
Where angleX was set based on the "sun" X position and loc vector is where I want the object and object's shadow to appear.
In my TextureAtlas the Sprite's for my Animation are rotated 90 degrees.
When I draw my Animation it's still rotaed by 90 degrees. How can I fix that?
My code looks like that:
TextureAtlas spritesheet = new TextureAtlas(Gdx.files.internal("images/spritesheet/spritesheet.atlas"));
Array<AtlasRegion> CLOUD_ANIMATION_REGIONS = spritesheet.findRegions("cloud_animation");
Animation animation = new Animation(0.1f,ImageProvider.CLOUD_ANIMATION_REGIONS);
In the render method:
batch.draw(animation.getKeyFrame(elapsedTime, true), x, y);
The animation works perfectly fien but it's rotated by 90 degree like in the spritesheet.
I realize that if I have a Sprite I can call Sprite.draw(batch) and it will fix the rotation but I don't seem to be able to use that mechanism for Animation's?
EDIT:
Like Alexander said, this will do the trick:
batch.draw(textureRegion, x, y, 0, 0,textureRegion.getRegionWidth(), textureRegion.getRegionHeight(), 1, 1, 90);
Ok, here is untested code:
TextureRegion textureRegion = animation.getKeyFrame(elapsedTime, true);
if (textureRegion instanceof TextureAtlas.AtlasRegion && ((TextureAtlas.AtlasRegion) textureRegion).rotate)
{
batch.draw(textureRegion, x, y, 0, 0, textureRegion.getRegionWidth(), textureRegion.getRegionHeight(), 1, 1, 90, true);
}
else
{
batch.draw(textureRegion, x, y);
}
What I'm doing here: I check if atlas packer marked the region as rotated and then draw it rotated 90 angle clockwise to compensate original 90 angle counter-clockwise rotation. See AtlasRegion's javadoc and special version of draw method that can rotate TextureRegion.
EDITED: fix arguments based on Markus comment
Somehow you should be using AtlasSprite I think. That carries out the unrotate in its constructor. You dont want to be rotating every frame - thats some overhead. Also the AtlasSprite should take care of trimmed regions in the atlas : something thats very important to maximise a single atlas texture. Alas it doesnt seem very easy to use as it seems one needs a seperate sprite for each frame which seems massive overhead.
I've created a 3D map and I'm labelling points on this map through Sprites. This in itself works fine, except for the positioning of the sprite labels.
Because I'm creating a map the camera can tilt from 0 to 90 degrees, while ideally the label always stays some distance directly above the item it is labelling on the screen. But unfortunately, as sprites are always centred around their origin and that overlaps the item, I have to move the sprite up on the Y world axis and with that the centre location of the sprite changes as the camera is tilted. This looks weird if the item looked at is off centre, and doesn't work too well when the camera is looking straight down.
No jsfiddle handy, but my application at http://leeft.eu/starcitizen/ should give a good impression of what it looks like.
The code of THREE.SpritePlugin suggests to me it should be possible to use "matrixWorld" to shift the sprite some distance up on the screen's Y axis while rendering, but I can't work out how to use that, nor am I entirely sure that's what I need to use in the first place.
Is it possible to shift the sprites up on the screen while rendering, or perhaps change their origin? Or is there maybe some other way I can achieve the same effect?
Three.js r.67
As suggested by WestLangley, I've created a workable solution by changing the sprite position based on the viewing angle though it took me hours to work out the few lines of code needed to get the math working. I've updated my application too, so see that for a live demo.
With the tilt angle phi and the heading angle theta as computed from the camera in OrbitControls.js the following code computes a sprite offset that does exactly what I want it to:
// Given:
// phi = tilt; 0 = top down view, 1.48 = 85 degrees (almost head on)
// theta = heading; 0 = north, < 0 looking east, > 0 looking west
// Compute an "opposite" angle; note the 'YXZ' axis order is important
var euler = new THREE.Euler( phi + Math.PI / 2, theta, 0, 'YXZ' );
// Labels are positioned 5.5 units up the Y axis relative to its parent
var spriteOffset = new THREE.Vector3( 0, -5.5, 0 );
// Rotate the offset vector to be opposite to the camera
spriteOffset.applyMatrix4( new THREE.Matrix4().makeRotationFromEuler( euler ) );
scene.traverse( function ( object ) {
if ( ( object instanceof THREE.Sprite ) && object.userData.isLabel ) {
object.position.copy( spriteOffset );
}
} );
Note for anyone using this code: that the sprite labels are children of the object group they're referring to, and this only sets a local offset from that parent object.
I had a similar problem, but with flat sprites; I put trees on a map and wanted them to rotate in such a way that they'd rotate around their base, rather than their center. To do that, i simply edited the image files of the trees to be twice as tall, with the bottom as just a transparency:
http://imgur.com/ogFxyFw
if you turn the first image into a sprite, it'll rotate around the tree's center when the camera rotates. The second tree will rotate around it's base when the camera rotates.
For your application, if you resize the textbox in such a way that the center of it would be coincide with the star; perhaps by adding a few newlines or editing the height of the sprite
This is very much a hack, but if you will only use sprites in this way, and could tolerate a global change to how sprites were rendered, you could change the following line in the compiled three.js script:
Find (ctrl+F) THREE.SpritePlugin = function, and you'll see:
this.init = function ( renderer ) {
_gl = renderer.context;
_renderer = renderer;
vertices = new Float32Array( [
- 0.5, - 0.5, 0, 0,
0.5, - 0.5, 1, 0,
0.5, 0.5, 1, 1,
- 0.5, 0.5, 0, 1
] );
I changed the definition of the array to the following:
var vertices = new Float32Array( [
- 0.5, - 0.0, 0, 0,
0.5, - 0.0, 1, 0,
0.5, 1.0, 1, 1,
- 0.5, 1.0, 0, 1
] );
And now all my sprites render with the rotation origin at the bottom.
If you use the minified version, search for THREE.SpritePlugin=function and move the cursor right until you find the Float32Array defined, and make the same changes there.
Note: this changes how things render only when using WebGL. For the canvas renderer you'll have to play a function called renderSprite() in the THREE.CanvasRenderer. I suspect playing with these lines will do it:
var dist = 0.5 * Math.sqrt( scaleX * scaleX + scaleY * scaleY ); // allow for rotated sprite
_elemBox.min.set( v1.x - dist, v1.y - dist );
_elemBox.max.set( v1.x + dist, v1.y + dist );
This function will also be a lot more difficult to find in the minified version, since renderSprite() is not an outward facing function, it'll likely be renamed to something obscure and small.
Note 2: I did try making these modifications with "polyfills" (or rather, redefining the SpritePlugin after Three is defined), but it caused major problems with things not being properly defined for some reason. Scoping is also an issue with the "polyfill" method.
Note 3: My version of three.js is r69. So there may be differences above.
I'm trying to have a plane face away from the camera with same orientation so it's aligned in the viewport.
I have a plane in front of the camera, perfectly aligned to the cameras viewport, and I want to flip it in front of the camera, along the objects Y axis, regardless of camera orientation.
The following will orient my plane to face at the camera and works for any orientation:
target.rotation.copy(camera.rotation);
The following will then flip the plane along the plane's Y axis:
target.rotation.y += Math.PI;
All good so far? Except when the camera rotation has a funky tilt to it, let's say it's looking up and to the left, tilted slightly to the right, the plane's flip is tilted, but not the same way as the camera, leaving me with a plane tilted either to the left or right...
I've tried several things such as:
target.rotation.z -= camera.rotation.z;
Nothing... Thanks for your help.
So the problem I was running into was when the camera was in negative z coordinates. This causes the flip on the Y axis to get messed up.
So basically you would do something like this:
var target = new THREE.Object3D();
//position
target.position.copy(s.camera.position);
target.position.add(THREE.Utils.cameraLookDir(s.camera).multiplyScalar(300));
//rotation
target.rotation.copy(s.camera.rotation);
target.rotation.y += PI;
target.rotation.z = -s.camera.rotation.z;
if (s.camera.position.z < 0) {
target.rotation.z = s.camera.rotation.z;
}
EDIT:
Add the following to appropriate spots in your program.
camera.rotation.eulerOrder = 'XZY';
target.rotation.eulerOrder = 'XZY';
Seems to solve previously encountered tilt issues! (see below)
RESOLVED:
Flipped planes tilted the wrong way in some instances, for example when in negative z coords and also the y rotation is not equal to 0, example: point in space hovering and looking at 0, 0, 0.
This is the solution I was looking for when I found this page (taken from this answer):
mesh.lookAt( camera.position );
The local z-axis of the mesh should then point toward the camera.
Please check this neat piece of code I found:
glEnable(GL_LINE_SMOOTH);
glColor4ub(0, 0, 0, 150);
mmDrawCircle( ccp(100, 100), 20, 0, 50, NO);
glLineWidth(40);
ccDrawLine(ccp(100, 100), ccp(100 + 100, 100));
mmDrawCircle( ccp(100+100, 100), 20, 0, 50, NO);
where mmDrawCircle and ccDrawLine just draws these shapes [FILLED] somehow... (ccp means a point with the given x, y coordinates respectively).
My problem .... Yes, you guessed it, The line overlaps with the circle, and both are translucent (semi transparent). So, the final shape is there, but the overlapping part becomes darker and the overall shape looks ugly.. i.e, I would be fine if I was drawing with 255 alpha.
Is there a way to tell OpenGL to render one of the shapes in the overlapping parts??
(The shape is obviously a rectangle with rounded edges .. half-circles..)
You could turn on GL_DEPTH_TEST and render the line first and a little closer to the camera. When you then render the circle below, the fragments of the line won't be touched.
(You can also use the stencil buffer for an effect like this).
Note that this might still look ugly. If you want to use anti-aliasing you should think quite hard on which blending modes you apply and in what order you render the primitives.