Rotating a texture around x, y, z axis and Using it to draw a polygon - actionscript-3

I'm trying to draw an arbitrary polygon with a transformed texture with Graphics API .
Here's what I'm trying to do in 3 steps:
First, I have a texture (as a BitmapData)
Second, Transform the texture - Tile it and rotate it around x, y or z axis. (y-axis for now).
Third, Draw a polygon using the transformed texture.
I could rotate it around z-axis with the code below:
var gr:Graphics = sp.graphics;
gr.clear();
var mat:Matrix = new Matrix();
mat.scale( 0.5, 0.5 );
mat.rotate( angle );
gr.beginBitmapFill( bd, mat, true, true );
gr.moveTo( points[0].x, points[0].y );
for ( var lp1:int = 1; lp1 < points.length; lp1++ )
gr.lineTo( points[lp1].x, points[lp1].y );
gr.lineTo( points[0].x, points[0].y );
gr.endFill();
But I couldn't rotate the texture around x or y axis as it requires some sort of projection I guess.
I thought about drawing a rotated Bitmap object onto a BitmapData and using it as a texture:
var bmp:Bitmap = new Bitmap( bd );
bmp.rotationY = angle;
var transformedBd:BitmapData = new BitmapData( 256, 256, true, 0 );
transformedBd.draw( bmp );
… and call gr.beginBitmapFill() with the transformedBd …
But with this code, the texture won't be tiled.
I also looked at drawTriangles() method but AFIK, it only let me draw a rotated polygon, not a polygon with rotated texture.
If anyone has insights on this issue, please share.
Any help will be greatly appreciated!

Perhaps you can:
put your 2D Texture inside a Sprite or other container
3D transform that container, for example by using
myContainer.rotationX = 20;
myContainer.rotationY = 200;
3 - then you create a new BitmapData()
4 - and you DRAW the entire myContainer into the bitmapdata.
myBitmapData.draw(myContainer, myMatrix, myColorTransform, blendMode, myRectangle, smooth);
5 - and finally you delete the original 2D texture and myContainer.
Voila, you now have a 3d transformed texture inside a single bitmapdata.

Related

3D ball rolling on wrong axis LibGDX

Hello I'm trying to make a billiards game using libgdx. I'm using 3d models for the balls and an Orthographic Camera to view them. I am having trouble getting them to roll correctly after rolling on a different axis. Here is a clip of what they look like when they're rolling.
As you can see they appear to be rotating as if they were on their starting axis. Is there any way to rotate it so that it looks like it's actually rolling. I am also not very familiar with transformation matrices or quaternions so im not too sure where to go.
Edit: Updated for clarity
Here is the code I use to update the rotation
public boolean update() {
if (!visible) {
return false;
}
Vector2 vBall = ballBody.getLinearVelocity();
float vAngle = ballBody.getAngularVelocity();
isMoving = true;
float x = ballBody.getPosition().x * SCALE;
float y = ballBody.getPosition().y * SCALE;
Vector2 axisInPlane = new Vector2(y - center.y, x - center.x).rotateRad(Math.PI/2f);
Vector3 axis3D = new Vector3(axisInPlane.x,axisInPlane.y,0f);
ball3D.transform.rotate(axis, (float) Math.toDegrees(dist / RADIUS_PX));
ball3D.transform.setTranslation(mapX(x), mapY(y), 0);
Just to be sure, center is an arbitrary fixed point where there is no rotation and all rotations are derived from this distance/angle as the ball has no slippage.
So you can directly get the axis with
Vector2 axisInPlane = new Vector2(y - center.y, x - center.x).rotateRad(Math.PI/2f);
Vector3 axis3D = new Vector3(axisInPlane.x,axisInPlane.y,0f);
Also Math.toDegree takes radians as an argument, not a float, so dist/RADIUS_PX will be off, you have to supply as a fraction of 2PI (360 degs in radians). Also this should be the circumference of the ball not the radius. I don't know what class ball3D is but I would check that ball3D.transform.rotate does take degrees as an argument and if it does replace that line with
float rotateRadians =(float) Math.toDegrees((dist/CIRCUMFERENCE_PX)*Math.PI*2f);
ball3D.transform.rotate(axis, rotateRadians );

WebGL Three.js : Texture alingment on a geometry face

I would like to write text on each faces of an IcosahedronGeometry
I'm able to generate the textures and apply the textures to all the faces :
for ( var i = 0; i < geometry.faces.length; i ++ ) {
geometry.faces[i].materialIndex = i;
materials.push( new THREE.MeshBasicMaterial( { overdraw: true, map: getTexture(i), wireframe: true, wireframeLinewidth: 1} ) );
}
// 3D element
element = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial(materials) );
However each textures are overwriting the other ... And I can't align them correctly
http://jsfiddle.net/jzbf7/
Any idea ?
You need to understand how the UVs are set up for IcosahedronGeometry -- they are very similar to the UVs for SphereGeometry, in which a map of the world will cover the entire sphere.
This is very different from the UVs for CubeGeometry, where the texture maps to each face.
Experiment with the updated fiddle to see for yourself: http://jsfiddle.net/jzbf7/2/
(If the sphere renders too dark, render it again -- the colors are random.)
Also, there is a bug in the IcosahedronGeometry UV map. This can be seen at the "seam".
three.js r.56

How to create intensity mask for heatmap?

I'm trying to develop heat map, now initially I would have to draw the intensity mask, and since I'm using GWT so I have randomly generated some coordinates and placed my circles ( with required gradience ) at those locations so the output comes out to be circles overlapping each other. And If I look at the intensity mask from Dylan Vester, it comes to be very smooth How can I draw my heat map ?? Also how the output is achieved similar to Dylan Vester?? Question also is if I'm drawing circles then how to decide the intensity at the intersection of two or more circles, how they have achieved ?? Here is my code
// creating the object for the heat points
Heat_Point x = new Heat_Point();
// Variables for random locations
int Min = 1,Max = 300;
int randomx,randomy;
// Generating set of random values
for( int i = 0 ; i < 100 ; i++ ) {
// Generating random x and y coordinates
randomx = Min + (int)(Math.random() * ((Max - Min) + 1));
randomy = Min + (int)(Math.random() * ((Max - Min) + 1));
// Drawing the heat points at generated locations
x.Draw_Heatpoint(c1, randomx, randomy);
}
And Here is how I'm plotting my heat point that is Heat_Point class
Context con1 = c1.getContext2d(); // c1 is my canvas
CanvasGradient x1;
x1 = ((Context2d) con1).createRadialGradient(x,y,10,x,y,20);
x1.addColorStop(0,"black");
x1.addColorStop(1,"white");
((Context2d) con1).beginPath();
((Context2d) con1).setFillStyle(x1);
((Context2d) con1).arc(x,y,20, 0, Math.PI * 2.0, true);
((Context2d) con1).fill();
((Context2d) con1).closePath();`
here I was supposed to add some images but I didn't have enough reputation :D :P
I took a quick look at HeatmapJS (http://www.patrick-wied.at/static/heatmapjs/) and it seems he uses radial gradients (like you have above) and he also uses opacity and a color filter called "multiply blend" to smooth out the intensity of the colors in the heat map.
His code is quite impressive. It's open source, so you might want to check it out!

canvas isPointInPath does not work with ctx.drawImage()

I suppose this doesn't work because canvas is drawing a bitmap of a vector (and a bitmap is not a path).
Even if it did work, the bitmap is likely always has a rectangular permitter.
Is there any way to leverage something like isPointInPath when using drawImage?
example:
The top canvas is drawn using drawImage and isPointInPath does not work.
The bottom canvas is drawn using arc and isPointInPath works.
a link to my proof
** EDIT **
I draw a circle on one canvas, and use isPointInPath to see if the mouse pointer is inside the circle (bottom canvas in my example).
I also "copy" the bottom canvas to the top canvas using drawImage. Notice that isPointInPath will not work on the top canvas (most likely due to reasons I mentioned above). Is there a work-around I can use for this that will work for ANY kind of path (or bitmap)?
A canvas context has this hidden thing called the current path. ctx.beginPath, ctx.lineTo etc create this path.
When you call ctx.stroke() or ctx.fill() the canvas strokes or fills that path.
Even after it is stroked or filled, the path is still present in the context.
This path is the only thing that isPointInPath tests.
If you want to test if something is in an image you have drawn or a rectangle that was drawn with ctx.fillRect(), that is not possible using built in methods.
Typically you'd want to use a is-point-in-rectangle function that you write yourself (or get from someone else).
If you're looking for how to do pixel-perfect (instead of just the image rectangle) hit detection for an image there are various methods of doing that discussed here: Pixel perfect 2D mouse picking with Canvas
You could try reimplementing ctx.drawImage() to always draw a box behind the image itself, like so (JSFiddle example):
ctx.customDrawImage = function(image, x, y){
this.drawImage(image, x, y);
this.rect(x, y, image.width, image.height);
}
var img1 = new Image();
img1.onload = function(){
var x = y = 0;
ctx.drawImage(img1, x, y);
console.log(ctx.isPointInPath(x + 1, y + 1));
x = 1.25 * img1.width;
ctx.customDrawImage(img1, x, y);
console.log(ctx.isPointInPath(x + 1, y + 1));
Note: you might get side effects like the rectangle appearing over the image, or bleeding through from behind if you are not careful.
To me, isPointInPath failed after canvas was moved. So, I used:
mouseClientX -= gCanvasElement.offsetLeft;
mouseclientY -= gCanvasElement.offsetTop;
I had some more challenges, because my canvas element could be rescaled. So first when I draw the figures, in my case arc, I save them in an array together with a name and draw them:
if (this.coInit == false)
{
let co = new TempCO ();
co.name= sensor.Name;
co.path = new Path2D();
co.path.arc(c.X, c.Y, this.radius, 0, 2 * Math.PI);
this.coWithPath.push(co);
}
let coWP = this.coWithPath.find(c=>c.name == sensor.Name);
this.ctx.fillStyle = color;
this.ctx.fill(coWP.path);
Then in the mouse event, I loop over the items and check if the click event is in a path. But I also need to rescale the mouse coordinates according to the resized canvas:
getCursorPosition(event) {
const rect = this.ctx.canvas.getBoundingClientRect();
const x = ((event.clientX - rect.left ) / rect.width) * this.canvasWidth;
const y = ((event.clientY - rect.top) / rect.height) * this.canvasHeight;
this.coWithPath.forEach(c=>{
if (this.ctx.isPointInPath(c.path, x, y))
{
console.log("arc is hit", c);
//Switch light
}
});
}
So I get the current size of the canvas and rescale the point to the original size. Now it works!
This is how the TempCO looks like:
export class TempCO
{
path : Path2D;
name : string;
}

circular colorTransform

Is there a way to apply a colorTransform to a BitmapData in a circle rather than in a rectangle?
Instead of erasing rectangular parts of an image by reducing the alpha channel as in the code below, I'd like to do it in circles.
_bitmap.colorTransform(new Rectangle(mouseX-d/2, mouseY-d/2, d, d),
new ColorTransform(1, 1, 1, .5, 0, 0, 0, 1));
I do have some code which loops through the pixels, extracts the alpha value and uses setPixel but it seams significantly slower than the colorTransform function.
Try creating a circle using the drawing API (flash.display.Graphics) and then drawing that onto the bitmap data with BlendMode.ERASE. That might solve your problem, if I understand it correctly.
var circle : Shape = new Shape;
circle.graphics.beginFill(0xffcc00, 1);
circle.graphics.drawEllipse(-50, -50, 100, 100);
// Create a transformation matrix for the draw() operation, with
// a translation matching the mouse position.
var mtx : Matrix = new Matrix();
mtx.translate(mouseX, mouseY);
// Draw circle at mouse position with the ERASE blend mode, to
// set affected pixels to alpha=0.
myBitmap.draw(circle, mtx, null, BlendMode.ERASE);
I'm not 100% sure that the ERASE blend mode works satisfyingly with the draw() command, but I can't see why it shouldn't. Please let me know how it works out!