LWJGL Picking - Select Certain Block When Hovering ( gluUnProject() ) - lwjgl

This video will show my current situation, and I currently can't find any answers to it online.
https://www.youtube.com/watch?v=O8Mh-1Emoc8&feature=youtu.be
My Code:
public Vector3D pickBlock() {
glDisable(GL_TEXTURE);
IntBuffer viewport = BufferUtils.createIntBuffer(16);
FloatBuffer modelview = BufferUtils.createFloatBuffer(16);
FloatBuffer projection = BufferUtils.createFloatBuffer(16);
FloatBuffer winZ = BufferUtils.createFloatBuffer(1);
float winX, winY;
FloatBuffer position = BufferUtils.createFloatBuffer(3);
glGetFloat(GL_MODELVIEW_MATRIX, modelview);
glGetFloat(GL_PROJECTION_MATRIX, projection);
glGetInteger(GL_VIEWPORT, viewport);
winX = (float)Display.getWidth() / 2;
winY = (float)viewport.get(3) - (float)Display.getHeight() / 2;
glReadPixels(Display.getWidth() / 2, (int)winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, winZ);
gluUnProject(winX, winY, winZ.get(), modelview, projection, viewport, position);
glEnable(GL_TEXTURE);
return new Vector3D(position.get(0) / 2 + 0.5f, position.get(1) / 2 + 0.5f, position.get(2) / 2 + 0.5f);
}
It returns "/ 2 + 0.5f" because that is needed because of the offsets I have for the blocks (if I removed the 0.5f, the offset would be in the center instead of the corner)

I seams to me that the error, based on the video, comes from when you are facing in the positive z direction (or whatever your back direction is). My guess is that you aren't taking the facing direction into account as I see in your code that you are just adding a constant 0.5F to the position of your cursor.
Therfore, when you are facing backwards, it adds 0.5 which makes it be behind the wall (since back is negative Z). one simple check would be weather the Z component of your forward vector is positive or negative, and deciding the factor added to the cursor based on that, then doing the same for the X.
Depending on how you implemented your camera (IE: if you used Euler angles (rx, ry, rz) or if you used Quaternions / forward vectors), the way you would do that check would vary, feel free to ask me for examples based on your system if you need.
hope this helped!
PS: if you're using angles, you can either check for the range of the y-axis rotation value and determine which direction you are facing and thus weather to add or subtract, OR you can calculate the forward vector based on your angles, and then check the for sign of the component.

Related

In Starling, how do you transform Filters to match the target Sprite's rotation & position?

Let's say your Starling display-list is as follows:
Stage
|___MainApp
|______Canvas (filter's target)
Then, you decide your MainApp should be rotated 90 degrees and offset a bit:
mainApp.rotation = Math.PI * 0.5;
mainApp.x = stage.stageWidth;
But all of a sudden, the filter keeps on applying itself to the target (canvas) in the angle it was originally (as if the MainApp was still at 0 degrees).
(notice in the GIF how the Blur's strong horizontal value continues to only apply horizontally although the parent object turned 90 degrees).
What would need to be changed to apply the filter to the target object before it gets it's parents transform? That way (I'm assuming) the filter's result would get transformed by the parent objects.
Any guess as to how this could be done?
https://github.com/bigp/StarlingShaderIssue
(PS: the filter I'm actually using is custom-made, but this BlurFilter example shows the same issue I'm having with the custom one. If there's any patching-up to do in the shader code, at least it wouldn't necessarily have to be done on the built-in BlurFilter specifically).
I solved this myself with numerous trial and error attempts over the course of several hours.
Since I only needed the shader to run in either at 0 or 90 degrees (not actually tweened like the gif demo shown in the question), I created a shader with two specialized sets of AGAL instructions.
Without going in too much details, the rotated version basically requires a few extra instructions to flip the x and y fields in the vertex and fragment shader (either by moving them with mov or directly calculating the mul or div result into the x or y field).
For example, compare the 0 deg vertex shader...
_vertexShader = [
"m44 op, va0, vc0", // 4x4 matrix transform to output space
"mov posOriginal, va1", // pass texture positions to fragment program
"mul posScaled, va1, viewportScale", // pass displacement positions (scaled)
].join("\n");
... with the 90 deg vertex shader:
_vertexShader = [
"m44 op, va0, vc0", // 4x4 matrix transform to output space
"mov posOriginal, va1", // pass texture positions to fragment program
//Calculate the rotated vertex "displacement" UVs
"mov temp1, va1",
"mov temp2, va1",
"mul temp2.y, temp1.x, viewportScale.y", //Flip X to Y, and scale with viewport Y
"mul temp2.x, temp1.y, viewportScale.x", //Flip Y to X, and scale with viewport X
"sub temp2.y, 1.0, temp2.y", //Invert the UV for the Y axis.
"mov posScaled, temp2",
].join("\n");
You can ignore the special aliases in the AGAL example, they're essentially posOriginal = v0, posScaled = v1 variants and viewportScale = vc4constants, then I do a string-replace to change them back to their respective registers & fields ).
Just a human-readable trick I use to avoid going insane. \☻/
The part that I struggled with the most was calculating the correct scale to adjust the UV's scale (with proper detection to Stage / Viewport resize and render-texture size shifts).
Eventually, this is what I came up with in the AS3 code:
var pt:Texture = _passTexture,
dt:RenderTexture = _displacement.texture,
notReady:Boolean = pt == null,
star:Starling = Starling.current;
var finalScaleX:Number, viewRatioX:Number = star.viewPort.width / star.stage.stageWidth;
var finalScaleY:Number, viewRatioY:Number = star.viewPort.height / star.stage.stageHeight;
if (notReady) {
finalScaleX = finalScaleY = 1.0;
} else if (isRotated) {
//NOTE: Notice how the native width is divided with height, instead of same side. Weird, but it works!
finalScaleY = pt.nativeWidth / dt.nativeHeight / _imageRatio / paramScaleX / viewRatioX; //Eureka!
finalScaleX = pt.nativeHeight / dt.nativeWidth / _imageRatio / paramScaleY / viewRatioY; //Eureka x2!
} else {
finalScaleX = pt.nativeWidth / dt.nativeWidth / _imageRatio / viewRatioX / paramScaleX;
finalScaleY = pt.nativeHeight / dt.nativeHeight / _imageRatio / viewRatioY / paramScaleY;
}
Hopefully these extracted pieces of code can be helpful to others with similar shader issues.
Good luck!

maintaining relative position when changing scaleX and scaleY?

I am trying to implement a simple "zoom" function in a map presentation type app. The user interacts with a NumericStepper to dial in a scale value and I then use that value to set the scaleX and scaleY properties of my map sprite. The parent of the map sprite has a scrollRect defined so the map is cropped as it scales. That all seems to work fine.
Naturally when I change the scale, the visible content shifts as the sprite becomes larger or smaller. I would like to keep the content in relatively the same screen location. I've taken a first pass at it below but it's not quite right.
Question: Am I on the right track here thinking that I can determine how much to shift the x/y by comparing the change in the width/height of the sprite after scaling? (as I write this I am thinking I can determine the center of the sprite before scaling, then reposition it so it stays centered over that point. Hmm. . .).
protected function scaleStepper_changeHandler(event:Event):void
{
var cX:Number = wrapper.x + (wrapper.width /2);
var cY:Number = wrapper.y + (wrapper.height /2);
wrapper.scaleX = scaleStepper.value;
wrapper.scaleY = scaleStepper.value;
wrapper.x = cX - (wrapper.width /2);
wrapper.y = cY - (wrapper.height /2);
}
You are on the right track, but for a better solution you should use a matrix to transform your Sprite. Use the following code below to achieve what you need:
private var originalMatrix:Matrix;
private function scaleAroundPoint(target:Sprite, scalePoint:Point, scaleFactor:Number):void
{
if(originalMatrix == null)
originalMatrix = target.transform.matrix;
var matrix:Matrix = originalMatrix.clone();
matrix.translate(-scalePoint.x, -scalePoint.y);
matrix.scale(scaleFactor, scaleFactor);
matrix.translate(scalePoint.x, scalePoint.y);
target.transform.matrix = matrix;
}
You can call this method like this:
scaleAroundPoint(wrapper, new Point(yourWidth/2, yourHeight/2), scaleStepper.value);
Hope this helps and solves your problem.
Am I on the right track here thinking that I can determine how much to shift the x/y by comparing the change in the width/height of the sprite after scaling?
Yes. As all values are known, you don't really have to "test" after scaling. You basically want to distribute the movement of the bounding box borders evenly.
Here's an example in one dimension, scaling factor 2, X is the registration point, | a boundary:
before scaling |--X--|
after scaling |----X----|
No problem there. Now what if the registration point is not in the middle?
before scaling |-X---|
after scaling |--X------|
As a last example, the edge case with the registration point on the boundary:
before scaling |X----|
after scaling |X--------|
Note how the boundaries of all 3 examples are equal before scaling and within each example, the registration point remains constant.
The problem is clearly identified. Now how to solve this?
We do know how much the width changes
before scaling width
after scaling width * scaleFactor
and from the first example we can determine where the left boundary should be after scaling (assuming that the registration point is at 0, so the object is centered):
before scaling -width * 0.5
after scaling -width * 0.5 * scaleFactor
This value depends on where the registration point of course is within the display object relative to the left boarder. To circumvent this dependency, subtract the values from each other to know how much the left boundary is moved to the left after scaling while keeping the object centered:
boundary shift width * 0.5 * (scaleFactor - 1)
Comparing before and after scaling, the left boundary should be further to the left by that amount and the right boundary should be further to the right by that amount.
The problem is that you cannot really set the left or right boundary directly.
You have to set the registration point, which will influence where the boundaries are. To know how far you should move the registration point, imagine both edge cases:
before scaling |X----|
after scaling |X--------|
corrected, |X--------|
before scaling |----X|
after scaling |--------X|
corrected, |--------X|
In both cases, the registration point has to be moved by the amount which the boundary should move, because essentially, the registration point is on the boundary and thus behaves the same way.
Any value in between can be found by linearly interpolating between both cases:
-[width * 0.5 * (scaleFactor - 1)] <= value <= +[width * 0.5 * (scaleFactor - 1)]
-[width * 0.5 * (scaleFactor - 1)] * (1-t) + [width * 0.5 * (scaleFactor - 1)] * t
To find the interpolation value t, which is 0 if X is on the left and 1 when on the right:
t = (X - L) / width
Add -[width * 0.5 * (scaleFactor - 1)] * (1-t) + [width * 0.5 * (scaleFactor - 1)] * t to the x position of the registration point and the scale the object.
Do the same for y in a similar fashion.

Gravity trajectory with already known destination

I have been spending several days trying to solve this problem and I am about to go mad. Your help would be very much appreciated.
I am using a 2D stage in libgdx. I want to move actors (or sprite) to this stage with a "gravity" display effect: for example for actor1, his initial coordinates are (0, 0), destination coordinates would be (100, 50), and I want to move this actor to this destination with a gravity trajectory effect. Then I want to use the same gravity for actor2 moving from (0, 0) to (25, 75), then actor3 from (0, 0) to (200, 75) etc.
I managed to apply a gravity trajectory to any actor based on this well known loop:
setX(getX() + velocity.x);
setY(getY() + velocity.y);
velocity.y += getGravity().y * delta;
So tweaking the gravity value would modify the trajectory. It works fine.
Now, as I said earlier I want to give every actors a unique trajectory given their predetermined destination.
So I have tried to find a formula to determine the x and y for each actor at every frame of their trajectory
I am using the following static parameters:
gravity.y : same for all actors
delay : the amount of frames during which each actor moves between his initial coordinates and his destination coordinates. Same value for all actors too
First I calculate the velocity with this SUPER UGLY formula that I am absolutely not proud of:
velocity = new Vector2 ( (destinationx - b.getX() )/time, initdisty/time + ( Math.sqrt(delta*1000)*time / ( 500/Math.abs(gravity) ) ));
where delta = Gdx.graphics.getDeltaTime();
Then I apply this velocity each frame to calculate the x and y of each actor:
public void act(float delta){
for (int i=0; i<delay; i++) {
setX(getX() + velocity.x);
setY(getY() + velocity.y);
velocity.y += gravity.y * delta;
}
}
It KIND OF work, but of course, this can not be a long term solid solution. Calculating the x and y for each frame for each actor (there can be 5-6 actors moving at the same time) doesn't look good at all.
The main problem is that the trajectories are good on computer with consistent 60FPS, they are okay on a tablet, but on a phone with limited memory and 30 < fps < 60, the trajectories become terribly wrong.
After reading several blog posts, it seems like I could avoid the multi device memory fps problems by removing the delta parameter from my formulas, but I haven't found how. And it still doesn't give me a strong long term solution to calculate the trajectory with predetermined destination coordinates.
Thanks for reading and for your time, please let me know if this is unclear I'll do my best to explain better.
Cause of the problem
Maintaining both position and velocity leads to discretization of the system resulting in quantization error. So you will experience inconsistent behavior by your current method when fps fluctuates.
Solution
All you need is to reduce your number of state variables to only two i.e. don't store current velocity. It is causing the errors in final position.
In stead use parametric form of the trajectory.
v = u + at
and
s = ut + ½at²
Implementation
Suppose you want to go from (sourceX, sourceY) to (targetX, targetY) in time 'totalTime'.
Calculate initial velocity.
Vector2 initialVelocity = new Vector2((targetX - sourceX) / totalTime,
(targetY - sourceY) / totalTime - gravity * totalTime / 2);
float currentTime = 0;
In each iteration, calculate position directly and keep track of currentTime.
public void act(float delta){
if (currentTime < totalTime) {
currentTime += delta;
setX((initialVelocity.x + gravity.x * currentTime / 2) * currentTime);
setY((initialVelocity.y + gravity.y * currentTime / 2) * currentTime);
} else {
setX(targetX);
setY(targetY);
}
}

Drawing an arrow at the end point of the line using line slope

I am developing a white board application which allows the user to draw line with arrow head (some like Microsoft Word line with arrow feature). I am using graphics property along with lineTo() method to draw a line. Now i have to draw a angular arrow on the last point of line. I am drawing the arrow by connecting the points around last points. As 360 line can pass through this point and each line can have a different angle of arrow. Please suggest me the way to calculating these point around the last point.
I've been doing something myself, and I needed it to look a bit nicer than just a triangle, and use relatively inexpensive calculations (as few calls to other functions as possible, like Math trigonometry). Here it is:
public static function DrawArrow(ax:int, ay:int, bx:int, by:int):void
{
// a is beginning, b is the arrow tip.
var abx:int, aby:int, ab:int, cx:Number, cy:Number, dx:Number, dy:Number, ex:Number, ey:Number, fx:Number, fy:Number;
var size:Number = 8, ratio:Number = 2, fullness1:Number = 2, fullness2:Number = 3; // these can be adjusted as needed
abx = bx - ax;
aby = by - ay;
ab = Math.sqrt(abx * abx + aby * aby);
cx = bx - size * abx / ab;
cy = by - size * aby / ab;
dx = cx + (by - cy) / ratio;
dy = cy + (cx - bx) / ratio;
ex = cx - (by - cy) / ratio;
ey = cy - (cx - bx) / ratio;
fx = (fullness1 * cx + bx) / fullness2;
fy = (fullness1 * cy + by) / fullness2;
// draw lines and apply fill: a -> b -> d -> f -> e -> b
// replace "sprite" with the name of your sprite
sprite.graphics.clear();
sprite.graphics.beginFill(0xffffff);
sprite.graphics.lineStyle(1, 0xffffff);
sprite.graphics.moveTo(ax, ay);
sprite.graphics.lineTo(bx, by);
sprite.graphics.lineTo(dx, dy);
sprite.graphics.lineTo(fx, fy);
sprite.graphics.lineTo(ex, ey);
sprite.graphics.lineTo(bx, by);
sprite.graphics.endFill();
}
You can also add the line color and thickness to the argument list, and maybe make it a member function of an extended Sprite, and you have a pretty nice, versatile function :) You can also play a bit with the numbers to get different shapes and sizes (small changes of fullness cause crazy changes in look, so careful :)). Just be careful not to set ratio or fullness2 to zero!
If you store the start and end point of the line, adding the arrow head should be relatively simple. If you subtract the end point coordinates from the start point coordinates, you will get the arrow direction vector (let's call it D). With this vector, you can determine any point on the line between the two points.
So, to draw the arrow head, you would need to determine a point (P1) on the segment that has a specific distance (d1) from the end point, determine a line that passes through it, and is perpendicular to D. And finally get a point (P2) that has a distance (d2) from the previously determined point. You can then determine the point that is symmetrical to P2, relative to D.
You will thus have an arrow head the length of d1 and a base with of 2 * d2.
Some additional information and a few code examples here: http://forums.devx.com/archive/index.php/t-74981.html

How to draw paths specified in terms of straight and curved motion

I have information on paths I would like to draw. The information consists of a sequence of straight sections and curves. For straight sections, I have only the length. For curves, I have the radius, direction and angle. Basically, I have a turtle that can move straight or move in a circular arc from the current position (after which moving straight will be in a different direction).
I would like some way to draw these paths with the following conditions:
Minimal (preferably no) trigonometry.
Ability to center on a canvas and scale to fit any arbitrary size.
From what I can tell, GDI+ gives me number 2, Cairo gives me number 1, but neither one makes it particularly easy to get both. I'm open to suggestions of how to make GDI+ or Cairo (preferably pycairo) work, and I'm also open to any other library (preferably C# or Python).
I'm even open to abstract mathematical explanations of how this would be done that I can convert into code.
For 2D motion, the state is [x, y, a]. Where the angle a is relative to the positive x-axis. Assuming initial state of [0, 0, 0]. 2 routines are needed to update the state according to each type of motion. Each path yields a new state, so the coordinates can be used to configure the canvas accordingly. The routines should be something like:
//by the definition of the state
State followLine(State s, double d) {
State s = new State();
s.x = s0.x + d * cos(s0.a);
s.y = s0.y + d * sin(s0.a);
s.a = s0.a;
return s;
}
State followCircle(State s0, double radius, double arcAngle, boolean clockwise) {
State s1 = new State(s0);
//look at the end point on the arc
if(clockwise) {
s1.a = s0.a - arcAngle / 2;
} else {
s1.a = s0.a + arcAngle / 2;
}
//move to the end point of the arc
State s = followLine(s1, 2 * radius * sin(arcAngle/ 2));
//fix new angle
if(clockwise) {
s.a = s0.a - arcAngle;
} else {
s.a = s0.a + arcAngle;
}
return s;
}