I have met some problem for integration the JPCT-AE with ARNative of ARToolkit's Project.
Purpose:
using jpct-ae to rendering model basic on ARToolkit;
Status :
i can render a model on the screen behind the preview data;
however, the model could no shown in correct position;
i do not know how the using the ProjectionMatrix from ARToolkit for JPCT-AE.
My code was shown belown:
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
ARNativeActivity.nativeSurfaceCreated();
}
public void onSurfaceChanged(GL10 unused, int width, int height) {
ARNativeActivity.nativeSurfaceChanged(width, height);
glViewport(0, 0, width, height);
fb = new FrameBuffer( width, height); // OpenGL ES 1.x constructor
world = new World();
world.setAmbientLight(20, 20, 20);
sun = new Light(world);
sun.setIntensity(250, 250, 250);
loadOBJ("cube.obj" , "cube.mtl" , "cube");
world.addObject(cubeColor);
cam = world.getCamera();
cam.moveCamera(Camera.CAMERA_MOVEOUT, 50);
cam.lookAt(cubeColor.getTransformedCenter());
SimpleVector sv = new SimpleVector();
sv.set(cubeColor.getTransformedCenter());
sv.y -= 100;
sv.z -= 100;
sun.setPosition(sv);
MemoryHelper.compact();
}
public void onDrawFrame(GL10 unused) {
glClear(GL_COLOR_BUFFER_BIT);
ARNativeActivity.nativeDrawFrame();
float[] projection = ARNativeActivity.getProjectMatrix();
Matrix projMatrix = new Matrix();
projMatrix.setDump(projection);
projMatrix.transformToGL();
SimpleVector translation = projMatrix.getTranslation();
SimpleVector dir = projMatrix.getZAxis();
SimpleVector up = projMatrix.getYAxis();
cam.setPosition(translation);
cam.setOrientation(dir, up);
world.renderScene(fb);
world.draw(fb);
fb.display();
}
I think this question is pretty similar to a newer one you made: Rendering a model basic on JPCT-AE with ARToolkit in Android. It will most likely be duplicated. Anyway, I have still not enough privileges to mark it as duplicated, so I reference to the other and try to answer the slight differences. The only difference I can see is that here you still are not using the transformation matrix given by the artoolkit. You must get it by calling
ARNativeActivity.getTransformationM()
and put it in a JPCT matrix:
transformM.setIdentity();
transformM .setDump(ARNativeActivity.getTransformationM());
transformM .transformToGL();
As told, is already on the other question, so I suggest all users going there for a more complete answer and external references.
Related
I have been working on this for 2 days and still cant figure out what is going on. I am working on a Game Framework and i have migrated from Slick2D to LibGDX and would like to render once to a texture as to save CPU/GPU cycles and improve performance. I have created a class called DrawSurface and its main goal is to allow me to draw to a offscreen texture and then just draw that using LibGDXs Built in Image class.
public final class DrawSurface {
public static interface DrawCall{
void draw(SpriteBatch b, int width, int height);
}
public static Texture offscreenDraw(DrawCall c, int canvasWidth, int canvasHeight){
FrameBuffer fbo = new FrameBuffer(Pixmap.Format.RGBA8888,(canvasWidth),(canvasHeight),true);
SpriteBatch batch = new SpriteBatch();
batch.setProjectionMatrix(new Matrix4().setToOrtho2D(0,0,fbo.getWidth(),fbo.getHeight()));
fbo.begin();
batch.begin();
c.draw(batch,fbo.getWidth(),fbo.getHeight());
batch.end();
Pixmap map = ScreenUtils.getFrameBufferPixmap(0,0,fbo.getWidth(),fbo.getHeight());
fbo.end();
Texture t = new Texture(map);
map.dispose();
return t;
}
}
Which Gives me This Result When Drawing Images:
The "DrawCall" that is used to get this image is:
Texture t = DrawSurface.offscreenDraw(new DrawSurface.DrawCall() {
#Override
public void draw(SpriteBatch b, int w, int h) {
Image img = new Image(0x0000FF,w,h);
img.setLocation(0,0);
img.draw(b);
for(int i = 0; i < w; i += 64){
for(int j = 0; j < h; j += 64){
Blocks.GRASS_BLOCK.setLocation(i,j);
Blocks.GRASS_BLOCK.draw(b);
}
}
}
},512,512);
The Image should Render as a blue Square 512x512 pixels in size, with small "Grass" block images that should also be square. Sized 16x16. Unfortunately i get a warped result, and i do not understand why. As the Large White thing (a software JoyStick i created) is not stretched while the "DrawsSurface" is. If you would like a look at my camera code:
// Constructor Above.
this.gameWidth = gameWidth;
this.gameHeight = gameHeight;
this.camera = new OrthographicCamera();
FlatPixelGame.gameCamera = this.camera;
this.viewport = new StretchViewport(gameWidth,gameHeight,camera);
this.viewport.apply();
LogBot.log("Game Instance Created Size [%s,%s]",gameWidth,gameHeight);
InputManager.getInstance().addListener(this);
this.camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
Any Help Would Be Appreciated, i have scoured Forums, StackOverflow and LibGDX Documentation and still cannot seem to fix this issue.
Again, Thank you in Advance :)
After a little work under the hood with LibGDX source code from BadLogic, as well as reading bug threads it seems there is an issue when converting a PixMap to a texture. Rendering a image derived from a file works fine, but generated images that come from a Pixmap can show warping due to the off-screen view-port not being the same as the current rendering view-port.
A quick way around this is using TextureRegions and Sprites.
public static Image offscreenDraw(DrawCall c, int canvasWidth, int canvasHeight){
FrameBuffer fbo = new FrameBuffer(Pixmap.Format.RGBA8888,canvasWidth,canvasHeight,true);
SpriteBatch batch = new SpriteBatch();
Matrix4 matrix = new Matrix4();
matrix.setToOrtho2D(0, 0, canvasWidth,canvasHeight);
batch.setProjectionMatrix(matrix);
fbo.begin();
batch.begin();
c.draw(batch,canvasWidth,canvasHeight);
batch.end();
Texture t = fbo.getColorBufferTexture();
t.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest);
if(!t.getTextureData().isPrepared()){
t.getTextureData().prepare();
}
fbo.end();
TextureRegion r = new TextureRegion(t,0,0,canvasWidth,canvasHeight);
return new Image(new com.badlogic.gdx.scenes.scene2d.ui.Image(new Sprite(r)));
}
I am attempting to create a day/night cycle in a simple RPG-style game with Java. I have reached a point where I have included a low-alpha color overlay will change hue over time to simulate this:
// Render the overlay rectangle.
public void render(Graphics2D g) {
// Set the color to yellow with ~50% opacity.
g.setColor(new Color(255, 255, 0, 125));
// Draw the rectangle.
g.fillRect(0, 0, handler.getWidth(), handler.getHeight());
g.dispose();
}
While this works, I would like to introduce blending modes (i.e. add, subtract, screen, soft light) into my code to increase the day/night cycle's realism.
Here's what I have tried, but to no avail:
Researching JavaFX's blending mode options. I don't want to switch to JavaFX.
Creating an all-white image that overlays the screen and uses setComposite() and setXORMode() from a different StackOverflow answer.
Using an image with a BlendingMode and setComposite() from the package org.jdesktop.swingx.graphics.BlendComposite.
My desired code is something similar to what follows, but I will take what I can get.
public void render(Graphics2D g) {
g.setColor(new Color(255, 255, 0, 125));
g.setBlendMode(ADD);
g.fillRect(0, 0, handler.getWidth(), handler.getHeight());
g.dispose();
}
One possibility to solve this would be to buffer your screen in a BufferedImage and then implement your own drawing methods(This definitely isn't a fast way to do this as it throws away all hardware-acceleration. If you need to render a big screen this can be laggy depending on your system and your implementation.):
class MyGraphics {
public enum BlendingMode {
NORMAL, ADD, …
}
public BufferedImage buffer;
private BlendingMode bm = BlendingMode.NORMAL;
private int color = 0;
public MyGraphics(BufferedImage buf) {
buffer = buf; // Initialize it with a bufferedImage of your panel size.
}
public void setBlendMode(BlendingMode b) {
bm = b;
}
private int applyBlendingMode(int imgColor1, int newColor) {
int rImg, rNew, gImg, gNew, bImg, bNew, alphaImg, alphaNew; // You can intialize those using bitshifts from the color integers.
switch(bm) {
// Implement all your blending modes here.
}
// And don't forget to return the result!
}
public void setColor(int c) {
color = c;
}
public void fillRect(int x0, int y0, int width, int height) {
for(int x = x0; x < x0+width; x++) {
for(int y = y0; y < y0+height; y++) {
buffer.setRGB(x, y, applyBlendingMode(buffer.getRGB(x, y), color));
}
}
}
}
If the setRGB and getRGB are working to slow for you, you might speed it up by working directly on the BufferedImage's data array(see here for further info).
Also keep in mind, that if you want to use normal blending mode, you can still do it the normal way using buffer.getGraphics() to get your Graphics object. This should be faster in most cases.
After you are done with implementing your blending-modes and maybe some further functionality to draw more then a rectangle you can just simply draw the underlying BufferedImage on your screen using Graphics.drawImage(buffer, 0, 0);
I am drawing a radial gradient circle on an image like this
I have java code for this
private void drawRadialGradientCircleJava(String imagePath, double posX, double posY, float radius, String outputPath) throws IOException{
BufferedImage city = ImageIO.read(new File(imagePath));
BufferedImage mask = new BufferedImage(city.getWidth(), city.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = mask.createGraphics();
Color transparent = new Color(255, 0, 0, 0);
Color fill = Color.RED;
RadialGradientPaint rgp = new RadialGradientPaint(
new Point2D.Double(posX, posY),
radius,
new float[]{0f, 0.75f, 1f},
new Color[]{transparent, transparent, fill});
g2d.setPaint(rgp);
g2d.fill(new Rectangle(0, 0, mask.getWidth(), mask.getHeight()));
g2d.dispose();
BufferedImage masked = new BufferedImage(city.getWidth(), city.getHeight(), BufferedImage.TYPE_INT_ARGB);
g2d = masked.createGraphics();
g2d.setColor(Color.RED);
g2d.fillRect(0, 0, masked.getWidth(), masked.getHeight());
g2d.drawImage(city, 0, 0, null);
g2d.setComposite(AlphaComposite.DstAtop);
g2d.drawImage(mask, 0, 0, null);
g2d.dispose();
ImageIO.write(masked,"png", new File(outputPath));
}
I want to do same thing in Android, I have an image view in which I have an image, now I want to touch a point in image and draw this transparent circle around that point
I have following Android code as well but id doesn't draw anything on the image
private void drawRadialGradientCircleAndroid(ImageView imageView, float posX,
float posY, float radius) throws IOException {
RadialGradient gradient = new RadialGradient(posX, posY, radius, Color.TRANSPARENT,
Color.TRANSPARENT, android.graphics.Shader.TileMode.CLAMP);
Paint p = new Paint();
p.setDither(true);
p.setShader(gradient);
Bitmap bm = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
Bitmap bmOverlay = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), bm.getConfig());
Canvas canvas = new Canvas(bmOverlay);
canvas.drawBitmap(bm, new Matrix(), null);
canvas.drawCircle(posY, posX, radius, p);
imageView.setImageBitmap(bmOverlay);
}
Please help how can I achieve this in Android.
We should migrate this to the answer boxes.
OP has basically got it here- and in fact the OP's revised gist is brilliant.
Some general tips regarding the first attempt in the question:
1) In protected void onSizeChanged(int w, int h, int oldw, int oldh):
width = w; there is no reason why you can't call getWidth() when you require this. The reason it's advisable is because the View's internal width is set quite late after onMeasure. Consequently, onDraw may be the next time you want a most up to date version, so use the getter there.
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);. Creating a bitmap is an expensive and memory intensive operation. Unless you want to write a bitmap to a file, or send it to a BitmapDrawable for an ImageView or something, you don't need to do this. Especially with effects drawn onto the UI with android's graphics library.
mCanvas = new Canvas(mBitmap); followed by a draw operation onto the new canvas. This is never needed. And yet I've seen it (not work) in many code bases and attempts. I think it's the fault of an old stack overflow post that got people doing this so that they could transform a canvas on a custom view without effecting the drawing onto the rest of the canvas. Incidentally, if you need this, use .restore() and .save() instead. If you see new Canvas, be suspicious.
2) onDraw(...):
Yes, you need to avoid doing things in onDraw, like, creating objects, or any heavy processing. But you still need to do the things in onDraw you need to do in onDraw!
So here you simply need to call : canvas.drawCircle(float cx, float cy, float radius, Paint paint) with arguments as per the docs.
This really isn't that sinful for onDraw. If you're worried about calling this too much, as might be the case if your entire button is animating across the screen, you need to use hardware acceleration available in later API versions, as will be detailed in an article called Optimizing the View; very helpful reading if you're using lots of custom drawn views.
3) That pesky radial gradient. The next issue you had is that you quite rightly created your paint in an initmethod so that the object creation was off the draw. But then quite rightly it will have IllegalArgumentExceptioned (I think) on you because at that stage the getHeight() of the view was 0. You tried passing in small pixel values- that won't work unless you know some magic about screen sizes.
This isn't your issue as much as the annoying view cycle at the heart of Android's design patterns. The fix though is easy enough: simply use a later part of the view's drawing process after the onMeasure call to set the paint filter.
But there are some issues with getting this right, namely that sometimes, annoyingly, onDraw gets called before the point at which you'd expect it. The result would be your paint is null and you wouldn't get the desired behavior.
I have found a more robust solution is simply to do a cheeky and naughty little null check in the onDraw and then once only construct the paint object there. It's not strictly speaking optimal, but given the complex way in which the Paint objects hook up with Android's graphics native layer better than trying to straddle the paint configuration and construction in many frequently called places. And it makes for darn clearer code.
This would look like (amending your gist):
#Override
protected void onDraw(final Canvas canvas) {
super.onDraw(canvas);
if (mPaint == null) {
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(1);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setShader(new RadialGradient(getWidth() / 2, getHeight() / 2,
getHeight() / 3, Color.TRANSPARENT, Color.BLACK, TileMode.MIRROR));
}
width = getWidth();
height = getHeight();
canvas.drawCircle(width / 2, height / 2, height / 3, mPaint);
}
So note a few changes- I think from your description you want the two colours swapped round in the arguments, also don't forget to center the center of your gradient in your view: width/2 and height/2 arguments.
Best of luck!
I have trouble with my app. On iPhone (tested on 5c, 5s, 6) i have two black stripes on both sides (on android all looks well).
How i can dispose of them?
This is my code for drawing
#Override
public void create () {
mWidth = Gdx.graphics.getWidth();
mHeight = Gdx.graphics.getHeight();
mScale = Math.max(mWidth, mHeight) / 20f;
backgroundTexture = new Texture(Gdx.files.internal("backBlue.png"));
ShaderProgram.pedantic = false;
backgroundShader = new ShaderProgram(VERT, FRAG);
if (!backgroundShader.isCompiled()) {
System.err.println(backgroundShader.getLog());
System.exit(0);
}
if (backgroundShader.getLog().length()!=0)
System.out.println(backgroundShader.getLog());
backgroundBatch = new SpriteBatch(5, backgroundShader);
}
#Override
public void render () {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
backgroundBatch.begin();
backgroundBatch.draw(backgroundTexture, 0, 0, mWidth, mHeight);
backgroundBatch.end();
...
}
#Override
public void resize (int width, int height) {
mWidth = width;
mHeight = height;
mScale = Math.max(width, height) / 20f;
backgroundShader.begin();
backgroundShader.setUniformf("resolution", width, height);
backgroundShader.end();
}
This is probably happening because the viewport you are using, which is usually set in the constructor or the create method.
What is a viewport?
Basically, a viewport is an object that is created to define the policy of how the game will be drawn on different screens. E.g., say your camera is set to be 480 x 800 (pixels). What happens if your game is running on a screen that has a different ratio, for instance, the iPhone 5 that has a screen of 1,136 × 640 pixels? Should the game be stretched? Should the image be cropped? Or should libgdx add black bars on either side to fit the camera size you are using? This decision is made by the viewport your camera is using.
This is it in a nutshell. It is highly recommended to read more on this on the wiki.
Additionally, a good tutorial on this subject can be found here.
Hey all I'm trying to implement 3D picking into my program, and it works perfectly if I don't move from the origin. It is perfectly accurate. But if I move the model matrix away from the origin (the viewmatrix eye is still at 0,0,0) the picking vectors are still drawn from the original location. It should still be drawing from the view matrix eye (0,0,0) but it isn't. Here's some of my code to see if you can find out why..
Vector3d near = unProject(x, y, 0, mMVPMatrix, this.width, this.height);
Vector3d far = unProject(x, y, 1, mMVPMatrix, this.width, this.height);
Vector3d pickingRay = far.subtract(near);
//pickingRay.z *= -1;
Vector3d normal = new Vector3d(0,0,1);
if (normal.dot(pickingRay) != 0 && pickingRay.z < 0)
{
float t = (-5f-normal.dot(mCamera.eye))/(normal.dot(pickingRay));
pickingRay = mCamera.eye.add(pickingRay.scale(t));
addObject(pickingRay.x, pickingRay.y, pickingRay.z+.5f, Shape.BOX);
//a line for the picking vector for debugging
PrimProperties a = new PrimProperties(); //new prim properties for size and center
Prim result = null;
result = new Line(a, mCamera.eye, far);//new line object for seeing look at vector
result.createVertices();
objects.add(result);
}
public static Vector3d unProject(
float winx, float winy, float winz,
float[] resultantMatrix,
float width, float height)
{
winy = height-winy;
float[] m = new float[16],
in = new float[4],
out = new float[4];
Matrix.invertM(m, 0, resultantMatrix, 0);
in[0] = (winx / width) * 2 - 1;
in[1] = (winy / height) * 2 - 1;
in[2] = 2 * winz - 1;
in[3] = 1;
Matrix.multiplyMV(out, 0, m, 0, in, 0);
if (out[3]==0)
return null;
out[3] = 1/out[3];
return new Vector3d(out[0] * out[3], out[1] * out[3], out[2] * out[3]);
}
Matrix.translateM(mModelMatrix, 0, this.diffX, this.diffY, 0); //i use this to move the model matrix based on pinch zooming stuff.
Any help would be greatly appreciated! Thanks.
I wonder which algorithm you have implemented. Is it a ray casting approach to the problem?
I didn't focus much on the code itself but this looks a way too simple implementation to be a fully operational ray casting solution.
In my humble experience, i would like to suggest you, depending on the complexity of your final project (which I don't know), to adopt a color picking solution.
This solution is usually the most flexible and the easiest to be implemented.
It consist in the rendering of the objects in your scene with unique flat colors (usually you disable lighting as well in your shaders) to a backbuffer...a texture, then you acquire the coordinates of the click (touch) and you read the color of the pixel in that specific coordinates.
Having the color of the pixel and the tables of the colors of the different objects you rendered, makes possible for you to understand what the user clicked from a logical perspective.
There are other approaches to the object picking problem, this is probably universally recognized as the fastest one.
Cheers
Maurizio