Draw cylinder from point X to point Y in Processing - java

I have to points in 3D space that I want to draw a cylinder between. I currently have this code:
applet.pushMatrix();
applet.stroke(0);
applet.fill(0);
applet.line(this.start.x, this.start.y, this.start.z, this.end.x, this.end.y, this.end.z); //debug, shows where the cylinder should be
applet.translate(this.start.x, this.start.y);
applet.beginShape(PConstants.TRIANGLE_STRIP);
float xdif = this.end.x - this.start.x;
float ydif = this.end.y - this.start.y;
float zdif = this.end.z - this.start.z;
float rx = (float)Math.atan(ydif / xdif);
float ry = (float)Math.atan(zdif / xdif);
float rz = (float)Math.atan(zdif == 0 ? 0 : ydif / zdif);
applet.rotateZ((float) (rx - Math.PI / 2));
applet.rotateY((float) (ry - Math.PI / 2));
applet.rotateX((float) (rz - Math.PI / 2));
float r = 20;
float len = HelperFunctions.distance(this.start, this.end) / 2;
boolean w = false;
for (int i = 0; i < 2; i += 1) {
for (float j = 0; j < Math.PI * 2 + 0.2; j += 0.4) {
w = !w;
float z = (i + (w ? 0 : 1)) * len;
float x = (float)(r * Math.cos(j));
float y = (float)(r * Math.sin(j));
applet.vertex(y, x, z);
}
}
applet.endShape();
applet.popMatrix();
The cylinder does draw correctly, however, it doesn't rotate correctly. I'm trying to use trig to determine the rotation angles, however, I'm not sure I've done it correctly. How would I get the correct angles to rotate around such that it is drawn from Vector start to Vector end?
Vector is a custom class with just a float x, y, z, and HelperFunctions.distance takes two Vectors and calculates the distance (pythagoras).
Thanks in advance.

Related

Java Rotate 3D Vertices around Y axis

I have a 3D model and I need to rotate its vertices around the Y axis (The axis going straight up in my case). For example lets say i have the vert
(3,2,3)(x,y,z) and when i rotate around the Y axis only the x and z's will change. how could I implement this in java using degrees? Thanks in advance!
(FYI) this is for rotating the points on my hitbox. Each "box" is just a triangle but wrapped in a cube so i can just check if a point is in the cube. This is done per triangle per model. This works perfectly because im able to walk through meshes with holes in them and everything. However, if any rotation is applied weird things start to happen.
Edit: here is my code using Andys method
public static boolean checkPointCollision(Vector3f pos){
boolean hit=false;
float px=Math.round(pos.x);
float py=Math.round(pos.y);
float pz=Math.round(pos.z);
px=pos.x;
py=pos.y;
pz=pos.z;
long startTime=System.currentTimeMillis();
float xmin,ymin,zmin,xmax,ymax,zmax,scale,rot;
//Cube Collisions
for (Entity entity : entities) {
int colID=entity.getCollisionIndex();
boolean entHasHitbox = entity.hasHitbox();
if(colID!=-1 && hit==false && entHasHitbox){
//Gets the entitys variables
scale = entity.getScale();
rot = entity.getRotY();
//Converts to radians
rot = (float) Math.toRadians(rot);
xmin = 0;
ymin = 0;
zmin = 0;
xmax = 0;
ymax = 0;
zmax = 0;
switch(entity.getCollisionType()){
case 1:
if(entHasHitbox){
//Gets the entities hitbox
List<Vector3f> hitboxMins = entity.getHitboxMin();
List<Vector3f> hitboxMaxs = entity.getHitboxMax();
for (int i = 0; i < hitboxMins.size(); i++) {
//Gets the entities hitbox points
Vector3f min = hitboxMins.get(i);
Vector3f max = hitboxMaxs.get(i);
//Sets all local position vars to the hitboxes mins and maxes
xmin = min.x;
ymin = min.y;
zmin = min.z;
xmax = max.x;
ymax = max.y;
zmax = max.z;
//Applies the models scale
xmin *=scale;
ymin *=scale;
zmin *=scale;
xmax *=scale;
ymax *=scale;
zmax *=scale;
//Rotates points
float nxmin = (float) (Math.cos(rot) * xmin - Math.sin(rot) * zmin);
float nzmin = (float) (Math.sin(rot) * xmin + Math.cos(rot) * zmin);
float nxmax = (float) (Math.cos(rot) * xmax - Math.sin(rot) * zmax);
float nzmax = (float) (Math.sin(rot) * xmax + Math.cos(rot) * zmax);
//Sets old points to new ones
xmin = nxmin;
zmin = nzmin;
xmax = nxmax;
zmax = nzmax;
//Increase local points to the entitys world position
xmin += entity.getPosition().x;
xmax += entity.getPosition().x;
ymin += entity.getPosition().y;
ymax += entity.getPosition().y;
zmin += entity.getPosition().z;
zmax += entity.getPosition().z;
//Debug
if(entities.get(17)==entity){//entities.get(17).increaseRotation(0, 10, 0);
System.out.println(xmin+","+ymin+","+zmin);
}
//Check if point is in the hitbox
if(px>=xmin && px<=xmax
&& py>=ymin && py<=ymax
&& pz>=zmin && pz<=zmax)
{
hit=true;
//Ends to loop
i=hitboxMins.size();
}
}
}
break;
}
}
}
long endTime = System.currentTimeMillis()-startTime;
if(endTime>10){
System.out.println("Delay in Point Collision");
}
return hit;
}
Multiply your points by the following matrix:
[ c 0 -s ]
[ 0 1 0 ]
[ s 0 c ]
i.e.
[newx] [ c 0 -s ] [x]
[newy] = [ 0 1 0 ] [y]
[newz] [ s 0 c ] [z]
where (x, y, z) are your original coordinates, (newx, newy, newz) are your rotated coordinates, and c = cos(angle) and s = sin(angle). Note that Java's trig functions take their parameters as radians, so you need to convert the angle in degrees appropriately.
If you've not used matrices before, this is equivalent to the following three expressions:
newx = c * x - s * z
newy = y
newz = s * x + c * z

Image edge detection algorithm: creating a 2D mesh

Let's first start off with what I am trying to do. I would like to be able to take PNG file with a transparent background and find anywhere from 90 to 360 points along the edge of the subject of the image. Here is a rough example of what I mean. Given this image of Mario and Yoshi:
I want to make a circle that is centered at the center of the image with a diameter slightly larger than the largest side of the image to serve as a reference. Then, I want to go around the circle at set intervals, and trace a line towards the center until it hits a non-transparent pixel. Here is what that would look like:
I have attempted to implement this a few different times, all of which failed, and I was hoping to get some guidance or insight as to what I am doing wrong. Here is an image of the math I am using behind the code (sorry if the quality is not great, I don't have a scanner):
The Line 1 is either the top, bottom, left or right edge of the image, and Line 2 goes through the center of the circle at the given angle. The point where lines 1 and 2 intersect should be on the edge of the image, and is where we should start looking for the edge of the image's subject.
Here is the code that I came up with from this idea. I did it in Java because BufferedImage is really easy to use, but I am going to translate this over to C# (XNA) for the final product.
public class Mesh {
private int angleA, angleB, angleC, angleD;
private BufferedImage image;
private Point center;
public ArrayList<Point> points = new ArrayList<>();
public Mesh(BufferedImage image) {
center = new Point(image.getWidth() / 2, image.getHeight() / 2);
angleA = (int) (Math.atan(center.y / center.x) * (180 / Math.PI));
angleB = 180 - angleA;
angleC = 180 + angleA;
angleD = 360 - angleA;
this.image = image;
for(int angle = 0; angle <= 360; angle+=4){
Point point = getNext(angle);
if(point != null) points.add(point);
}
}
private Point getNext(int angle) {
double radians = angle * Math.PI / 180;
double xStep = Math.cos(radians);
double yStep = Math.sin(radians);
int addX = angle >= 90 && angle <= 270 ? 1 : -1;
int addY = angle >= 0 && angle <= 180 ? 1 : -1;
double x, y;
if (xStep != 0) {
double slope = yStep / xStep;
double intercept = center.y - (slope * center.x);
if (angle >= angleA && angle <= angleB) {
y = 0;
x = -intercept / slope;
} else if (angle > angleB && angle < angleC) {
x = 0;
y = intercept;
} else if (angle >= angleC && angle <= angleD) {
y = image.getHeight() - 1;
x = (y - intercept) / slope;
} else {
x = image.getWidth() - 1;
y = slope * x + intercept;
}
} else {
x = center.x;
y = angle <= angleB ? 0 : image.getHeight();
}
if (x < 0) x = 0;
if (x > image.getWidth() - 1) x = image.getWidth() - 1;
if (y < 0) y = 0;
if (y > image.getHeight() - 1) y = image.getHeight() - 1;
double distance = Math.sqrt(Math.pow(x - center.x, 2) + Math.pow(y - center.y, 2));
double stepSize = Math.sqrt(Math.pow(xStep, 2) + Math.pow(yStep, 2));
int totalSteps = (int) Math.floor(distance / stepSize);
for (int step = 0; step < totalSteps; step++) {
int xVal = (int) x;
int yVal = (int) y;
if(xVal < 0) xVal = 0;
if(xVal > image.getWidth() -1) xVal = image.getWidth() -1;
if(yVal < 0) yVal = 0;
if(yVal > image.getHeight()-1) yVal = image.getHeight() -1;
int pixel = image.getRGB(xVal, yVal);
if ((pixel >> 24) == 0x00) {
x += (Math.abs(xStep) * addX);
y += (Math.abs(yStep) * addY);
} else {
return new Point(xVal, yVal);
}
}
return null;
}
}
The algorithm should be returning all positive points that are all ordered in counterclockwise rotation (and non-overlapping) but I have failed to get the desired output (this being my most recent attempt) so just to restate the question, is there a formalized way of doing this, or can someone find the mistake I made in my logic. For visual reference, the Mario and Yoshi Traced image is sort of what the final output should look like, but with many more points (which would give more detail to the mesh).

Making a circle in an array (Tile based game light map)

I am making a tiled based game in java and I want to make a light map.
I am having some issues. I have the lightmap array that has lights placed on it that affect the array. Lights emit in a circle shape. It seems ok so far but its not exactly what I wanted.
Here is my code so far:
for(float i = 0; i < strength + 1; i++){
for(double u = 0.0f; u < 360; u += 0.5){
double angle = u * Math.PI / 180;
int x2 = (int)(x + i * Math.cos(angle));
int y2 = (int)(y + i * Math.sin(angle));
if(map[y2][x2] > 1 - 1 / i)
map[y2][x2] = 1 - 1 / i;
}
}
Result:
As you can see in the result, it seems as though the light is expanding too much on the bottom left side (red x's). How do I fix this?
Background info:
Strength:
The radius of how far the light reaches. This also
determines how bright the light will be at each tile of the array.
The Array "map" is a 2D float array. The engine I am using uses float
values for the alpha channel. The range is 0 (completely transparent)
to 1 (completely opaque).
Solution (Thanks to Gene):
for(int x2 = -strength; x2 <= strength; x2++){
for (int y2 = -strength; y2 <= strength; y2++) {
double r = Math.sqrt(x2 * x2 + y2 * y2);
double inv_rad = r <= strength + 1 ? 1 / r : 0;
if(map[y + y2][x + x2] > 1 - (float) inv_rad)
map[y + y2][x + x2] = 1 - (float) inv_rad;
}
}
Your algorithm suffers from integer truncation of the map indicies. Try it the other away around. Compute the distance from each pixel in a square surrounding the center to the center. From this distance calculate what the intensity ought to be. It will be something like this:
for (x = -R; x <= R; x++)
for (y = -R; y <= R; y++) {
double r = Math.sqrt(x * x + y * y);
double inv_rad = r <= R ? 1 / r : 0; // truncate outside radius R
map[yc + y][xc + x] = 1 - inv_rad;
}
Here xc and yc are the integer center coordinates. R is the half-size of the box around the center.
when i try to add this to my project i only get o.o back
the values i entered where 500, 500,50
private float map[][] = new float[1000][1000];
public void test(int x, int y, float strength){
public void addLight(int x,int y,int strength ){
for(int x2 = -strength; x2 <= strength; x2++){
for (int y2 = -strength; y2 <= strength; y2++) {
double r = Math.sqrt(x2 * x2 + y2 * y2);
double inv_rad = r <= strength + 1 ? 1 / r : 0;
if(map[y + y2][x + x2] > 1 - (float) inv_rad)
map[y + y2][x + x2] = 1 - (float) inv_rad;
System.out.println(map[y + y2][x + x2]);
}
}
}

OpenGL: two spheres in single vertex buffer

(Question is at bottom)Im learning opengl(using lwjgl) and done some drawing of flat shape through sending buffers. Now I need to draw many spheres in single buffer. In my last question, I was advised to use geometry instancing but I dont know how to use any shader language in java yet so I'm trying to make multiple objects in single buffer just like in the examples.
What I tried to generate two spheres by QUAD_STRIP style(using lwjgl's own GLU.Sphere() function to fill the buffers):
n=c1*(c2+1);
float rr=(float) Math.random();
float gg=(float) Math.random();
float bb=(float) Math.random();
float aa=(float) Math.random();
positions = new float[c1 * (c2+1) * 3*2 *2];
normals = new float[c1 * (c2+1) * 3*2 *2];
colors = new float[c1 * (c2+1) * 4*2 *2];
int counter=0;
float drho = 3.141593F / 32.0f;
float dtheta = 6.283186F / 32.0f;
float ds = 1.0F / 32.0f;
float dt = 1.0F / 32.0f;
float t = 1.0F;
/*first sphere*/
for (int i = 0; i < 32; i++) {
float rho = i * drho;
float s = 0.0F;
for (int j = 0; j <= 32; j++) {
float theta = j == 32 ? 0.0F : j * dtheta;
float x = (float) (-Math.sin(theta) * Math.sin(rho));
float y = (float) (Math.cos(theta) * Math.sin(rho));
float z = (float) (1.0f * Math.cos(rho));
normals[counter*3+0]=x*1.0f;normals[counter*3+1]=y*1.0f;normalscounter*3+2]=z*1.0f;
colors[counter*4+0]=rr;colors[counter*4+1]=gg;colors[counter*4+2]=bb;colors[counter*4+3]=1.0f/*aa*/;
positions[counter*3+0]=x*r;positions[counter*3+1]=y*r;positions[counter*3+2]=z*r;
counter++;
x = (float) (-Math.sin(theta) * Math.sin(rho + drho));
y = (float) (Math.cos(theta) * Math.sin(rho + drho));
z = (float) (1.0f * Math.cos(rho + drho));
normals[counter*3+0]=x*1.0f;normals[counter*3+1]=y*1.0f;normals[counter*3+2]=z*1.0f;
colors[counter*4+0]=rr;colors[counter*4+1]=gg;colors[counter*4+2]=bb;colors[counter*4+3]=1.0f/*aa*/;
positions[counter*3+0]=x*r;positions[counter*3+1]=y*r;positions[counter*3+2]=z*r;
counter++;
s += ds;
}
t -= dt;
}
/* first sphere end */
/* second sphere generation */
{
drho = 3.141593F / 32.0f;
dtheta = 6.283186F / 32.0f;
ds = 1.0F / 32.0f;
dt = 1.0F / 32.0f;
t = 1.0F;
for (int i = 0; i < 32; i++) {
float rho = i * drho;
float s = 0.0F;
for (int j = 0; j <= 32; j++) {
float theta = j == 32 ? 0.0F : j * dtheta;
float x = (float) (-Math.sin(theta) * Math.sin(rho));
float y = (float) (Math.cos(theta) * Math.sin(rho));
float z = (float) (1.0f * Math.cos(rho));
normals[counter*3+0]=x*1.0f;normals[counter*3+1]=y*1.0f;normals[counter*3+2]=z*1.0f;
colors[counter*4+0]=rr;colors[counter*4+1]=gg;colors[counter*4+2]=bb;colors[counter*4+3]=1.0f/*aa*/;
positions[counter*3+0]=x*r+1.0f;positions[counter*3+1]=y*r+1.0f;positions[counter*3+2]=z*r+1.0f;
counter++;
x = (float) (-Math.sin(theta) * Math.sin(rho + drho));
y = (float) (Math.cos(theta) * Math.sin(rho + drho));
z = (float) (1.0f * Math.cos(rho + drho));
normals[counter*3+0]=x*1.0f;normals[counter*3+1]=y*1.0f;normals[counter*3+2]=z*1.0f;
colors[counter*4+0]=rr;colors[counter*4+1]=gg;colors[counter*4+2]=bb;colors[counter*4+3]=1.0f/*aa*/;
positions[counter*3+0]=x*r+1.0f;positions[counter*3+1]=y*r+1.0f;positions[counter*3+2]=z*r+1.0f;
counter++;
s += ds;
}
t -= dt;
}
}
/*second sphere end*/
positionsBuf=BufferUtils.createFloatBuffer(c1 * (c2+1) * 3*2 *2);
positionsBuf.put(positions);
positionsBuf.rewind();
colorsBuf=BufferUtils.createFloatBuffer(c1 * (c2+1) * 4*2 *2);
colorsBuf.put(colors);
colorsBuf.rewind();
normalsBuf=BufferUtils.createFloatBuffer(c1 * (c2+1) * 3*2 *2);
normalsBuf.put(normals);
normalsBuf.rewind();
As you can see, below image shows how two spheres are drawn. There is an unwanted link between two.
Most probably the rope is caused by the last point of first sphere and first point of second sphere. Is there some kind of delimiter/drawing-hint to separate two drawings in the same buffer?
Here is how they are drawn:
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER,sphereBufferCol.get(0));
GL11.glColorPointer(4, GL11.GL_FLOAT, 0, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, sphereBufferPos.get(0));
GL11.glVertexPointer(3, GL11.GL_FLOAT, 0, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, sphereBufferNormal.get(0));
GL11.glNormalPointer(GL11.GL_FLOAT, 0, 0);
GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
GL11.glEnableClientState(GL11.GL_COLOR_ARRAY);
GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY);
//Each sphere is generated 32 by 32 quadstriparray and each having two sets of two points and there are two spheres
GL11.glDrawArrays(GL11.GL_QUAD_STRIP, 0, 32*33*2 *2);
GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
GL11.glDisableClientState(GL11.GL_COLOR_ARRAY);
GL11.glDisableClientState(GL11.GL_NORMAL_ARRAY);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
Question: How can I make that rope-like thing disappear without decreasing performance? Maybe putting zero to last and first points' alpha value can make it invisible but wouldnt that cause two holes on each sphere and decrease performance because of many lines on the screen?
All vertex values will be altered by opencl interoperability so single drawing call is needed to draw whole 10000+ spheres.
There seem to be a number of options:
use multiple buffers
use quads instead of quad strips
use primitive restart
use degenerate triangles, i.e. add the last vertex twice
use [instanced rendering] (http://www.opengl.org/wiki/Vertex_Rendering#Instancing)
If you are on newer hardware and want to use quad strips, I'd prefer using primitive restart.
Please note that this is just the result of a quick assessment and anchecked (I personally don't use quad strips or even tri strips that often ;) ).

Logic for analog stick produces a square instead of a circle

I'm trying to simulate an analog stick on a mobile platform.
I calculate a stick vector which based on the position of the finger and the radius of the stick returns a value from -1 to 1.
public void calcStickVector(float x, float y)
{
float cx = getCenterX();
float cy = getCenterY();
float distX = x - cx;
float distY = y - cy;
distX /= getRadius();
distY /= getRadius();
distX = JMath.clamp(-1.0f, 1.0f, distX);
distY = JMath.clamp(-1.0f, 1.0f, distY);
stickVector.x = distX;
stickVector.y = distY;
}
public RectF getInnerStickRect()
{
float r = getInnerRadius();
float cx = getCenterX() + (getRadius() * getStickVector().x);
float cy = getCenterY() + (getRadius() * getStickVector().y);
innerStickRect.left = cx - r;
innerStickRect.top = cy - r;
innerStickRect.right = cx + r;
innerStickRect.bottom = cy + r;
return innerStickRect;
}
It almost works, but visually the inner stick, when moved around seems to form a square rather than going around in a circle. Is there something wrong with my logic?
Thanks
As it is, you really are making a box with 1's as the corners. You need to normalize the vector(divide x and y by distance) instead of dividing by radius and clamping.
double dist = Math.sqrt(distX*distX) + (distY*distY));
distX /= dist;
distY /= dist;

Categories

Resources