I'm using the method of dividing the x and y coordinates by the z value, then rendering it just like you would a 2D game/thing to create 3D looking thing. The problem is when the z value is less then 0 it flips the quadrants for the coordinate and looks very weird. At the moment there is only movement if someone could help me fix the negative z value thing and show me how to rotate. I'm not using and matrices only vectors that take in x,y and z for the maths if that helps. I'm making this using Java with no extra libraries.
Thanks for the help.
I used the perspective matrix and multiplied it by my vector but it didn't work here is my code there might be something wrong with it. I just turned the vector into a 1 by 3 matrix and then did this.
public Matrix multiply(Matrix matrix)
{
Matrix result = new Matrix(getWidth(),getHeight());
for(int y = 0; y < getHeight()-1; y++)
{
for(int x = 0; x < getWidth()-1; x++)
{
float sum = 0.0f;
for(int e = 0; e < this.getWidth()-1; e++)
{
sum += this.matrix[e + y * getWidth()] * matrix.matrix[x + e * matrix.getWidth()];
}
result.matrix[x + y * getWidth()] = sum;
}
}
return result;
}
Just guessing here, but it sounds like you are trying to do a projection transform: You are modeling 3D objects (things with X, Y, and Z coordinates) and you want to project them onto a 2D window (i.e., the screen).
The meaning of Z in the naive projection transform is the distance between the point and a plane parallel to the screen, that passes through your eyeball. If you have points with -Z, those represent points that are behind your head.
Sounds like you need to translate the Z coordinates so that Z=0 is the plane of the screen, or a plane parallel to and behind the screen. (In other words, Add a constant to all of your Zs, so that none of them is negative.)
http://en.wikipedia.org/wiki/3D_projection
Related
An exercise in Shiffman's Nature of Code asks me to create Perlin Noise using Processing's noise() function. Here's my code I made to create Perlin Noise
float xSpace = 0; // Signifies "space" between noise() values on the x coordinate.
float ySpace = 0; // Signifies "space" between noise() values on the y coordinate.
void setup(){
size(500,500);
background(0);
loadPixels();
for(int x = 0; x < width; x++) {
for(int y = 0; y < height; y++) {
float bright = map(noise(xSpace,ySpace),0,1,0,255);
pixels[(y * width) + x] = color(bright);
//Each pixel in the pixels[] array is a color element.
ySpace = ySpace + 0.01;
}
xSpace = xSpace + 0.01 ;
}
updatePixels();
}
And when I run my code, it creates an image like this
I looked at the solution in the textbook. The textbook's solution and my solution are almost identical except the textbook reinitializes ySpace back to 0 with every iteration of the outer loop.
// Textbook's solution
for(int x = 0; x < width; x++) {
ySpace = 0;
for(int y = 0; y < height; y++) {
float bright = map(noise(xSpace,ySpace),0,1,0,255);
pixels[(y * width) + x] = color(bright);
ySpace = ySpace + 0.01;
}
xSpace = xSpace + 0.01 ;
}
However, when I run the textbook's code, the code creates a much smoother image like this
Why, when ySpace is reinitialized in the outer loop, does the image come out much smoother than the when its not? In other words, why is the textbook's code create a much smoother image than my code?
I noticed that the ySpace in my code will be significantly larger than the ySpace in the textbook's code once the for loop is complete. But I'm not sure if that's the reason why my code's image is not as smooth. From my understanding, noise(x,y) creates 2d Perlin Noise. When applied to a pixel, the pixel should be a similar color to the pixels around it, but it doesn't look like its happening in my code.
The noise() function essentially takes a 2D coordinate (or a 3D coordinate, or a single number, but in your case a 2D coordinate) and returns a random number based on that coordinate. Coordinates that are closer together will generate random numbers that are closer together.
With that in mind, think about what your code is doing and what the textbook is doing. The textbook is feeding in an x,y coordinate based on the position in the window, which makes sense since that's where the resulting random value is being drawn.
But your code keeps increasing the y coordinate no matter what. This might make sense if you only had a single column of pixels that just kept going down, but you're trying to loop over the pixels on the screen.
I am working on a sample project in Java, specifically Android, with OpenGL ES 2.0. I am looking to create a terrain for a player to move across. The player needs to move up and down the terrains hieght following the heightmap. The terrain is not flat. I am using Blender to create the terrain and heightmap. The terrain is being imported as an obj file.
The import and the drawing is working fine but i am having issues making the coordinates follow the heightmap. It doesn't seem to follow it 100%. The player moves up or down too soon every so often or he drops below the terrain.
What I Have So Far:
1)What I am doing is importing the OBJ file into project. Reading the farthest point from terrain object and using this as the object length ( this value * 2 ). This tells me how many vertices are in the object along one side.
2)I then get the difference in the players position to terrain origin in world coordinates. I take the x and z values and divide each by the OBJ object length*2 to give the region of the terrain the object is in. This will give me the percentage of where the x and z position the player is in reference to the terrain.
3) I open the heightmap and multiply the percentages above to the image of the heightmap to get the x and y position on the heightmap to read the height from.
Below is what I am working with.
public float getHeightOfTerrain(float worldX, float worldZ){
// worldX and worldZ are the players position
// Currentmatrix is the matrix used for positioning the terrain
float terrainX = worldX - CurrentMatrix[12] + objLength;
float terrainZ = worldZ - CurrentMatrix[14] + objLength;
return getHeight(terrainX, terrainZ);
}
................
float MAX_HEIGHT = 20;
float MAX_PIXEL_COLOR = 256*256*256;
................
public float getHeight(float x, float z){
float posX = x / (objLength*2);
float posZ = z / (objLength*2);
if(posX < 0 || posX > 1 || posZ < 0 || posZ > 1){ // if over 1 which is 100% of terrain then return
return 0;
}
float imgX = posX * bitmapOfMap.getWidth();
float imgZ = bitmapOfMap.getHeight() - (posZ * bitmapOfMap.getHeight()); // subtract BC bitmap y reads in reverse
if(imgX < 0 || imgX >= bitmapOfMap.getWidth() || imgZ < 0 || imgZ >= bitmapOfMap.getHeight()){ // if over then return
return 0;
}
float height = bitmapOfMap.getPixel((int)imgX, (int)imgZ);
height += MAX_PIXEL_COLOR/2f;
height /= MAX_PIXEL_COLOR/2f;
height *= MAX_HEIGHT;
return height;
}
The smaller the terrain height, the better this setup works. The bigger change in terrain height, the worse this system works. I have tried different obj and heightmaps, recreating over and over thinking this may be the issue but the same problems exist.
Am I doing this completely wrong? Any help would be appreciated. Anyone know a better way? I really want to keep my OBJ file import and read from that for customization.
I went ahead and created the terrain just by the heightmap, no OBJ import. Then applied my code above and had the same exact issue. So I dug a bit deeper in what is exactly going on step by step. It all started from the way I was keep track of the terrains location on x, y, and z then subtract that from the players position. I was tracking the players position from a seperate array of x, y, z and then terrains position from the matrix[12], matrix[13], matrix[14] as x, y, z.
This was the issue. I can't use the floats in the matrices as positioning relative values. I had to keep a seperate x, y, z for the terrain as well.
So from.....
float terrainX = worldX - CurrentMatrix[12] + objLength;
float terrainZ = worldZ - CurrentMatrix[14] + objLength;
to
float x, y, z = 0;
.....
float terrainX = z;
float terrainZ = x;
Now the model works perfect! .... moves up and down the terrain appropriately following the heightmap. I hope this helps anyone that may be having the same issue.
The applet used is like the first quadrant of a Cartisian Plane with the domain and range (0, 200). My assignment is to draw a house and a sun in this applet.
I am trying to draw the circle for the sun. I really have no idea where to start. We are learning about for loops and nested loops so it probably pertains to that. We haven't got to arrays and general functions like draw.circle do not exist for this applet. If it helps, here is how I drew my roof for the house (two right triangles): Notice it is drawn pixel by pixel. I suspect my teacher wants the same kind of thing for the circle.
//roof
//left side
double starty = 100;
for(double x = 16; x <= 63; x++){
for(int y = 100; y <= starty; y++){
img.set(x, y, JRaster.purple);
}
starty += 1;
}
//right side
double startx = 110;
for(int y = 100; y <= 147; y++){
for(double x = 63; x <= startx; x++){
img.set(x , y, JRaster.purple);
}
startx -= 1;
}
Here's how I would draw the north-east quarter of a circle, pixel by pixel. You can just repeat this with slight variations for the other three quarters. No trigonometry required!
Start by drawing the eastern most point of the circle. Then you'll draw more pixels, moving northwards and westwards, until you get to the northern most point of the circle.
Calculate the distance of the point you've just drawn from the centre. If it's more than the radius, then your next pixel will be one to the left, otherwise, your next pixel will be the one above.
Repeat the previous step till you get to the northern most point.
Post a comment if you get stuck, with converting this to Java, or with adjusting it for the other three quarters of the circle.
I won't give you code, but you should remember how a circle is made. Going from theta=0 to theta=2*pi, the circle is traced by x=cos x, y=sin x.
So, using a for loop that increments a double(here called theta) by something like 0.01 until 2*pi(2*Math.PI or roughly 6.28) plot off Math.cos(theta), Math.sin(theta).
I've got a problem: I have two coordinates (start and end point positions) and a polygon. I want to check whether this route is (1) from outside to inside of the polygon, (2) from inside to outside, (3) only inside, or (4) only outside.
I would really appreciate any help.
You are lucky! Java contains a Polygon class which has a method contains(double x, double y). Use it!
See this page:
http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
This function is taken from there.
It is based on the observation that a test point is within a polygon if when projected on the y-axis it's x value is below odd number of polygon edges. Works for both convex and concave polygons.
int pnpoly(int nvert, float *vertx, float *verty, float testx, float testy)
{
int i, j, c = 0;
for (i = 0, j = nvert-1; i < nvert; j = i++) {
if ( ((verty[i]>testy) != (verty[j]>testy)) &&
(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
c = !c;
}
return c;
}
I'm making an ellipsoid out of voxels, and I have an implementation, but it's not working correctly, for the past few hours I've been trying things with no success.
Here's how it works:
It draws 2D ellipses down the Z axis using the Bresenham circle algorithm
It calculates the coordinates of a circle going forward and one going side to side
It uses those coordinates as radii for X and Y
Here's what works:
Spheres are perfect
Ellipsoids are perfect when
z > x and z > y
x == y
Here's what doesn't:
Ellipsoids when x != y
Example when y > x http://postimage.org/image/gslvykrgd/
The same thing happens when x > y only flipped
I'm guessing its because I'm drawing the slices from center to front every time, but I don't know. Below is my implementation, it's a mess. I quickly cleaned it up a bit so it's understandable to some degree. Also I'm saving optimisations for later, I just want it working now.
I won't show my implementation of the circle algorithm itself, because I KNOW that it works and it would just make this question longer. So I'll explain the two functions for it instead.
private List<Integer> getSlice(int rx, int ry) gets the raw result from a run of the Bresenham circle algorithm, no symmetry needed. It returns the result as a list of the x, y results in that order.
public void generateEllipse(int z, int cx, int cy, int cz, int rx, int ry) generates an ellipse with the given information and plots down the coordinates using symmetry, these will be rendered on the screen.
ArrayList<Integer> s = getSlice(rz, rx);
ArrayList<Integer> s2 = getSlice(rz, ry);
int cap = Math.max(s2.size(), s.size());
while (s.size() > 1)
{
int x = 0;
int z = 0;
int z2 = 0;
int y2 = 0;
int i = cap - 2;
if (s.size() > i)
{
z = s.get(i);
x = s.get(i + 1);
s.remove(i + 1);
s.remove(i);
}
if (s2.size() > i)
{
z2 = s2.get(i);
y2 = s2.get(i + 1);
s2.remove(i + 1);
s2.remove(i);
}
if (x != 0 && y2 != 0)
generateEllipse(z, cx, cy, cz, x, y2);
cap = Math.max(s2.size(), s.size());
I asked a similar question a week or two back (yeah I've been having problems for that long :() and got an answer, I implemented it and it worked, but I wasn't satisfied, I want to avoid floating point numbers all together. See 3D Ellipsoid out of discrete units.
With that I was having problems with rounding off the numbers and getting uneven slices, so spheres were impossible. Ironically, now spheres are the only thing possible (other than front to back ellipses).
EDIT:
I got x > y working by adding
else if (y2 < x && ry - y2 != 0)
generateEllipse(z, cx, cy, cz, x, ry - y2);
and || r - y2 == 0 to the first test at the bottom.
I'm not too sure why that worked, I'm figuring that out now. But I'm still having problems with y > x. Anyone?
EDIT2:
Now that I look at it, it's different than the y = x ellipsoid, back to the drawing board.
EDIT3:
Last night I was thinking about this and I think I've figured it out, this isn't an answer to my own question, but I guess pointing out what I'm seeing to be wrong. I'm testing for the first list and drawing coordinates decrementally from the size of the largest list.
That's badness because the two lists aren't guaranteed equal lengths, that's a failure on my part for trying to rush an algorithm.
In the picture, you can't see, but the little ellipse is actually a few blocks away from the big ellipse. This is caused when from ellipses not being drawn, which is caused by lists not having data. The actual little ellipse big ellipse is caused because the algorithm draws two octants, both of which are stored into the list from getSlice(...).
So how can I fix this problem? I haven't implemented anything yet and probably won't for a while (it's early) but this is what my brain cranked out. Again, this is not an answer to the question, just thoughts.
I iterate for while(!s.isEmpty()) and define two new values outside the loop: incX = s.size and incY = s1.size I test to see if their z values match, if not, then I correct it. I'm thinking I'll get the values, test the largest list and if they don't match then decrement the inc value of the smallest list by two and get the old values.
I test for !s.isEmpty() because the two lists will be empty at the same time. Also drawing ellipses, I'll use whichever one z value, because, again, they both should be equal.
If that's wrong, then I guess I have this document I found to go through: http://www.cs.sunysb.edu/vislab/wordpress/pdf/398.pdf.
Thank you for anyone who viewed this (even though I didn't get any replies :(), I'm setting this answer because the problem is solved, the code is as follows:
ArrayList<Integer> s = getSlice(rz, rx);
ArrayList<Integer> s2 = getSlice(rz, ry);
boolean yMax = Math.max(s2.size(), s.size()) == s2.size();
int decX = s.size() - 1;
int decY = s2.size() - 1;
boolean done = false;
while (!done)
{
int x = 0;
int z = 0;
int z2 = 0;
int y = 0;
y = s2.get(decY--);
z2 = s2.get(decY--);
x = s.get(decX--);
z = s.get(decX--);
if (z != z2)
{
if (yMax)
{
decX += 2;
x = s.get(decX);
s2.remove(decY + 2);
s2.remove(decY + 1);
}
else
{
decY += 2;
y = s2.get(decY);
s.remove(decX + 2);
s.remove(decX + 1);
}
z = z < z2 ? z : z2;
}
else
{
s.remove(decX + 2);
s.remove(decX + 1);
s2.remove(decY + 2);
s2.remove(decY + 1);
}
if (y != 0 && x != 0)
generateEllipse(z, cx, cy, cz, x, y);
done = yMax ? s2.isEmpty() : s.isEmpty();
}
All that needs to be done now is optimisation. I'm still going to read that paper, it covers other topics that are interesting and useful for my program :).
The issue was that I was not accounting for the different sizes of each list, if a curve is less steep than the other it will have more coordinates. Z will always be the same when rx == ry. This allowed me to draw spheres and forward to back ellipsoids.
When they are not the same the z will change because the curve will be faster / slower. When this happened while I was testing for the first list it would ignore those because iteration would stop before it got to them.
The big ellipse, little ellipse was caused because they were drawn backwards, so the outer octant was drawn first which happens to have less total values.
In the near future I will put up a much more detailed answer and a much more elegant implementation. I'm just putting up this answer to let any passersby know that the problem is resolved. I want no one to ever go through the frustration I did trying to figure this whole thing out! It's amazing how the most difficult problems are caused by the silliest things.