Why is this Perlin Noise image smoother than the other? - java

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.

Related

Speed up Simplex Noise

I want to make a Java program, in which moving sky is generated out of Simplex Noise, but I have performance issues (framerate is too low). I'm using https://github.com/KdotJPG/OpenSimplex2/blob/master/java/OpenSimplex2F.java noise class.
My function which generates the sky, generates it entirely again each frame:
private void generate() {
float y = offset;
for (int i = 0; i < frame.getHeight(); i++) {
float x = offset;
for (int j = 0; j < frame.getWidth(); j++) {
double a = noise.noise2(x, y) + 0.25f * noise.noise2(2 * x, 2 * y) + 0.125f * noise.noise2(4 * x, 4 * y);
a = a / (1 + 0.25 + 0.125);
a = (a + 1) / 2;
a *= 100;
Color color = Color.getHSBColor(220f / 360f, a / 100f, 1f);
background.setRGB(j, i, color.getRGB());
x += noiseResolution;
}
y += noiseResolution;
}
}
Where background is BufferedImage I'm drawing on and offset says how much noise is moved.
I have tried to save an array of pixels of background each frame and translate it by the number of pixels it should be moved, and then I generated only pixels that are new. Unfortunately, because it was rendered too fast then, the number of pixels it should be moved was e.g. 0.2, so I couldn't translate array indices by a fraction.
So I guess the only way is to somehow generate it in another way, but I totally have no idea how.
Thanks!
Not sure about Java, but in C++ with DirectX, OpenGL or any low level interface like that, this should be easily done on the GPU in either HLSL (DirectX), or GLSL (OpenGL). I implemented 5D Simplex noise and even zoomed in so it fills my large screen, and on my 9 year old computer with my old ho-hum graphics card it still does a couple hundred frames per second. Here's what it looks like.
https://www.youtube.com/watch?v=oRO1IGcWIwg
If you can run a fragment shader from Java, I would think that would be the way to go. I think there is some OpenGL interface in Java so you might want to look int that.

Rotate image 90 degrees explanation

So I managed to get an image to rotate 90 degrees by using my code for 180 and messing about basically but Im still very confused on what the code actually does and how it does it. I understand the rotate 180 but not the rotate 90 with the code below. Can any explain this to me?
OFImage image1 = new OFImage(image);
for (int x = 0; x < image.getWidth(); ++x) {
for (int y = 0; y < image.getHeight(); ++y) {
image.setPixel(y, x, image1.getPixel(image.getWidth() - x - 1, y));
I have commented your code
OFImage image1 = new OFImage(image); // create a copy of `image`
for (int x = 0; x < image.getWidth(); ++x) { // loop through each column of pixels in original presumably from left to right
for (int y = 0; y < image.getHeight(); ++y) { // loop through each cell of the column presumably from top to bottom
image.setPixel(y, x, image1.getPixel(image.getWidth() - x - 1, y)); // here you have swapped the x and y coordinates and you are putting in the pixel from the copy that is at width - x - 1, y
So when x = 0 (column) and y = 0 (row), you are putting in a copy of the pixel from (W= image.width - 1, y) (last pixel in first row) into (0,0) so (W,0) => (0,0)
Then when x = 0 and y = 1 it is (W, 1) => (1, 0), then (W, 2) => (2, 0)
At the start of your loops, you are reading from the rightmost column, and writing to the topmost row.
Not sure how to describe the process in detail to be honest, but it's just using maths (obviously), to swap each pixel individually with the appropriate alternative pixel, to give the effect of a 90 degree rotation.
To help me understand it, I drew 3x3 and 4x4 grids, and labelled each cell, simulating pixels. And simply used the method "setPixel" with its parameters as an equation, and passed each pixel/co-ordinate through it to work out the result. I'd suggest doing the same, since it's probably the best method to understanding how the method works properly.

Incomplete Light Circle

I've made a lighting engine which allows for shadows. It works on a grid system where each pixel has a light value stored as an integer in an array. Here is a demonstration of what it looks like:
The shadow and the actual pixel coloring works fine. The only problem is the unlit pixels further out in the circle, which for some reason makes a very interesting pattern(you may need to zoom into the image to see it). Here is the code which draws the light.
public void implementLighting(){
lightLevels = new int[Game.WIDTH*Game.HEIGHT];
//Resets the light level map to replace it with the new lighting
for(LightSource lightSource : lights) {
//Iterates through all light sources in the world
double circumference = (Math.PI * lightSource.getRadius() * 2),
segmentToDegrees = 360 / circumference, distanceToLighting = lightSource.getLightLevel() / lightSource.getRadius();
//Degrades in brightness further out
for (double i = 0; i < circumference; i++) {
//Draws a ray to every outer pixel of the light source's reach
double radians = Math.toRadians(i*segmentToDegrees),
sine = Math.sin(radians),
cosine = Math.cos(radians),
x = lightSource.getVector().getScrX() + cosine,
y = lightSource.getVector().getScrY() + sine,
nextLit = 0;
for (double j = 0; j < lightSource.getRadius(); j++) {
int lighting = (int)(distanceToLighting * (lightSource.getRadius() - j));
double pixelHeight = super.getPixelHeight((int) x, (int)y);
if((int)j==(int)nextLit) addLighting((int)x, (int)y, lighting);
//If light is projected to have hit the pixel
if(pixelHeight > 0) {
double slope = (lightSource.getEmittingHeight() - pixelHeight) / (0 - j);
nextLit = (-lightSource.getRadius()) / slope;
/*If something is blocking it
* Using heightmap and emitting height, project where next lit pixel will be
*/
}
else nextLit++;
//Advances the light by one pixel if nothing is blocking it
x += cosine;
y += sine;
}
}
}
lights = new ArrayList<>();
}
The algorithm i'm using should account for every pixel within the radius of the light source not blocked by an object, so i'm not sure why some of the outer pixels are missing.
Thanks.
EDIT: What I found is, the unlit pixels within the radius of the light source are actually just dimmer than the other ones. This is a consequence of the addLighting method not simply changing the lighting of a pixel, but adding it to the value that's already there. This means that the "unlit" are the ones only being added to once.
To test this hypothesis, I made a program that draws a circle in the same way it is done to generate lighting. Here is the code that draws the circle:
BufferedImage image = new BufferedImage(WIDTH, HEIGHT,
BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, WIDTH, HEIGHT);
double radius = 100,
x = (WIDTH-radius)/2,
y = (HEIGHT-radius)/2,
circumference = Math.PI*2*radius,
segmentToRadians = (360*Math.PI)/(circumference*180);
for(double i = 0; i < circumference; i++){
double radians = segmentToRadians*i,
cosine = Math.cos(radians),
sine = Math.sin(radians),
xPos = x + cosine,
yPos = y + sine;
for (int j = 0; j < radius; j++) {
if(xPos >= 0 && xPos < WIDTH && yPos >= 0 && yPos < HEIGHT) {
int rgb = image.getRGB((int) Math.round(xPos), (int) Math.round(yPos));
if (rgb == Color.white.getRGB()) image.setRGB((int) Math.round(xPos), (int) Math.round(yPos), 0);
else image.setRGB((int) Math.round(xPos), (int) Math.round(yPos), Color.red.getRGB());
}
xPos += cosine;
yPos += sine;
}
}
Here is the result:
The white pixels are pixels not colored
The black pixels are pixels colored once
The red pixels are pixels colored 2 or more times
So its actually even worse than I originally proposed. It's a combination of unlit pixels, and pixels lit multiple times.
You should iterate over real image pixels, not polar grid points.
So correct pixel-walking code might look as
for(int x = 0; x < WIDTH; ++x) {
for(int y = 0; y < HEIGHT; ++y) {
double distance = Math.hypot(x - xCenter, y - yCenter);
if(distance <= radius) {
image.setRGB(x, y, YOUR_CODE_HERE);
}
}
}
Of course this snippet can be optimized choosing good filling polygon instead of rectangle.
This can be solved by anti-aliasing.
Because you push float-coordinate information and compress it , some lossy sampling occur.
double x,y ------(snap)---> lightLevels[int ?][int ?]
To totally solve that problem, you have to draw transparent pixel (i.e. those that less lit) around that line with a correct light intensity. It is quite hard to calculate though. (see https://en.wikipedia.org/wiki/Spatial_anti-aliasing)
Workaround
An easier (but dirty) approach is to draw another transparent thicker line over the line you draw, and tune the intensity as needed.
Or just make your line thicker i.e. using bigger blurry point but less lit to compensate.
It should make the glitch less obvious.
(see algorithm at how do I create a line of arbitrary thickness using Bresenham?)
An even better approach is to change your drawing approach.
Drawing each line manually is very expensive.
You may draw a circle using 2D sprite.
However, it is not applicable if you really want the ray-cast like in this image : http://www.iforce2d.net/image/explosions-raycast1.png
Split graphic - gameplay
For best performance and appearance, you may prefer GPU to render instead, but use more rough algorithm to do ray-cast for the gameplay.
Nonetheless, it is a very complex topic. (e.g. http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-16-shadow-mapping/ )
Reference
Here are more information:
http://what-when-how.com/opengl-programming-guide/antialiasing-blending-antialiasing-fog-and-polygon-offset-opengl-programming/ (opengl-antialias with image)
DirectX11 Non-Solid wireframe (a related question about directx11 with image)

How to fully make 2d to 3d?

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

How can a draw a circle in java pixel by pixel using a graphical app?

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).

Categories

Resources