Java 3d parametric surfaces drawing - java

i really need your help since that i am fighting with the unknown for some time now.
I am trying to draw a parametric surface on java 3d. The surface is being drawn if i a use a point array. Here is the code :
PointArray lsa=new PointArray(length, GeometryArray.COLOR_3|GeometryArray.NORMALS|GeometryArray.COORDINATES);
float maxV=(float) ((float) 2*Math.PI);
float maxU=(float) ((float) Math.PI);
Vector3f norm = new Vector3f();
for (float v = 0.01f; v < maxV; v+=0.03)
{
for (float u = 0.01f; u < maxU; u+=0.03)
{
vIndex++;
Point3f pt = new Point3f();
pt.x=(float) (Math.sin(u)*Math.cos(v));
pt.y=(float) (2*Math.sin(u)*Math.sin(v));
pt.z=(float) Math.cos(u);
lsa.setCoordinate(vIndex, pt);
lsa.setColor(vIndex, new Color3f(0.9f,0.0f,0.0f));
}
}
Shape3D shape = new Shape3D(lsa);
The problem that I have is that it's drawing only the points (dots) so it's not a full drawn surface. How can I draw this parametric surface with polygons or any surface? Are there any methods ?
I am searching the Web, bought Books but I still can not make it with java 3d.
Thank you very much.

Here's how I would do it.
I would define a
Point3f[][] points = new Point3f[(int)((umax-umin)/du)][(int)((vmax-vmin)/dv)];
Then use loops similar to the ones you have int i = 0; i<points.length; i++, int j = 0; j < points[0].length; j++. Define u = i * du + umin, v = j * dv + vmin.
and populate this array with Point3f corresponding to (u, v).
Loop int i = 0; i<points.length - 1; i++, int j = 0; j < points[0].length - 1; j++ and get the points at points[i][j], points[i+1][j], points[i][j+1], and points[i+1][j+1].
Then use the method given in this article to convert these points into a Polygon. Add it to your model / an array that you later add to your model.
Of course, this may not be the best way to do it and I have the feeling that it doesn't handle discontinuities very well, but it should at least make polygons.

Hello here is the solution, it draws a coons surface for example, it should work for any parametric surface x(s, t), y(s, t), z(s, t).
public static Shape3D getShape3D()
{
//Coons
int ns=100;
int nt=100;
float param0=1.0f;
float param1=3.0f;
float s=0.0f;
float t=0.0f;
if (ns>500) ns=500;
if (nt>500) nt=500;
Point3f[][] f=new Point3f[ns][nt];
int sizeOfVectors=0;
for (int i=0;i<ns;i++) //t -->s
{
for (int j=0;j<nt;j++) //u ---t
{
s=((float) i/ns);
t=((float) j/nt);
//System.out.println(" i "+ i + " j "+ j + " s "+ s + " t "+ t);
f[i][j]=new Point3f();
//f[i][j].x=s;
//f[i][j].y=2*t;
//f[i][j].z=10*t*(1-s);
f[i][j].x=param0*s;
f[i][j].y=param1*t;
f[i][j].z=(float) (0.5*((54*s*Math.sqrt(s)-126*Math.sqrt(s)+72*s-6)*t+(27*Math.sqrt(s)-27*s+6)));
/*f[i][j].x = (float) (Math.sqrt(s)*Math.cos(t));
f[i][j].y=(float) (Math.sqrt(s)*Math.sin(t));
f[i][j].z=s;*/
sizeOfVectors++;
sizeOfVectors++;
}
}
System.out.println("Total vectors "+sizeOfVectors);
Shape3D plShape = new Shape3D();
int vIndex=-1;
int k=0;
for (int i=0;i<(ns-1);i++)
{
k=i+1;
sizeOfVectors=nt*2;
vIndex=-1;
TriangleStripArray lsa=new TriangleStripArray(sizeOfVectors, GeometryArray.COLOR_3|GeometryArray.COORDINATES|GeometryArray.NORMALS, new int[] {sizeOfVectors});
for (int j=0;j<nt;j++)
{
vIndex++;
lsa.setCoordinate(vIndex, f[i][j]);
lsa.setColor(vIndex, new Color3f(0.9f,0.0f,0.0f));
vIndex++;
lsa.setCoordinate(vIndex, f[k][j]);
lsa.setColor(vIndex, new Color3f(0.9f,0.0f,0.0f));
}
plShape.addGeometry(lsa);
}
return plShape;
}
It works like a dream. Your guidance was the catalyst to finally make it.

Related

Problem with Scan-Line Polygon Filling algorithm in java

(please don't mark this question as not clear, I spent a lot of time posting it ;) )
Okay, I am trying to make a simple 2d java game engine as a learning project, and part of it is rendering a filled polygon as a feature.
I am creating this algorithm my self, and I really can't figure out what I am doing wrong.
My though process is something like so:
Loop through every line, get the number of points in that line, then get the X location of every point in that line,
Then loop through the line again this time checking if the x in the loop is inside one of the lines in the points array, if so, draw it.
Disclaimer: the Polygon class is another type of mesh, and its draw method returns an int array with lines drawn through each vertex.
Disclaimer 2: I've tried other people's solutions but none really helped me and none really explained it properly (which is not the point in a learning project).
The draw methods are called one per frame.
FilledPolygon:
#Override
public int[] draw() {
int[] pixels = new Polygon(verts).draw();
int[] filled = new int[width * height];
for (int y = 0; y < height; y++) {
int count = 0;
for (int x = 0; x < width; x++) {
if (pixels[x + y * width] == 0xffffffff) {
count++;
}
}
int[] points = new int[count];
int current = 0;
for (int x = 0; x < width; x++) {
if (pixels[x + y * width] == 0xffffffff) {
points[current] = x;
current++;
}
}
if (count >= 2) {
int num = count;
if (count % 2 != 0)
num--;
for (int i = 0; i < num; i += 2) {
for (int x = points[i]; x < points[i+1]; x++) {
filled[x + y * width] = 0xffffffff;
}
}
}
}
return filled;
}
The Polygon class simply uses Bresenham's line algorithm and has nothing to do with the problem.
The game class:
#Override
public void load() {
obj = new EngineObject();
obj.addComponent(new MeshRenderer(new FilledPolygon(new int[][] {
{0,0},
{60, 0},
{0, 60},
{80, 50}
})));
((MeshRenderer)(obj.getComponent(MeshRenderer.class))).color = CYAN;
obj.transform.position.Y = 100;
}
The expected result is to get this shape filled up.(it was created using the polygon mesh):
The actual result of using the FilledPolygon mesh:
You code seems to have several problems and I will not focus on that.
Your approach based on drawing the outline then filling the "inside" runs cannot work in the general case because the outlines join at the vertices and intersections, and the alternation outside-edge-inside-edge-outside is broken, in an unrecoverable way (you can't know which segment to fill by just looking at a row).
You'd better use a standard polygon filling algorithm. You will find many descriptions on the Web.
For a simple but somewhat inefficient solution, work as follows:
process all lines between the minimum and maximum ordinates; let Y be the current ordinate;
loop on the edges;
assign every vertex a positive or negative sign if y ≥ Y or y < Y (mind the asymmetry !);
whenever the endpoints of an edge have a different sign, compute the intersection between the edge and the line;
you will get an even number of intersections; sort them horizontally;
draw between every other point.
You can get a more efficient solution by keeping a trace of which edges cross the current line, in a so-called "active list". Check the algorithms known as "scanline fill".
Note that you imply that pixels[] has the same width*height size as filled[]. Based on the mangled output, I would say that they are just not the same.
Otherwise if you just want to fill a scanline (assuming everything is convex), that code is overcomplicated, simply look for the endpoints and loop between them:
public int[] draw() {
int[] pixels = new Polygon(verts).draw();
int[] filled = new int[width * height];
for (int y = 0; y < height; y++) {
int left = -1;
for (int x = 0; x < width; x++) {
if (pixels[x + y * width] == 0xffffffff) {
left = x;
break;
}
}
if (left >= 0) {
int right = left;
for (int x = width - 1; x > left; x--) {
if (pixels[x + y * width] == 0xffffffff) {
right = x;
break;
}
}
for (int x = left; x <= right; x++) {
filled[x + y * width] = 0xffffffff;
}
}
}
return filled;
}
However this kind of approach relies on having the entire polygon in the view, which may not always be the case in real life.

I am trying to add collision detection to this particle system I made

I am doing this in processing which is essentially java and I have never attempted anything like this before. Can't find any examples of collision detection using arrays to map the pixels.
I am not really trying to make them realistic collisions. I was thinking it would have the same response as if it hit a wall which is just for it to change directions in whatever axis is appropriate for the wall it hit.
I have tried checking if the x and y position are the same but can't seem to make that work. I'd appreciate any input on this.
import java.util.Arrays;
int numOfParticles = 10;
float[] x = new float[numOfParticles]; //initial position of y only matters
float[] px = new float[numOfParticles];
float[] y = new float[numOfParticles];
float[] py = new float[numOfParticles];
int speed = 10;//inversly related to speed
float[] xIncrement = new float[numOfParticles]; //the ratio of increments determines the pattern
float[] yIncrement = new float[numOfParticles]; // it is the slope of the line
//float xIncrement = 10/speed; //the ratio of increments determines the pattern
//float yIncrement = 11/speed; // it is the slope of the line
color currentColor;
int alpha = 100;//range of 0-255
//radius of ball
int radius = 1;
//thickness of line behind ball
int thickness = 5;
int rateOfColor = 5; //this is inversely related to rate but also changes the range of colors
int maxColor = 255;
int minColor = 0;
void setup(){
size(500,500);
background(0);
colorMode(HSB);
strokeWeight(thickness);
frameRate(60);
//initialize particles
for(int i = 0;i<numOfParticles;i++){
xIncrement[i] = random(0,100)/speed; //the ratio of increments determines the pattern
yIncrement[i] = random(0,100)/speed; // it is the slope of the line
x[i] = random(0,width);
px[i] = x[i];
y[i] = random(0,height);
py[i] = y[i];
}
//you can either initialize all of them individually or do a random one
//x[0] = 0;
//px[0] = x[0];
//y[0] = 450;
//py[0] = y[0];
//x[1] = width;
//px[1] = x[1];
//y[1] = 450;
//py[1] = y[1];
}
void draw(){
background(0); //comment out for criss cross
for(int i = 0; i < numOfParticles; i++){
particle(i);
}
}
void particle(int particleNum){
currentColor = color(minColor + (x[particleNum]/rateOfColor)%maxColor,255,255,alpha);
stroke(currentColor);
fill(currentColor);
ellipse(x[particleNum],y[particleNum],radius,radius);
line(px[particleNum],py[particleNum],x[particleNum],y[particleNum]);
px[particleNum] = x[particleNum];
py[particleNum] = y[particleNum];
y[particleNum]+= yIncrement[particleNum];
x[particleNum]+= xIncrement[particleNum];
if(x[particleNum] > width + 1 || x[particleNum] < 0){
x[particleNum] -= 2*xIncrement[particleNum];
xIncrement[particleNum]*=-1;
}
if( y[particleNum] > height + 1 || y[particleNum] < 0){
y[particleNum] -= 2*yIncrement[particleNum];
yIncrement[particleNum]*=-1;
}
//if(Arrays.binarySearch(x,x[particleNum]) >= 0 && Arrays.binarySearch(y,y[particleNum]) >= 0){
// xIncrement[particleNum]*=-1;
// yIncrement[particleNum]*=-1;
// print("*\n");
// stop();
//}
print("x[0] = " + x[0] + "\n");
print("x[1] = " + x[1] + "\n");
print("y[0] = " + y[0] + "\n");
print("y[1] = " + y[1] + "\n");
}
Stack Overflow isn't really designed for general "how do I do this" type questions. It's for specific "I tried X, expected Y, but got Z instead" type questions. But I'll try to help in a general sense:
You need to break your problem down into smaller pieces and then take those pieces on one at a time. Don't worry about the whole particle system. Make it work for a single particle. Do some research on collision detection.
Then if you get stuck, you can post a more specific question along with a MCVE. Good luck.

projecting Tango 3D point to screen Google Project Tango

Ptoject Tango provides a point cloud, how can you get the position in pixels of a 3D point in the point cloud in meters?
I tried using the projection matrix but I get very small values (0.5,1.3 etc) instead of say 1234,324 (in pixels).
I include the code I have tried
//Get the current rotation matrix
Matrix4 projMatrix = mRenderer.getCurrentCamera().getProjectionMatrix();
//Get all the points in the pointcloud and store them as 3D points
FloatBuffer pointsBuffer = mPointCloudManager.updateAndGetLatestPointCloudRenderBuffer().floatBuffer;
Vector3[] points3D = new Vector3[pointsBuffer.capacity()/3];
int j =0;
for (int i = 0; i < pointsBuffer.capacity() - 3; i = i + 3) {
points3D[j]= new Vector3(
pointsBuffer.get(i),
pointsBuffer.get(i+1),
pointsBuffer.get(i+2));
//Log.v("Points3d", "J: "+ j + " X: " +points3D[j].x + "\tY: "+ points3D[j].y +"\tZ: "+ points3D[j].z );
j++;
}
//Get the projection of the points in the screen.
Vector3[] points2D = new Vector3[points3D.length];
for(int i =0; i < points3D.length-1;i++)
{
Log.v("Points", "X: " +points3D[i].x + "\tY: "+ points3D[i].y +"\tZ: "+ points3D[i].z );
points2D[i] = points3D[i].multiply(projMatrix);
Log.v("Points", "pX: " +points2D[i].x + "\tpY: "+ points2D[i].y +"\tpZ: "+ points2D[i].z );
}
The example I'm using is the point cloud java which can be found here
https://github.com/googlesamples/tango-examples-java
UPDATE
TangoCameraIntrinsics ccIntrinsics = mTango.getCameraIntrinsics(TangoCameraIntrinsics.TANGO_CAMERA_COLOR);
double fx = ccIntrinsics.fx;
double fy = ccIntrinsics.fy;
double cx = ccIntrinsics.cx;
double cy = ccIntrinsics.cy;
double[][] projMatrix = new double[][] {
{fx, 0 , -cx},
{0, fy, -cy},
{0, 0, 1}
};
Then to compute the projected point I use
for(int i =0; i < points3D.length-1;i++)
{
double[][] point = new double[][] {
{points3D[i].x},
{points3D[i].y},
{points3D[i].z}
};
double [][] point2d = CustomMatrix.multiplyByMatrix(projMatrix, point);
points2D[i] = new Vector2(0,0);
if(point2d[2][0]!=0)
{
Log.v("temp point", "pX: " +point2d[0][0]/point2d[2][0]+" pY: " +point2d[1][0]/point2d[2][0] );
points2D[i] = new Vector2(point2d[0][0]/point2d[2][0],point2d[1][0]/point2d[2][0]);
}
}
But I think that the results are still not what is expected, I for instance get results like:
pX: -175.58042313027244 pY: -92.573740812066
Which to me looks not right.
UPDATE
Using color camera as suggested gives better results, but poitns are still negative
-1127.8086915171814 pY: -652.5887102192332
Would it be ok to just multiply them by -1?
You have to multiply 3D point with RGB camera's intrinsics matrix to obtain pixel coordinate. 3D points are in Depthcamera's frame. You get pixel coordinates by following method:
and
x and y are pixel coordinates.
And K is constructed with parameters using intrinsics function

Generate 2d world with vectors

I try to get started with a 2d map generator with vectors. Now I have some questions how should I go for it.
public float[] gen() {
float[] vec = new float[100];
float x = 0, y = 0;
float a = 20,
b = 10;
for (int i = 0; i < vec.length; i += 2) {
vec[i] = MathUtils.random(x, x + a);
vec[i+1] = MathUtils.random(y - b, y + b);
x = vec[i];
y = vec[i+1];
}
return vec;
}
Would this be a good way to get verctors from? var a, b could be changed for smooth land / hills.
I thought about a neverending map. But how could I only render the part of the player sees. I will work with box2d.
Generated world parts should be saved to a file. Should I save them as chunks like in Minecraft done? And what file fromat is reccoment (json)?
I just liked to get a little perpective to look forwart.
Answer for 2nd Q.
You have to have a Camera
if(x >=camera.project(new Vector3(camera.position.x - camera.viewportWidth - 25, 0, 0)).x) && x <= camera.project(new Vector3(camera.viewportWidth + camera.position.x + 25, 0, 0)).x)
and y the same or less laggy than this(every frame there is created new Vector3 object, so...)
Good luck!

Solving circle equations

I'm looking for some assistance with solving the below equations in Java
(a-x1)^2 + (b-y1)^2 = r1^2 + r^2
(a-x2)^2 + (b-y2)^2 = r2^2 + r^2
(a-x3)^2 + (b-y3)^2 = r3^2 + r^2
Values of x1, y1, r1, x2, y2, r2 & x3, y3, r3 are known.
I need to solve for a, b, r
How to go about doing this in Java? I checked the Commons Maths library but didn't find how I could achieve this. It helps with linear equations though.
I think you need linear equations for Gaussian elimination.
If a, b, and r are what you need to solve for, it's obvious that these are non-linear equations.
You'll need a non-linear solver, like Newton-Raphson.
You'll have to linearize your equations. Calculate the Jacobean for the differentials da, db, and dr.
You'll start with an initial guess
a = a(old)
b = b(old)
r = r(old)
use a linearized version of the equations to calculate an increment
2*(a(old)-x1)*da + 2*(b(old)-y1)*db = 2*r(old)*dr
2*(a(old)-x2)*da + 2*(b(old)-y2)*db = 2*r(old)*dr
2*(a(old)-x3)*da + 2*(b(old)-y3)*db = 2*r(old)*dr
update your guess
a(new) = a(old) + da
b(new) = b(old) + db
r(new) = r(old) + dr
and repeat until it converges (if it converges).
You should never solve linear equations using Gaussian elimination: it suffers from a number of problems. A better idea is to do LU decomposition and forward-back substitution.
If my linearized equations are correct, they take the form A(dx) = 0. What should the boundary condition be?
(a, b) are the coordinates for the center of the circle; r is the radius.
Do you really have three points (x1, y1), (x2, y2), and (x3, y3)? Or do you have lots more points? If it's the latter, you'll need a least squares fit.
hope this method can give you some ideas:
public int[] getCoordinates(float XR_1, float YR_1, float XR_2, float YR_2,
float XR_3, float YR_3, int R1, int R2, int R3) {
//define the positions
int XU_1 = 0, YU_1 = 0, XU_2 = 0, YU_2 = 0, XU, YU;
//define variables and arrays that needed
float D0[][] = new float[17][50];
float D1[][] = new float[17][50];
float f[][] = new float[17][50];
float fmin_1 = 0;
float fmin_2 = 0;
//define columns and rows
int i, j;
//Y goes from 0 to 49
for(j=0; j<=49; j++){
//X goes from 0 to 16
for(i=0; i<=16; i++){
D0[i][j] = (float) (Math.pow((i-XR_1),2) + Math.pow((j-YR_1),2) - Math.pow(R1,2));
D1[i][j] = (float) (Math.pow((i-XR_2),2) + Math.pow((j-YR_2),2) - Math.pow(R2,2));
f[i][j] = (float) Math.sqrt(Math.pow(D0[i][j], 2) + Math.pow(D1[i][j], 2));
//get two position where f[i][j] are the minimum
//initialise the minimum two positions
if(i==0 & j==0){
fmin_1 = f[i][j];
XU_1 = i;
YU_1 = j;
}
else if(j==0 & i==1){
if(f[i][j] < fmin_1){
fmin_2 = fmin_1;
fmin_1 = f[i][j];
XU_2 = XU_1;
XU_1 = i;
YU_2 = YU_1;
YU_1 = j;
}
else {
fmin_2 = f[i][j];
XU_2 = i;
YU_2 = j;
}
}
else{
if(f[i][j] < fmin_1){
fmin_2 = fmin_1;
fmin_1 = f[i][j];
XU_2 = XU_1;
XU_1 = i;
YU_2 = YU_1;
YU_1 = j;
}
else if(f[i][j] < fmin_2){
fmin_2 = f[i][j];
XU_2 = i;
YU_2 = j;
}
}
}
}
this method gives two closest points in the coordinate system, you can use the similar way to get the most ideal one.

Categories

Resources