I'm using the ARToolkit for android and try to write a text over the detected marker. I want to do this using a simple TextView. So I'm only using ARToolkit to find the marker.
But how can I find out where in my camera-preview the marker is right no (I need the coordinates), so I can but the TextView over the marker?
Thanks in advance !
Both comments are correct, ARToolkit returns both a Projection Matrix and a Transformation Matrix. Both are designed to be used with OpenGL, not with a standard Android view. The projection matrix is to be applied to the camera and the transformation one is to be applied to the object (pose matrix)
If you only want to display text, I recommend you to use the Unity plugin and then use the Unity UI components to add a canvas and a text attached to the marker. Those components are already designed to be 3D objects (if you go that way, remember to set the canvas to "World Space".
The other options you have are:
a) Render the text into a texture and draw it on a Quad, you can do that based on the example that has a cube.
b) Do some matrix calculations using both matrix and the apply transformations to the TextView on position and rotation using a transformation Matrix (the Android class). Although is possible, the math involved is rather complex. If you want it to just float looking at the camera, setTranslationX, Y and Z should be enough.
c) Link a 3D engine with text rendering capability to ARToolkit. I've done that with jPCT-AE. While this works, it takes quite a lot of work. I plan to write about it soon.
There is another option to detect the markers corner points.
It will require some changes to the wrapper code and recompiling the Android binaries.
Fork or clone the artoolkit5 github repository and make the following changes:
Add an entry to ARMarker.h
float cornerPoints[8];
In ARMarkerSquare.cpp make a change in the updateWithDetectedMarkers method just after the code where a marker has been determined visible, update the cornerPoints:
// Consider marker visible if a match was found.
if (k != -1) {
visible = true;
m_cf = markerInfo[k].cf;
for (int c = 0; c < 4; c++) {
cornerPoints[c*2] = markerInfo[k].vertex[c][0];
cornerPoints[c*2 + 1] = markerInfo[k].vertex[c][1];
}
Add a new method ARToolKitWrapperExportedAPI.cpp to retrieve the corner points:
EXPORT_API bool arwQueryMarkerCornerPoints(int markerUID, float points[8])
{
ARMarker *marker;
if (!gARTK) return false;
if (!(marker = gARTK->findMarker(markerUID))) {
gARTK->logv(AR_LOG_LEVEL_ERROR, "arwQueryMarkerCornerPoints(): Couldn't locate marker with UID %d.", markerUID);
return false;
}
for (int i = 0; i < 8; i++) points[i] = (float)marker->cornerPoints[i];
return marker->visible;
}
And add the JNI definition for that:
JNIEXPORT jfloatArray JNICALL JNIFUNCTION(arwQueryMarkerCornerPoints(JNIEnv *env, jobject obj, jint markerUID))
{
float trans[8];
if (arwQueryMarkerCornerPoints(markerUID, trans)) return glArrayToJava(env, trans, 8);
return NULL;
}
After all that I recompile the ARWrapper shared objects in the android directory with the build.sh script and used these new shared objects.
In the he NativeInterface.java add the following method:
/**
* Retrieves the corner points for the specified marker
*
* #param markerUID The unique identifier (UID) of the marker to check
* #return A float array of size 8 containing the corner points starting at top left (x,y) top right, bottom right, bottom left.
* So
*/
public static native float[] arwQueryMarkerCornerPoints(int markerUID);
And finally add the method to ARToolKit.java as well:
/**
* Retrieves the corner points for the specified marker
*
* #param markerUID The unique identifier (UID) of the marker to check
* #return A float array of size 8 containing the corner points starting at top left (x,y) top right, bottom right, bottom left.
*
*/
public float[] arwQueryMarkerCornerPoints(int markerUID) {
if (!initedNative) return null;
return NativeInterface.arwQueryMarkerCornerPoints(markerUID);
}
See also:
https://archive.artoolkit.org/community/forums/viewtopic.php?f=26&t=16099
The changes can be seen seen in this fork as well: https://github.com/ekkelenkamp/artoolkit5/tree/marker_corner_points
Related
For an assignment I am making a Boardgame. (In java) This Boardgame has a map, with multiple fields/lands that have to be used. Units can be placed on them, they can move. Other things are also placed on them.
For the map I have one image I use. I looked online for solutions, but the only ones I found where for a grid game (such as chess or checkers) and the map of this game can not be divided in just squares. I tried this, but the field shapes are to different to make that work.
I had a few faint ideas as to how to work this out, but I can't quite put them into code examples and have no clue if they would work, or how.
The ideas I had:
Make some invisible buttons and bind them to specific coordinates in the picture. The problem I had with this solution was that it also had to be able to display things placed on it. It would also be very inconvenient if not all of the field was clickable.
I have a 'overlay' image with the outlines of all the fields and the 'insides' removed. I made this overlay so I could add a faint color overlay over the board. Would it be possible to use this in any kind of way?
First I though of cutting out all the loose fields and putting them together to form the one image. Only, I don't know how I would do this. Not just where to place it, but also, how can I make sure that the elements are Always in the same place compared to eachother, and my board doesn't mess up when changing screen/resolution size?
I am using javafx for the graphical elements in my game.
If there are any suggestions of something I haven't thought of myself, those are also very welcome.
If it's sufficient to retrieve the color of the pixel where the mouse was clicked, then you can do that fairly easily. If you know the image is displayed in the image view unscaled and uncropped, then all you need is:
imageView.setOnMouseClicked(e -> {
Color color = imageView.getImage().getPixelReader().getColor((int)e.getX(), (int)e.getY());
// ...
});
More generally, you may need to map the image view coordinates to the image coordinates:
imageView.setOnMouseClicked(e -> {
double viewX = e.getX();
double viewY = e.getY();
double viewW = imageView.getBoundsInLocal().getWidth();
double viewH = imageView.getBoundsInLocal().getHeight();
Rectangle2D viewport = imageView.getViewport();
double imgX = viewport.getMinX() + e.getX() * viewport.getWidth() / viewW;
double imgY = viewport.getMinY() + e.getY() * viewport.getHeight() / viewH ;
Color color = imageView.getImage().getPixelReader().getColor((int)imgX, (int)imgY);
// ...
});
Once you have the color you can do some simple analysis to see if it approximately matches the color of various items in your image, e.g. check the hue component, or check if the "distance" from a fixed color is suitably small.
A typical implementation of that might look like:
// choose a color based on what is in your image:
private final Color FIELD_GREEN = Color.rgb(10, 10, 200);
private double distance(Color c1, Color c2) {
double deltaR = c1.getRed() - c2.getRed();
double deltaG = c1.getGreen() - c2.getGreen();
double deltaB = c1.getBlue() - c2.getBlue();
return Math.sqrt(deltaR * deltaR + deltaG * deltaG + deltaB * deltaB);
}
private boolean colorsApproximatelyEqual(Color c1, Color c2, double tolerance) {
return distance(c1, c2) < tolerance ;
}
And the back in the handler you can do
if (colorsApproximatelyEqual(color, FIELD_GREEN, 0.1)) {
// process click on field...
}
Whether or not this is a viable approach depends on the nature of the image map. If the coloring in the map is too complex (or objects are not easily distinguishable by color), then you will likely need to place other elements in the scene graph and register handlers on each of them, as you describe in the question.
In NASA WorldWind, one can assign a "direction of travel" speed leader to the Milstd-2525 symbols. However, this speed leader is black, making it very difficult to see against the dark blue ocean background. I have tried changing the internal color material in the TacticalSymbolAttributes, but this doesn't seem to have an effect (on anything). The documentation unfortunately doesn't provide any clues on how to change the line's color.
Is it possible to change the color of the Milstd-2525 Tactical Symbol's speed leader line in Worldwind, and if so, how?
Base of source codes of WorldWindJava on github, class MilStd2525TacticalSymbol overrides method named layoutDynamicModifiers. In this method you can see that for DIRECTION_OF_MOVEMENT only eventually addLine(...) is called (This method is implemented in the superclass AbstractTacticalSymbol which only adds a line to a list named currentLines) and only SPEED_LEADER_SCALE could be set and other properties for the direction of movement could not be changed externally.
#Override
protected void layoutDynamicModifiers(DrawContext dc, AVList modifiers, OrderedSymbol osym)
{
this.currentLines.clear();
if (!this.isShowGraphicModifiers())
return;
// Direction of Movement indicator. Placed either at the center of the icon or at the bottom of the symbol
// layout.
Object o = this.getModifier(SymbologyConstants.DIRECTION_OF_MOVEMENT);
if (o != null && o instanceof Angle)
{
// The length of the direction of movement line is equal to the height of the symbol frame. See
// MIL-STD-2525C section 5.3.4.1.c, page 33.
double length = this.iconRect.getHeight();
Object d = this.getModifier(SymbologyConstants.SPEED_LEADER_SCALE);
if (d != null && d instanceof Number)
length *= ((Number) d).doubleValue();
if (this.useGroundHeadingIndicator)
{
List<? extends Point2D> points = MilStd2525Util.computeGroundHeadingIndicatorPoints(dc, osym.placePoint,
(Angle) o, length, this.iconRect.getHeight());
this.addLine(dc, Offset.BOTTOM_CENTER, points, LAYOUT_RELATIVE, points.size() - 1, osym);
}
else
{
List<? extends Point2D> points = MilStd2525Util.computeCenterHeadingIndicatorPoints(dc,
osym.placePoint, (Angle) o, length);
this.addLine(dc, Offset.CENTER, points, null, 0, osym);
}
}
}
In the superclass AbstractTacticalSymbol, field currentLines (which contains the line for the direction of movement) is used in a method named drawLines(...) which draws added lines to the mentioned list (line 2366 of class). In line 2364 you can see that color is set to black.
gl.glColor4f(0f, 0f, 0f, opacity.floatValue());
Now I suggest you extend MilStd2525TacticalSymbol and do following:
extend class AbstractTacticalSymbol.Line and define some fields to store color.
override method layoutDynamicModifiers and get your own key (for example DIRECTION_OF_MOVEMENT_COLOR) to get color from modifiers and use this given color to create your own line and add this to currentLines list (you can override method addLine for this purpose).
finally override drawLines to use store color in your own Line class and change the color of gl before draw line (you can change back color to black after the direction of movement is drawn).
I'm running off an earlier Worldwind but try Taking a look at AbstractTacticalSymbol.java -> drawLines() method.
It's defaulting the glColor to black before drawing the lines.
I'm working on a project with Processing that requires the ability to determine whether or not the mouse is inside of a circle. Therefore, I need to obtain the position of the circle and the position of the mouse. However, the position of the circle has been modified using matrix functions such as translate and scale. For example:
float circle_x;
float circle_y;
float circle_radius;
void setup() {
circle_x = 10.0;
circle_y = 17.0;
circle_radius = 15.0;
}
void draw() {
pushMatrix();
/* ... arbitrary number of calls to modify the matrix ... */
translate(THING, THING);
scale(THING);
translate(THING);
/* ... */
/* draw the circle */
ellipse(circle_x, circle_y, circle_radius, circle_radius);
/* now I want to detect whether or not my mouse is inside of the
circle. In order to do that, I need to modify the coordinates
of the mouse in the same fashion as circle_x and circle_y. I'm
hoping to do something like this: */
float world_x = screenToWorld_X(mouseX);
float world_y = screenToWorld_Y(mouseY);
/* ... check if [world_x, world_y] is inside the circle ... */
popMatrix();
}
Is there any way to do this in Processing? I was looking at the documentation but I couldn't seem to find any functions. If not, how can I achieve my goal?
Thanks.
Check out the coordinates section of the reference.
Specifically, you're looking for the modelX() and modelY() functions. Or you could use the screenX() and screenY() functions to go the other way and convert your world coordinates into screen coordinates.
I am using libgdx for easy 3D game, I need check model is clicked.
It is my code:
public int getObject (int screenX, int screenY) {
Ray ray = cam.getPickRay(screenX, screenY);
int result = -1;
float distance = -1;
for (int i = 0; i < rooms.size; ++i) {
final GameObject instance = rooms.get(i);
instance.transform.getTranslation(position);
position.add(instance.center);
final float len = ray.direction.dot(position.x-ray.origin.x, position.y-ray.origin.y, position.z-ray.origin.z);
if (len < 0f)
continue;
float dist2 = position.dst2(ray.origin.x+ray.direction.x*len, ray.origin.y+ray.direction.y*len, ray.origin.z+ray.direction.z*len);
if (distance >= 0f && dist2 > distance)
continue;
if (dist2 <= instance.radius * instance.radius ) {
result = i;
distance = dist2;
}
}
return result;
}
It it sometimes work.
Is is my model:
http://www6.zippyshare.com/v/97501566/file.html
What do I wrong?
Any help for me?
I am new with libgdx.
When was I press 1 it lights, but when I waas press 2, 1 lights too (instead 2)...
I didn't fully analyze your code nor do I know what It it sometimes work. actually means (e.g. in which circumstances doesn't it work?) but you're using a bounding sphere for detecting whether the object has been clicked or not.
Assuming your calculations are correct (as I said, I didn't check them in depth) you still can have false positives or negatives since the only shape which is perfectly represented by a bounding sphere is ... well... a sphere.
That might be the source for click detection to work "sometimes".
If that is the case and you want more accurate detection you should either use different bound volumes, bounding volumne hierarchies or a rendering based approach (i.e. render the object id into some buffer, which would allow for pixel perfect selection).
UPDATE:
From your post update it seems that bounding spheres are not the problem here, since they should not overlap, unless your data is wrong - which you should check/debug.
So the problem might actually lie in your calculations. From the documentation it looks like the ray you get is projected into the scene (i.e. into world space) so you'd need to transform your objects' center into worldspace as well.
You're currently only applying the position but ignore rotation and scale thus the resulting position might be wrong. I'm sure there's some built-in transform code, so instead of transforming manually you should use that. Please check the docs on how to do that.
I have a line segment that represents a direction and magnitude (length), when i draw the segment it works as it should. the value getAimArmsRotation is being pulled from another class that contains a touchpad value.
if (player.getFacingRight()) {
lOriginX = (player.getPosition().x + Player.SIZEw/2);
lOriginY = (player.getPosition().y + Player.SIZEh/1.5f);
//lEndX = lOriginX + (float)Math.cos((player.getAimArmsRotation())/57) * 15f;
//lEndY = lOriginY + (float)Math.sin((player.getAimArmsRotation())/57) * 15f;
laserO = new Vector2(lOriginX, lOriginY);
laserE = new Vector2(lEndX, lEndY);
However if I use the Vectors or floats from this calculation and apply them to a model's velocity vector it does not move the model along the line segment as I would think it should.
EDIT: Sorry meant to attach this picture when I created the question. Fig 1 is how my line segment looks, when I set the velocity values that make up the line segment to my object it moves in the direction that fig 2 shows.
getAimArmsRotation() is just a method that sets a sprite's rotation with a value from the touchpad in another class. I don't think that the values should matter since these floats are what i've used in order to give the line segment it's length and direction, I would think that giving an object a velocity of the x and y floats would give it the same direction as the line?
Thanks for the DV, jerks.
I wasn't taking into account the origin position of the object when trying to send it along the desired path. I was only using the LineEnd values, I needed to give the object it's origin point to correctly calculate the trajectory or path.
for (GameObject go: gObjects) {
if (go.getType() == PROJECTILE_ID) {
go.getVelocity().x = player.getLineEndX() - player.getLineOrgX();
go.getVelocity().y = player.getLineEndY() - player.getLineOrgY();
System.out.println(go.getVelocity().x);
System.out.println(go.getVelocity().y);
}
}