Java Custom 3D Rotation doesn't look right - java

Java 3D Renderering
Context
Currently, I am working on a small 3D renderer. I am using Java.
The Problem
When I am rotating shapes, I noticed that the rotation is completely incorrect
(video on bottom)
What have I done?
I have:
Searched Stack Overflow
Printed out debug info
Redid rotation
None of these has worked.
Code
TVector
public class TVector {
public float x, y, z;
public TVector ogPos;
public TVector(float _x, float _y, float _z) {
this.x = _x;
this.y = _y;
this.z = _z;
this.ogPos = new TVector(this.x, this.y, this.z, true);
}
private TVector(float _x, float _y, float _z, boolean _throw) {
this.x = _x;
this.y = _y;
this.z = _z;
}
public TVector convertToOrthographic() {
return new TVector(this.x, this.y, 0);
}
}
Mesh
public class Mesh {
public Triangle[] tris;
public TVector rot = new TVector(0, 0, 0);
public void RotateX(float theta) {
this.rot.x += theta;
this.rot.x %= 360;
double cos = Math.cos(this.rot.x);
double sin = Math.sin(this.rot.x);
for (Triangle t : this.tris) {
for (TVector p : t.points) {
double[][] rotMatrix = new double[][] {
new double[] {
1, 0, 0
},
new double[] {
0, cos, -sin
},
new double[] {
0, sin, cos
}
};
double[][] posMatrix = new double[][] {
new double[] {
p.ogPos.x
},
new double[] {
p.ogPos.y
},
new double[] {
p.ogPos.z
}
};
double[][] finalRes = Utils.multiplyMatrices(rotMatrix, posMatrix);
p.x = (float) finalRes[0][0];
p.y = (float) finalRes[1][0];
p.z = (float) finalRes[2][0];
System.out.println(p.x);
System.out.println(p.y);
}
}
}
}
Plane
public class Plane extends Mesh {
public Plane(int x, int y, int z, int length) {
this.tris = new Triangle[] {
new Triangle(
new TVector(x, y, z),
new TVector(x + length, y, z),
new TVector(x, y + length, z)
),
new Triangle(
new TVector(x + length, y - length, z),
new TVector(x + length, y, z),
new TVector(x, y + length, z)
)
};
}
}
Note: There is a window rendering this stuff, and rotating the plane.
Gif:
I use REPLIT
Thanks in advance!
Rotation is in degrees.
EDIT:
Rotation is less buggier now

Related

How can I offset a Bounding Circle based on a rotation?

I am creating a Bullet projectile and giving it a Binding Circle with it. I am trying to set the circle to be at the front of the bullet so when it impacts it collides. Below is the bullet and a blue circle displaying the bounding circle location.
The bottom right example is what I am looking todo but with any rotation. Any thoughts on how I can offset the circle dynamically?
HitBox.java (This is the blue circle)
package com.icyrelic.game.object;
import com.icyrelic.game.object.entity.Entity;
import com.jogamp.opengl.math.VectorUtil;
import lombok.Getter;
import lombok.Setter;
public class HitBox {
#Getter
private GameObject object;
#Getter #Setter
private float width = 0, height = 0, xOffset = 0f, yOffset = 0f, radius = 0;
public HitBox(GameObject object, float width, float height) {
this.object = object;
this.width = width;
this.height = height;
}
public HitBox(GameObject entity, float radius) {
this.object = object;
this.radius = radius;
}
public boolean intersects(HitBox b) {
boolean collisionX = getMinX() <= b.getMaxX() && getMaxX() >= b.getMinX();
boolean collisionY = getMinY() <= b.getMaxY() && getMaxY() >= b.getMinY();
return collisionX && collisionY;
}
public boolean willCollide(HitBox b, float x, float y) {
//Circle vs Circle
if(radius != 0 && b.getRadius() != 0)
return circleCollide(x, y, b.getRadius(), b.getXOffset(), b.getYOffset());
//Circle vs AABB
if((radius != 0 && b.getRadius() == 0) || (radius == 0 && b.getRadius() != 0))
return circleAABBCollusion(b, x, y);
//AABB vs AABB
boolean collisionX = getMinX() <= x+b.getWidth()/2 && getMaxX() >= x-b.getWidth()/2;
boolean collisionY = getMinY() <= y+b.getHeight()/2 && getMaxY() >= y-b.getHeight()/2;
return collisionX && collisionY;
}
private boolean circleCollide(float x2, float y2, float radius2, float xOffset2, float yOffset2) {
double xDif = (object.getLocation().getX() + xOffset) - (x2 + xOffset2);
double yDif = (object.getLocation().getY() + yOffset) - (y2 + yOffset2);
double distanceSquared = xDif * xDif + yDif * yDif;
return distanceSquared < (radius + radius2) * (radius + radius2);
}
private boolean circleAABBCollusion(HitBox b, float x, float y) {
HitBox circle = radius == 0 ? b : this;
HitBox aabb = radius == 0 ? this : b;
float[] circleCenter = radius == 0 ? new float[] {x, y} : new float[] {object.getLocation().getX(), object.getLocation().getY()};
float[] aabbCenter = radius == 0 ? new float[] {object.getLocation().getX(), object.getLocation().getY()} : new float[] {x, y};
float closestX = circleCenter[0] + circle.getXOffset();
float closestY = circleCenter[1] + circle.getYOffset();
if(closestX < aabb.getMinX(aabbCenter[0])) closestX = aabb.getMinX(aabbCenter[0]);
else if (closestX > aabb.getMaxX(aabbCenter[0])) closestX = aabb.getMaxX(aabbCenter[0]);
if(closestY < aabb.getMinY(aabbCenter[1])) closestY = aabb.getMinY(aabbCenter[1]);
else if (closestY > aabb.getMaxY(aabbCenter[1])) closestY = aabb.getMaxY(aabbCenter[1]);
float dist = VectorUtil.distSquareVec3(new float[]{circleCenter[0]+circle.getXOffset(), circleCenter[1]+circle.getYOffset(), 1}, new float[]{closestX, closestY, 1});
return dist <= circle.getRadius() * circle.getRadius();
}
private float getMinX() { return object.getLocation().getX()+xOffset - width/2; }
private float getMaxX() { return object.getLocation().getX()+xOffset + width/2; }
private float getMinY() { return object.getLocation().getY()+yOffset - height/2; }
private float getMaxY() { return object.getLocation().getY()+yOffset + height/2;}
private float getMinX(float x) { return x+xOffset - width/2; }
private float getMaxX(float x) { return x+xOffset + width/2; }
private float getMinY(float y) { return y+yOffset - height/2; }
private float getMaxY(float y) { return y+yOffset + height/2;}
public void setSize(float width, float height) { this.width = width; this.height = height; }
public void setOffset(float x, float y) { this.xOffset = x; this.yOffset = y; }
}
Bullet.java
package com.icyrelic.game.object.projectile.type;
import com.icyrelic.game.Graphics.Animation;
import com.icyrelic.game.Graphics.ImageResource;
import com.icyrelic.game.object.projectile.Projectile;
public class Bullet extends Projectile {
public Bullet(float x, float y, float width, float height, float rotation, float rotationOffset) {
super(x,y,width, height, rotation, rotationOffset);
hitBox.setRadius(0.03f);
hitBox.setYOffset(-0.12f);
location.setRotationOffset(-0f);
animations = new Animation[1];
ImageResource[] a = new ImageResource[1];
a[0] = new ImageResource("/Projectile/Bullet.png");
animations[0] = new Animation(a, 1);
}
#Override
public void update() {
//location.setRotation(0);
}
}
Projectile.java
package com.icyrelic.game.object.projectile;
import com.icyrelic.game.Graphics.Graphics;
import com.icyrelic.game.object.GameObject;
import com.icyrelic.game.object.HitBox;
import lombok.Getter;
#Getter
public abstract class Projectile extends GameObject {
protected float speed = 1.0f;
protected HitBox hitBox;
public Projectile(float x, float y, float width, float height, float rotation, float rotationOffset) {
super(x, y, width, height, rotation, rotationOffset);
this.hitBox = new HitBox(this, width, height);
}
#Override
public void render() {
super.render();
Graphics.setColor(0,0, 1, 1);
if(hitBox.getRadius() == 0) {
Graphics.drawRect(location.getX() + hitBox.getXOffset(), location.getY() + hitBox.getYOffset(), hitBox.getWidth(), hitBox.getHeight(), false);
} else {
Graphics.drawHollowCircle(location.getX() + hitBox.getXOffset(), location.getY() + hitBox.getYOffset(), hitBox.getRadius());
}
Graphics.setColor(1,0, 0, 1);
//Graphics.drawRect(location.getX(), location.getY(), width/2, height/2, false);
Graphics.setColor(1,1, 1, 1);
Graphics.setColor(1,1, 1, 1);
}
}
GameObject.java
package com.icyrelic.game.object;
import com.icyrelic.game.Graphics.Animation;
import com.icyrelic.game.Graphics.Graphics;
import com.icyrelic.game.world.Location;
import lombok.Getter;
#Getter
public abstract class GameObject {
protected Location location;
protected float width = 1, height = 1;
protected float xImageOffset = 0, yImageOffset = 0;
protected Animation[] animations;
protected int currentAnimation = 0;
public GameObject(float x, float y, float width, float height, float rotation, float rotationOffset) {
this.location = new Location(x, y, rotation, rotationOffset);
this.width = width;
this.height = height;
}
public void render () {
animations[currentAnimation].play();
Graphics.setRotation(location.getRotation() + location.getRotationOffset());
Graphics.drawImage(animations[currentAnimation].getImage(), location.getX(), location.getY(), xImageOffset, yImageOffset, width, height);
Graphics.setRotation(0);
//Graphics.setRotation(-rotation);
}
public abstract void update ();
}
After trying to translate the information provided by Alberto I have the following result. its somewhat closer in the right direction but still not 100%
hitBox.setXOffset(((float) Math.sin(location.getRotationRadians()) ));
hitBox.setYOffset(((float) Math.cos(location.getRotationRadians()) ));
Since
Graphics.drawHollowCircle(location.getX() + hitBox.getXOffset(), location.getY() + hitBox.getYOffset(), hitBox.getRadius());
Is always drawing at the bottom, this
Graphics.drawHollowCircle(location.getX() + hitBox.getXOffset(), location.getY() + hitBox.getYOffset() / 2, hitBox.getRadius());
Should draw the circle in the center... then using some trigonometry, to get the center of the circle you will have to do something like this:
float offsetX = Math.sin(location.getRotation()) * (hitBox.getYOffset() / 2);
float offsetY = Math.cos(location.getRotation()) * (hitBox.getYOffset() / 2);
Graphics.drawHollowCircle(location.getX() + offsetX, location.getY() + offsetY, hitBox.getRadius());
assuming location.getRotation() will return the radiants to rotate

Did I correctly translate this pseudocode into Java?

I asked this question on Math.se a few days ago, and got the following answer in pseudocode:
Function RandomCircleInside(centerX, centerY, radius):
Let newRadius = radius * Random()
Let radians = 2.0 * 3.14159265358979323846 * Random()
Let deviation = (radius - newRadius) * Sqrt(Random())
Let newX = centerX + deviation * Cos(radians)
Let newY = centerY + deviation * Sin(radians)
Return (newX, newY, newRadius)
End Function
I changed the pseudocode to Java and added my own changes to fit my needs. The new code looks like this:
Circle createNewCircle(int centerX, int centerY, int radius, int newR, Color newColor) {
int newRadius = radius * Random();
double radians = 2.0 * 3.141592653589793 * Random();
double deviation = (radius - newRadius) * Math.sqrt(Random());
System.out.println(radius + " - " + newRadius + " * sqrt(0 or 1) = " + (radius-newRadius) + " * (0 or 1) = " + deviation);
double newX = centerX + deviation * Math.cos(radians);
System.out.println(centerX + " + " + deviation + " * cos(" + radians + ") = " + (centerX + deviation) + " * " + Math.cos(radians));
double newY = centerY + deviation * Math.sin(radians);
int newCirX = (int) newX;
int newCirY = (int) newY;
Circle newCir = new Circle(newCirX, newCirY, newR*2, newR*2, newR, newColor, true);
return newCir;
}
The code itself is supposed to create a new Circle inside of a preexisting one. I created a circle class that looks like this:
import java.awt.Color;
import java.awt.Graphics;
public class Circle {
public int X, Y, Width, Height, radius;
public Color color;
public boolean toFill;
public Circle(int x, int y, int width, int height, int radius, Color color, boolean fill) {
X = x;
Y = y;
Width = width;
Height = height;
this.radius = radius;
this.color = color;
toFill = fill;
}
public void render(Graphics g) {
g.setColor(color);
for(int i=-5; i<5; i++) {
if(toFill) {
g.fillOval(X+i, Y+i, Width-i, Height-i);
} else {
g.drawOval(X+i, Y+i, Width-i, Height-i);
}
}
}
public boolean contains(Circle pBound) {
int pBoundCenterX = pBound.X+pBound.radius;
int cirCenterX = X+radius;
int diffBetweenCentersX = Math.abs(pBoundCenterX-cirCenterX);
int pBoundCenterY = pBound.Y+pBound.radius;
int cirCenterY = Y+radius;
int diffBetweenCentersY = Math.abs(pBoundCenterY-cirCenterY);
if(diffBetweenCentersX<= (pBound.radius+radius) && diffBetweenCentersX>=Math.abs(pBound.radius-radius)) { // X
if(diffBetweenCentersY>=Math.abs(pBound.radius-radius)) { // Y
return true;
}
}
return false;
}
public int getX() {
return X;
}
public int getWidth() {
return Width;
}
public int getRadius() {
return radius;
}
public void setWidth(int width) {
Width = width;
}
public int getHeight() {
return Height;
}
public void setHeight(int height) {
Height = height;
}
public void setX(int x) {
X = x;
}
public int getY() {
return Y;
}
public void setY(int y) {
Y = y;
}
}
My way of creating the new circle is this:
if(secInGame==timesForCircle[X] && !hasChanged) { // circle 2
Circle cir1 = cir;
cir = createNewCircle(cir1.X+(cir1.Width/2), cir1.Y+(cir1.Height/2), cir1.getRadius(), 135, Color.cyan);
hasChanged = true;
circleOn++;
circ++;
}
Where cir1 is the preexisting Circle and cir is the new circle.
Is there anything I didn't code correctly? I've tried a few different variations, but they all give the same result.
Before I implemented the pseudocode, my circles looked like this:
but now it looks like this:
All of my code can be found on github at: link
I think there are several issues in your code.
1. First of all it is not clear why your Circle has radius, Width and Height. For a circle all 3 things should be the same. Also your render in case toFill is true looks strange. Here is a simplified version (note: I didn't compile it so there might be some bugs):
public class Circle {
public int X, Y, radius;
public Color color;
public boolean toFill;
public Circle(int x, int y, int radius, Color color, boolean fill) {
X = x;
Y = y;
this.radius = radius;
this.color = color;
toFill = fill;
}
public void render(Graphics g) {
g.setColor(color);
final int r2 = 2*radius;
if(toFill) {
g.fillOval(X, Y, r2, r2);
}
else {
for(int i=-5; i<5; i++) {
g.drawOval(X+i, Y+i, r2-i, r2-i);
}
}
}
public boolean contains(Circle pBound) {
int pBoundCenterX = pBound.X+pBound.radius;
int cirCenterX = X+radius;
int diffBetweenCentersX = Math.abs(pBoundCenterX-cirCenterX);
int pBoundCenterY = pBound.Y+pBound.radius;
int cirCenterY = Y+radius;
int diffBetweenCentersY = Math.abs(pBoundCenterY-cirCenterY);
if(diffBetweenCentersX<= (pBound.radius+radius) && diffBetweenCentersX>=Math.abs(pBound.radius-radius)) { // X
if(diffBetweenCentersY>=Math.abs(pBound.radius-radius)) { // Y
return true;
}
}
return false;
}
public int getX() {
return X;
}
public int getRadius() {
return radius;
}
public void setX(int x) {
X = x;
}
public int getY() {
return Y;
}
public void setY(int y) {
Y = y;
}
}
I didn't check your code, but I'd consider as a good practice:
renaming x and y into leftX and topY to avoid confusion with centerX/centerY meaning. Or change meaning to more typical center one.
declaring all your fields as private (see encapsulation);
declaring all your fields as final and remove all the setXyz methods (see immutability)
2. I don't understand why your createNewCircle has newR parameter and at the same time you generate a random newRadius in the first line. One of these definitely should be removed. Given that the parameter is always a constant 135 I think it should be removed.
3. Now I believe the main bug in your translation is in the lines
int newCirX = (int) newX;
int newCirY = (int) newY;
It probably should be something like
int newCirX = (int) newX - newRadius;
int newCirY = (int) newY - newRadius;
It looks like you messed with center vs top-left. Actually I think the fact that you made such a bug is an argument that supports renaming x and y I suggested in item #1.

Java draw 3d points to 2d system using 3d projection

I have tried to follow the Wikipedia page on 3d projection to draw my own 3d line using java and AWT with Swing.
The output file that is created as a result of the rendering doesn't contain anything.
What have I done wrong?
Why isn't this producing an image file that has points on it?
Are my formulas off?
I was following this Wikipedia page as my reference: https://en.wikipedia.org/wiki/3D_projection#Perspective_projection
I have a set of points which are generated using a loop.
I then calculate the position of the 3d coordinate to 2d without using matrices, like one of the suggested method in the link.
Have I miss-interpreted something or not implemented something?
Any help and feedback are welcome.
I known nothing is drawn to the window. That isn't a priority at the moment. The priority it's getting the algorithms to work.
public class Window {
JFrame f = new JFrame();
public Window() {
JPanel p = new JPanel();
render();
f.add(p);
f.setSize(500, 500);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
Window w = new Window();
}
void render() {
BufferedImage image = new BufferedImage(300, 300, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.setColor(Color.red);
for (int i = 0; i < 10; i++) {
Vector3 point = new Vector3(1 + i, 2, 1 + i);
int x = calculateBX(point, new Vector3(0, 0, 0));
int y = calculateBY(point, new Vector3(1, 1, 1));
g.drawLine(x, y, x, y);
}
try {
File outputfile = new File("saved.png");
ImageIO.write(image, "png", outputfile);
} catch (IOException e) {
e.printStackTrace();
}
}
double calculatDX(Vector3 v, Vector3 camera) {
double cx = Math.cos(0);
double cy = Math.cos(0);
double cz = Math.cos(0);
double sx = Math.sin(0);
double sy = Math.sin(0);
double sz = Math.sin(0);
int x = v.getX() - camera.getX();
int y = v.getY() - camera.getY();
int z = v.getZ() - camera.getZ();
double dx = cy * ((sz) * (y) + (cz) * (x)) - (sy) * (z);
return dx;
}
double calculatDY(Vector3 v, Vector3 camera) {
double cx = Math.cos(0);
double cy = Math.cos(0);
double cz = Math.cos(0);
double sx = Math.sin(0);
double sy = Math.sin(0);
double sz = Math.sin(0);
int x = v.getX() - camera.getX();
int y = v.getY() - camera.getY();
int z = v.getZ() - camera.getZ();
double dy = sx * ((cy) * (z) + (sy) * ((sz) * (y) + (cz) * (x))) + (cx) * (cz * (y) - sz * x);
return dy;
}
double calculatDZ(Vector3 v, Vector3 camera) {
double cx = Math.cos(0);
double cy = Math.cos(0);
double cz = Math.cos(0);
double sx = Math.sin(0);
double sy = Math.sin(0);
double sz = Math.sin(0);
int x = v.getX() - camera.getX();
int y = v.getY() - camera.getY();
int z = v.getZ() - camera.getZ();
double dz = cx * ((cy) * (z) + (sy) * ((sz) * (y) + (cz) * (x))) - (sx) * (cz * (y) - sz * x);
return dz;
}
int calculateBX(Vector3 v, Vector3 camera) {
int ez = camera.getZ();
int ex = camera.getX();
double dz = calculatDZ(v, camera);
double dx = calculatDX(v, camera);
return (int) ((ez / dz) * dx) - ex;
}
int calculateBY(Vector3 v, Vector3 camera) {
int ez = camera.getZ();
int ey = camera.getY();
double dz = calculatDZ(v, camera);
double dy = calculatDY(v, camera);
return (int) ((ez / dz) * dy) - ey;
}
}
Vector Class
public class Vector3 {
private int x, y, z;
public Vector3(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZ() {
return z;
}
}

Draw intersection of two regions in JavaFX

I have a few restrictions type of a ax+by>=c (1) and x>=z and y>=k (2). Restrictions (1) and (2) make a regions. I need to find the intersection of this regions and fill that other color. How can I do it in JavaFX? Can I use Canvas for solve this?
Sure, just fill everything with the polygon color and then for each area fill everything not in the area with the background color.
Note that this way you fill the whole Canvas except for the polygon with the background color.
public class Area {
private final double x;
private final double y;
private final double threshold;
private final int minCorner;
public Area(double x, double y, double threshold, boolean greater) {
if (x == 0 && y == 0) {
throw new IllegalArgumentException();
}
if (greater) {
x *= -1;
y *= -1;
threshold *= -1;
}
this.x = x;
this.y = y;
this.threshold = threshold;
boolean yPos = y > 0;
// find corner with minimum result for evaluate
this.minCorner = x < 0 ? (yPos ? 1 : 2) : (yPos ? 0 : 3);
}
public Area(double x, double y, double threshold) {
this(x, y, threshold, false);
}
private static final int[][] CORNER_FACTORS = {
{0, 0},
{1, 0},
{1, 1},
{0, 1}
};
public boolean contains(double x, double y) {
return evaluate(x, y) <= threshold;
}
public double hLineIntersection(double y) {
if (x == 0) {
return this.y * y == threshold ? Double.POSITIVE_INFINITY : Double.NaN;
} else {
return (threshold - this.y * y) / this.x;
}
}
public double vLineIntersection(double x) {
if (y == 0) {
return this.x * x == threshold ? Double.POSITIVE_INFINITY : Double.NaN;
} else {
return (threshold - this.x * x) / this.y;
}
}
private double evaluate(double x, double y) {
return this.x * x + this.y * y;
}
public void fillCleanArea(GraphicsContext gc, double w, double h) {
double[] xcoords = new double[5];
double[] ycoords = new double[5];
int[] factors = CORNER_FACTORS[minCorner];
boolean inside = contains(factors[0] * w, factors[1] * h);
int ptIndex = 0;
for (int i = minCorner, max = minCorner + 4; i < max; i++) {
factors = CORNER_FACTORS[i % 4];
double x = factors[0] * w;
double y = factors[1] * h;
boolean nowInside = contains(x, y);
if (inside != nowInside) {
// add intersection point with side
if ((i & 1) == 0) {
ycoords[ptIndex] = vLineIntersection(x);
xcoords[ptIndex++] = x;
} else {
xcoords[ptIndex] = hLineIntersection(y);
ycoords[ptIndex++] = y;
}
inside = nowInside;
// stop, if the end point is inside the area again
if (inside) {
break;
}
}
// add corners outside the bounds to polygon
if (!inside) {
xcoords[ptIndex] = x;
ycoords[ptIndex++] = y;
}
}
// draw polygon
if (ptIndex > 0) {
gc.fillPolygon(xcoords, ycoords, ptIndex);
}
}
}
public static void draw(Canvas canvas, Paint fill, Paint background, Area... areas) {
GraphicsContext gc = canvas.getGraphicsContext2D();
double w = canvas.getWidth();
double h = canvas.getHeight();
// fill everything with polygon color
gc.setFill(fill);
gc.fillRect(0, 0, w, h);
// fill everything outside the polygon with background color
gc.setFill(background);
for (Area area : areas) {
area.fillCleanArea(gc, w, h);
}
}
#Override
public void start(Stage primaryStage) {
Canvas canvas = new Canvas(400, 400);
draw(canvas, Color.BLUE, Color.WHITE,
new Area(1, 1, 400), new Area(1, -1, 100), new Area(1, -1, -100, true), new Area(1, 2, 250, true));
StackPane root = new StackPane(canvas);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
This won't give you the polygon's corner points though...

Moving cube in opengl on android help

After a lot of trial and error I was able to draw a cube and a tile map for the cube to be infront of. I added input so that when you move your finger, the camera moves. But now I want to add the next step in my games progression. I want it to have my cube move to where i pressed my finger in 3d space. It sounds a bit difficult. What I wanted to do is have you use one finger to slide the camera around the map and the other to double tap and move. So far my cube jitters and wobbles in place but doesn't move to where I want it to go. Of course none of my code is perfect and my following of gluunproject might be far from correct. Here is my code so far
The cube creator and update code//its short
public shapemaker(int x, int y, int z,int width)
{
centerx =x;
centery =y;
centerz =z;
mysquare1= new square(centerx,centery,centerz-5,1,.0f,.0f,1f,"vert");
mysquare2= new square(centerx-1,centery,centerz-6f,1,.0f,1.0f,.0f,"side");
mysquare3= new square(centerx,centery,centerz-7,1,1.0f,.0f,.0f,"vert");
mysquare4= new square(centerx+1,centery,centerz-6f,1,.0f,.5f,.5f,"side");
mysquare5= new square(centerx,centery-1,centerz-6f,1,.5f,.5f,.0f,"horiz");
mysquare6= new square(centerx,centery+1,centerz-6f,1,.5f,.0f,.5f,"horiz");
}
public void updatecube(float x, float y, float z)
{
centerx =x;
centery =y;
centerz =z;
mysquare1= new square(centerx,centery,centerz-5,1,.0f,.0f,1f,"vert");
mysquare2= new square(centerx-1,centery,centerz-6f,1,.0f,1.0f,.0f,"side");
mysquare3= new square(centerx,centery,centerz-7,1,1.0f,.0f,.0f,"vert");
mysquare4= new square(centerx+1,centery,centerz-6f,1,.0f,.5f,.5f,"side");
mysquare5= new square(centerx,centery-1,centerz-6f,1,.5f,.5f,.0f,"horiz");
mysquare6= new square(centerx,centery+1,centerz-6f,1,.5f,.0f,.5f,"horiz");
}
public void drawcube(GL10 gl)
{
mysquare1.draw(gl);
mysquare2.draw(gl);
mysquare3.draw(gl);
mysquare4.draw(gl);
mysquare5.draw(gl);
mysquare6.draw(gl);
}
public float getcenterx()
{
return centerx;
}
public float getcentery()
{
return centery;
}
public float getcenterz()
{
return centerz;
}
Here is the actual implementation code , it is based off of googles intro to opengl
class ClearGLSurfaceView extends GLSurfaceView {
private static final String BufferUtils = null;
float x =0;
float y =0;
float z =0f;
float prevx=0;
float prevy=0;
GL10 mygl;
// GL gl;
float mywidth;
float myheight;
public ClearGLSurfaceView(Context context,float width, float height) {
super(context);
mRenderer = new ClearRenderer();
setRenderer(mRenderer);
mywidth = width;
myheight = height;
}
#Override
public boolean onTouchEvent(final MotionEvent event)
{
queueEvent(new Runnable() {
// Find the index of the active pointer and fetch its position
public void run()
{
float curx = event.getX();
float cury = event.getY();
final int action = event.getAction();
if(action == MotionEvent.ACTION_MOVE)
{
if(curx>prevx)
{
x-=.1f;
}
if(curx<prevx)
{
x+=.1f;
}
if(cury>prevy)
{
y+=.1f;
}
if(cury<prevy)
{
y-=.1f;
}
}
if(action == MotionEvent.ACTION_DOWN)
{
// GLU.gluUnProject(winX, winY, winZ, model,
// modelOffset, project, projectOffset, view, viewOffset, obj, objOffset)
vector2d moveto = new vector2d(0,0);
moveto = mRenderer.getworkcoords(curx,cury);
Log.i("move to ", "x "+moveto.x+" y "+ moveto.y+" z " + moveto.z);
mRenderer.updatemoveto(moveto.x, moveto.y);
}
prevx= curx;
prevy = cury;
mRenderer.updatecamera(x, y, z);
}
});
return true;
}
ClearRenderer mRenderer;
}
class ClearRenderer implements GLSurfaceView.Renderer {
GL10 mygl;
GL11 mygl11;
int viewport[] = new int[4];
float modelview[] = new float[16];
float projection[] = new float[16];
float wcoord[] = new float[4];
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // OpenGL docs.
gl.glShadeModel(GL10.GL_SMOOTH);// OpenGL docs.
gl.glClearDepthf(1.0f);// OpenGL docs.
gl.glEnable(GL10.GL_DEPTH_TEST);// OpenGL docs.
gl.glDepthFunc(GL10.GL_LEQUAL);// OpenGL docs.
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, // OpenGL docs.
GL10.GL_NICEST);
mygl = gl;
mygl11 = (GL11) gl;
int index;
int counter = 0;
float zcoord = -7.0f;
mygl11.glGetFloatv(GL11.GL_MODELVIEW_MATRIX, modelview, 0);
mygl11.glGetFloatv(GL11.GL_PROJECTION_MATRIX, projection, 0);
mygl11.glGetIntegerv(GL11.GL_VIEWPORT, viewport, 0);
for(int x=0;x<11;x++)
{
for(int y =0;y<10;y++)
{
index = tilemap1[y][x];
if(index==0)
{
tiles[counter]=new square(x,y,zcoord,0.5f,1.0f,0.0f,0f,"vert");
}
if(index==1)
{
tiles[counter]=new square(x,y,zcoord,0.5f,0f,1.0f,0f,"vert");
}
if(index==2)
{
tiles[counter]=new square(x,y,zcoord,0.5f,0.0f,0.0f,1f,"vert");
}
counter++;
}
}
}
public vector2d getworkcoords(float width,float height)
{
float[] depth = new float[1];
float winx = width;
float winy =viewport[3]-height;
//vector2d position = new vector2d(0,0);
int test = GLU.gluUnProject(winx, winy,0.0f, modelview, 0, projection,
0, viewport, 0, wcoord, 0);
vector2d v = new vector2d(0,0);
v.x = wcoord[0];
v.y = wcoord[1];
v.z = wcoord[2];
return v ;
}
public void onSurfaceChanged(GL10 gl, int w, int h) {
gl.glViewport(0, 0, w, h);
gl.glMatrixMode(GL10.GL_PROJECTION);// OpenGL docs.
gl.glLoadIdentity();// OpenGL docs.
GLU.gluPerspective(gl, 45.0f,
(float) w / (float) h,
0.1f, 100.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW);// OpenGL docs.
gl.glLoadIdentity();// OpenGL docs.
}
public float movetox;
public float movetoy;
float currentposx;
float currentposy;
public void updatemoveto(float x , float y)
{
movetox = x;
movetoy = y;
}
public void onDrawFrame(GL10 gl) {
gl.glClearColor(mRed, mGreen, mBlue, 1.0f);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
currentposx = mycube.getcenterx();
currentposy = mycube.getcentery();
float x = movetox -currentposx;
float y = movetoy - currentposy;
double angle = Math.atan2(y, x);
double mx =.5f* Math.cos(angle);
double my = .5f* Math.sin(angle);
double mmx = mx+ currentposx;
double mmy = my+ currentposy;
mycube.updatecube((float)(mmx), (float)(mmy),0);
mycube.drawcube(gl);
for(int i = 0;i<110;i++)
{
tiles[i].draw(gl);
}
}
public void setColor(float r, float g, float b) {
mRed = r;
mGreen = g;
mBlue = b;
}
public void updatecamera(float myx, float myy, float myz)
{
mygl.glLoadIdentity();// OpenGL docs.
GLU.gluLookAt(mygl, myx, myy, myz, myx, myy, myz-10, 0, 1, 0);
}
private float mRed;
private float mGreen;
private float mBlue;
int tilemap1[][] = {
{0,0,0,0,0,0,0,0,0,0,0},
{0,1,2,1,1,1,1,1,1,1,0},
{0,1,2,1,1,1,1,1,1,1,0},
{0,1,2,1,1,1,1,1,1,1,0},
{0,1,2,2,2,1,1,1,1,1,0},
{0,1,1,1,2,1,1,1,1,1,0},
{0,1,1,1,2,1,1,1,1,1,0},
{0,1,1,1,2,1,1,1,1,1,0},
{0,1,1,1,2,2,1,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0},
};
square[] tiles = new square[110];
shapemaker mycube = new shapemaker(0,0,0,1);
}
I did not include the on create method and the on pause ones. I would also like advice on designing the code structure because my implementation is far from perfect.
So in short. I would like help figuring out how to modify the code I made to have a cube move to where i press. And how you would improve the code
Thanks
First of all,
you don't need to recreate vertices on every moving. It is very complex task and it will low the framerate (FPS). In you code you have model matrix. Usually it is responsible for translating, scaling rotating of your model(mesh, cube in your example). In common case you have to translate the model matrix and then multiple model, projection and view matrixes, you will get the matrix for your device screen. Then by multiplication of vertex postion and this matrix you'll get the right position of vertex.
you can look at this question/answer

Categories

Resources