Collision Bug in 2D Platformer Game - java

I am currently developing a 2D Mario-Like Platformer Game. I ran into a collision problem i've been trying to solve for a while now, but nothing seems to work :/
Basicly, i have a CenterLayer, which stores at which Position what kind of Tile is.
Then i have some Sprites and a Player, which should collide with these Tiles.
Because these Tiles can be triangular shaped (or any other kind of convex polygon), i decided to handle collision via SAT (Seperating Axis Theorem). This works great, but when it comes to collision with the floor where many tiles are adjacent to eachother and the sprite is moving left, it pickes the wrong edge and moves the Sprite to the right, but expected result would be moving it up. This causes the sprite to get stuck.
This is the code im currently using:
package level;
import java.awt.Polygon;
import tiles.Tile;
import sprites.*;
public class Collider {
/** Collide Sprite (or Player) with CenterLayer **/
public static void collide(Sprite s, CenterLayer c){
CollisionPolygon ps = s.getPolygon();
//Get blocks to collide with
int startXTile = (int) (s.getX() / CenterLayer.TILE_WIDTH) - 1;
int endXTile = (int) Math.ceil((s.getX() + s.getWidth()) / CenterLayer.TILE_WIDTH) + 1;
int startYTile = (int) (s.getY() / CenterLayer.TILE_HEIGHT) - 1;
int endYTile = (int) Math.ceil((s.getY() + s.getHeight()) / CenterLayer.TILE_HEIGHT) +1;
//limit to level boundaries
if(startXTile < 0) startXTile = 0;
if(endXTile > c.LEVEL_WIDTH) endXTile = c.LEVEL_WIDTH;
if(startYTile < 0) startYTile = 0;
if(endYTile > c.LEVEL_HEIGHT) endYTile = c.LEVEL_HEIGHT;
int sizeX = endXTile - startXTile;
int sizeY = endYTile - startYTile;
//loop through tiles and collide
for(int xc = 0; xc < sizeX; xc++)
for(int yc = 0; yc < sizeY; yc++){
int xblock = xc + startXTile;
int yblock = yc + startYTile;
Tile t = c.getTile(xblock, yblock);
if(t!=null){ //if tile == null --> tile is air
CollisionPolygon pt = t.getPolygon(xblock, yblock);
double[] projection = PolygonCollision(ps, pt);
//if collision has happened
if(projection[0] != 0 || projection[1] != 0){
//collide
s.moveBy(projection[0], projection[1]);
//update sprites polygon to new position
ps = s.getPolygon();
}
}
}
}
public static double dotProduct(double x, double y, double dx, double dy) {
return x * dx + y * dy;
}
// Calculate the projection of a polygon on an axis (ax, ay)
// and returns it as a [min, max] interval
public static double[] ProjectPolygon(double ax, double ay, Polygon p) {
double dotProduct = dotProduct(ax, ay, p.xpoints[0], p.ypoints[0]);
double min = dotProduct;
double max = dotProduct;
for (int i = 0; i < p.npoints; i++) {
dotProduct = dotProduct(p.xpoints[i], p.ypoints[i], ax, ay);
if (dotProduct < min) {
min = dotProduct;
} else if (dotProduct > max) {
max = dotProduct;
}
}
return new double[] { min, max };
}
// Calculate the distance between [minA, maxA](p1[0], p1[1]) and [minB, maxB](p2[0], p2[1])
// The distance will be negative if the intervals overlap
public static double IntervalDistance(double[] p1, double[] p2) {
if (p1[0] < p2[0]) {
return p2[0] - p1[1];
} else {
return p1[0] - p2[1];
}
}
public static double[] PolygonCollision(CollisionPolygon p1, CollisionPolygon p2){
boolean intersection = true;
int edgeCount1 = p1.npoints;
int edgeCount2 = p2.npoints;
double projectionX = 0;
double projectionY = 0;
double projectionDist = Double.POSITIVE_INFINITY;
//loop through all the edges
for(int edgeIndex = 0; edgeIndex < edgeCount1 + edgeCount2; edgeIndex++){
//find edges
double[] axis;
if(edgeIndex < edgeCount1){
axis = p1.getAxis(edgeIndex);
} else {
axis = p2.getAxis(edgeIndex - edgeCount1);
}
double axisX = axis[0];
double axisY = axis[1];
//System.out.println("edge: " +axisX + ", "+ axisY);
//find the projection of both polygons on current axis
final double[] proj1 = ProjectPolygon(axisX, axisY, p1);
final double[] proj2 = ProjectPolygon(axisX, axisY, p2);
//Check if polygons are intersecting, if not end loop
double id = IntervalDistance(proj1, proj2);
if(id > 0){
intersection = false;
break;
}
//Check if projection would be shorter than previous one
id = Math.abs(id);
if(id < projectionDist){
projectionDist = id;
projectionX = axisX;
projectionY = axisY;
//check if hit from "false" side
double d1x = p1.getCenterX();
double d1y = p1.getCenterY();
double d2x = p2.getCenterX();
double d2y = p2.getCenterY();
double midx = d1x - d2x;
double midy = d1y - d2y;
double dot = dotProduct(midx, midy, projectionX, projectionY);
if(dot < 0){
projectionX = -projectionX;
projectionY = -projectionY;
}
}
}
double[] result = new double[]{0, 0};
if(intersection){
//System.out.println("colliison: " + projectionX +"; "+ projectionY + ", " + projectionDist);
result[0] = projectionX * projectionDist;
result[1] = projectionY * projectionDist;
}
return result;
}
}
Any Ideas?
Tom

I had this bug too , it happens when there are parallel edges on a poly.The easy way to fix this is to project the difference between the polygon centers on the found axis.If the result is negative you would just multiply the axis by -1.
Vector aMidPoint = new Vector();
Vector bMidPoint = new Vector();
for ( Vector v : aVerts) {
aMidPoint = aMidPoint.add(v);
}
for ( Vector v : bVerts) {
bMidPoint = bMidPoint.add(v);
}
aMidPoint = aMidPoint.scalarDivision(aVerts.size());
bMidPoint = bMidPoint.scalarDivision(bVerts.size());
Vector ba = aMidPoint.subtract(bMidPoint);
if (ba.dotProduct(minOverlapVector) < 0) {
minOverlapVector = minOverlapVector.scalarMultiplication(-1);
}

Related

Get lines of Sudoku grid with open cv

I am developing an app that will solve Sudoku from camera. I am using OpenCV library. I spent some time researching and I decided to try with this project, since I am totally new in image recognition .
I have a problem with detecting grid lines. With code I have, app detects only one horizontal or one vertical line(depends on threshold, 51 and below returns one vertical and 52 and above returns one horizontal). Here is my function for finding corners, where I am detecting lines:
private List<Point> findCorners(Mat mat) {
Mat lines = new Mat();
List<double[]> horizontalLines = new ArrayList<double[]>();
List<double[]> verticalLines = new ArrayList<double[]>();
//Imgproc.GaussianBlur( mat, lines, new Size(5, 5), 2, 2 );
int threshold = 150;
int minLineSize = 0;
int lineGap = 10;
//Imgproc.Canny(mat, lines, 70, 100);
Imgproc.HoughLinesP(mat, lines, 1, Math.PI / 180, threshold);
for (int i = 0; i < lines.cols(); i++) {
double[] line = lines.get(0, i);
double x1 = line[0];
double y1 = line[1];
double x2 = line[2];
double y2 = line[3];
if (Math.abs(y2 - y1) < Math.abs(x2 - x1)) {
horizontalLines.add(line);
} else if (Math.abs(x2 - x1) < Math.abs(y2 - y1)) {
verticalLines.add(line);
}
}
String lineInfo = String.format(
"horizontal: %d, vertical: %d, total: %d",
horizontalLines.size(), verticalLines.size(), lines.cols());
Log.d(TAG_HOUGHLINES, lineInfo);
// find the lines furthest from centre which will be the bounds for the
// grid
double[] topLine = horizontalLines.get(0);
double[] bottomLine = horizontalLines.get(0);
double[] leftLine = verticalLines.get(0);
double[] rightLine = verticalLines.get(0);
double xMin = 1000;
double xMax = 0;
double yMin = 1000;
double yMax = 0;
for (int i = 0; i < horizontalLines.size(); i++) {
if (horizontalLines.get(i)[1] < yMin
|| horizontalLines.get(i)[3] < yMin) {
topLine = horizontalLines.get(i);
yMin = horizontalLines.get(i)[1];
} else if (horizontalLines.get(i)[1] > yMax
|| horizontalLines.get(i)[3] > yMax) {
bottomLine = horizontalLines.get(i);
yMax = horizontalLines.get(i)[1];
}
}
for (int i = 0; i < verticalLines.size(); i++) {
if (verticalLines.get(i)[0] < xMin
|| verticalLines.get(i)[2] < xMin) {
leftLine = verticalLines.get(i);
xMin = verticalLines.get(i)[0];
} else if (verticalLines.get(i)[0] > xMax
|| verticalLines.get(i)[2] > xMax) {
rightLine = verticalLines.get(i);
xMax = verticalLines.get(i)[0];
}
}
// obtain four corners of sudoku grid
Point topLeft = ImgManipUtil.findCorner(topLine, leftLine);
Point topRight = ImgManipUtil.findCorner(topLine, rightLine);
Point bottomLeft = ImgManipUtil.findCorner(bottomLine, leftLine);
Point bottomRight = ImgManipUtil.findCorner(bottomLine, rightLine);
List<Point> corners = new ArrayList<Point>(4);
corners.add(topLeft);
corners.add(topRight);
corners.add(bottomLeft);
corners.add(bottomRight);
return corners;
}
Here is the input image

Perceptron doesn't find the right line even with a bias (Processing)

My perceptron doesn't find the right y-intercept even though I added a bias. The slope is correct. This is my second try coding a perceptron from scratch and I got the same error twice.
The perceptron evaluates if a point on a canvas is higher or lower than the interception line. The inputs are the x-coordinate, y-coordinate and 1 for the bias.
Perceptron class:
class Perceptron
{
float[] weights;
Perceptron(int layerSize)
{
weights = new float[layerSize];
for (int i = 0; i < layerSize; i++)
{
weights[i] = random(-1.0,1.0);
}
}
float Evaluate(float[] input)
{
float sum = 0;
for (int i = 0; i < weights.length; i++)
{
sum += weights[i] * input[i];
}
return sum;
}
float Learn(float[] input, int expected)
{
float guess = Evaluate(input);
float error = expected - guess;
for (int i = 0; i < weights.length; i++)
{
weights[i] += error * input[i] * 0.01;
}
return guess;
}
}
This is the testing code:
PVector[] points;
float m = 1; // y = mx+q (in canvas space)
float q = 0; //
Perceptron brain;
void setup()
{
size(600,600);
points = new PVector[100];
for (int i = 0; i < points.length; i++)
{
points[i] = new PVector(random(0,width),random(0,height));
}
brain = new Perceptron(3);
}
void draw()
{
background(255);
DrawGraph();
DrawPoints();
//noLoop();
}
void DrawPoints()
{
for (int i = 0; i < points.length; i++)
{
float[] input = new float[] {points[i].x / width, points[i].y / height, 1};
int expected = ((m * points[i].x + q) < points[i].y) ? 1 : 0; // is point above line
float output = brain.Learn(input, expected);
fill(sign(output) * 255);
stroke(expected*255,100,100);
strokeWeight(3);
ellipse(points[i].x, points[i].y, 20, 20);
}
}
int sign(float x)
{
return x >= 0 ? 1 : 0;
}
void DrawGraph()
{
float y1 = 0 * m + q;
float y2 = width * m + q;
stroke(255,100,100);
strokeWeight(3);
line(0,y1,width,y2);
}
I found the problem
float guess = Evaluate(input);
float error = expected - guess;
should be
float guess = sign(Evaluate(input));
float error = expected - guess;
The output was never exactly one ore zero even if the answer would be correct. Because of this even the correct points gave a small error that stopped the perceptron from finding the right answer. By calculating the sign of the answer first the error is 0 if the answer is correct.

Raytracing: Dark rings appear

I am getting strange rings of black on my spheres when I render with lighting. I just added lighting and I cannot figure out why the black rings are being created.
Here is my code for my tracer.
public class Tracer {
public Camera Cam;
public int Width, Height;
public BufferedImage Image;
public Color BackGroundColor;
public int StartX, StartY, EndX, EndY,RowCount,ColCount;
public ArrayList<GeometricObject> GeoObjects;
public ArrayList<LightObject> LightObjects;
public boolean Tracing;
public double AmbientLight;
public Tracer(Camera cam, int width, int height, BufferedImage image, Color backGroundColor, int startX, int startY, int endX, int endY, int rowCount, int colCount, ArrayList<GeometricObject> Geoobjects,ArrayList<LightObject> Lightobjects,double ambientLight) {
super();
Cam = cam;
Width = width;
Height = height;
Image = image;
BackGroundColor = backGroundColor;
StartX = startX;
StartY = startY;
EndX = endX;
EndY = endY;
RowCount = rowCount;
ColCount = colCount;
GeoObjects = Geoobjects;
LightObjects = Lightobjects;
if(ambientLight > 1){
AmbientLight = 1;
}else if(ambientLight < 0){
AmbientLight = 0;
}else{
AmbientLight = ambientLight;
}
}
public void TracePixelFast(int x, int y) {
Color color = new Color(BackGroundColor.r,BackGroundColor.g,BackGroundColor.b);
for(int o = 0;o < GeoObjects.size();o++){
GeometricObject GO = GeoObjects.get(o);
Ray r = new Ray(Cam.GetRayPos(Width, Height, x, y, 1, 1, RowCount, ColCount), Cam.GetRayDir(Width, Height, x, y, 1,1, RowCount, ColCount));
double hit = GO.hit(r);
if (hit != 0.0) {
color = Cal_Pixel(x,y);
Image.setRGB(x, y, color.toInt());
break;
}
}
}
public void TracePixelSmooth(int x, int y) {
Image.setRGB(x, y,Cal_Pixel(x,y).toInt());
}
public Color Cal_Pixel(int x,int y){
Color color = new Color(BackGroundColor);
Color colorh = new Color(BackGroundColor);
Color bgc = new Color(BackGroundColor);
int HIT = 0;
int MISS = 0;
for (int row = 0; row < RowCount; row++) {
for (int col = 0; col < ColCount; col++) {
double min = Double.MAX_VALUE;
for (int o = 0; o < GeoObjects.size(); o++) {
GeometricObject GO = GeoObjects.get(o);
Ray r = new Ray(Cam.GetRayPos(Width, Height, x, y, row, col, RowCount, ColCount),Cam.GetRayDir(Width, Height, x, y, row, col, RowCount, ColCount));
double hit = GO.hit(r);
if (hit != 0.0 && hit < min) {
min = hit;
colorh = ShadePixel(GO, r, hit);
HIT++;
} else {
double min2 = Double.MAX_VALUE;
for (int o2 = 0; o2 < GeoObjects.size(); o2++) {
if(o!=o2){
GeometricObject GO2 = GeoObjects.get(o2);
double hit2 = GO2.hit(r);
if (hit2 != 0.0 && hit2 < min2) {
min2 = hit2;
bgc = ShadePixel(GO2, r, hit2);
}
}
}
MISS++;
}
}
}
}
for(int h = 0;h < HIT;h++){
color.Add(colorh);
}
for(int m = 0;m < MISS;m++){
color.Add(bgc);
}
color.Divide(RowCount * ColCount);
return color;
}
public Color ShadePixel(GeometricObject GO,Ray ray,double t){
ArrayList<Color> PixelShade = new ArrayList<Color>();
Normal normal = GO.Cal_Normal(ray, t);
for(int l = 0;l < LightObjects.size();l++){
LightObject light = LightObjects.get(l);
Vector3D r_Dir = light.Pos.Sub(normal.Origin);
r_Dir.normalize();
Ray raytolight = new Ray(normal.Origin,r_Dir);
int WAS_HIT = 0;
for(int o = 0;o < GeoObjects.size();o++){
GeometricObject NGO = GeoObjects.get(o);
double hit = NGO.hit(raytolight);
if (hit != 0.0) {
WAS_HIT = 1;
}
}
if(WAS_HIT == 0){
double Dot = normal.Direction.Dot(r_Dir);
if(Dot < 0){
Dot = 0;
}
double Diffuse = 1 - AmbientLight;
Color color = new Color(GO.Color);
double Shade = AmbientLight + Diffuse*Dot;
color.Mul(Shade);
PixelShade.add(color);
}else{
Color color = new Color(GO.Color);
double Shade = AmbientLight;
color.Mul(Shade);
PixelShade.add(color);
}
}
Color Final = new Color();
for(int s = 0;s < PixelShade.size();s++){
Final.Add(PixelShade.get(s));
}
Final.Divide(PixelShade.size());
return Final;
}
public void TraceArea(boolean SmoothTracing) {
Tracing = true;
if(SmoothTracing){
for (int x = StartX; x < EndX; x++) {
for (int y = StartY; y < EndY; y++) {
TracePixelSmooth(x,y);
}
}
}else{
for (int x = StartX; x < EndX; x++) {
for (int y = StartY; y < EndY; y++) {
TracePixelFast(x,y);
}
}
}
}
}
And here is the code for the sphere.
public class Sphere extends GeometricObject{
public Vector3D Center;
public double Radius;
public Sphere(Vector3D Center,double Radius,Color Color){
this.Center = Center;
this.Radius = Radius;
this.Color = Color;
}
public double hit(Ray ray) {
double a = ray.Direction.Dot(ray.Direction);
double b = 2 * ray.Origin.Sub(Center).Dot(ray.Direction);
double c = ray.Origin.Sub(Center).Dot(ray.Origin.Sub(Center))-Radius*Radius;
double discreminant = b*b-4*a*c;
if(discreminant < 0.0f){
return 0.0;
}else{
double t = (-b - Math.sqrt(discreminant))/(2*a);
if(t > 10E-9){
return t;
}else{
return 0.0;
}
}
}
public Normal Cal_Normal(Ray ray,double t) {
Vector3D NPos = new Vector3D(ray.Origin.x + ray.Direction.x*t,ray.Origin.y + ray.Direction.y*t,ray.Origin.z + ray.Direction.z*t);
Vector3D NDir = NPos.Sub(Center).Div(Radius);
return new Normal(NPos,NDir);
}
}
I am sure the problem is in shadepixel() but I could be wrong.
I just found out that the more objects that I add the more rings there are:
1 object no rings.
2 objects 1 ring.
3 objects 2 rings.
If you need me to post more of my code.Just ask and I will.
When I get back from school I will post my color class and fix the color problem. I still do not understand why the more objects (spheres) I add, the more rings there are. Can anyone explain to me why this is happening?
Here is my Color code.
public class Color {
public float r,g,b;
public Color(){
r = 0.0f;
g = 0.0f;
b = 0.0f;
}
public Color(float fr,float fg,float fb){
r = fr;
g = fg;
b = fb;
}
public Color(Color color){
r = color.r;
g = color.g;
b = color.b;
}
public void Add(Color color){
r += color.r;
g += color.g;
b += color.b;
}
public void Divide(int scalar){
r /= scalar;
g /= scalar;
b /= scalar;
}
public void Mul(double mul){
r *= mul;
g *= mul;
b *= mul;
}
public int toInt(){
return (int) (r*255)<<16 | (int) (g*255)<<8 | (int) (b*255);
}
There are multiple issues with this code, but the direct reason for the rings is that color component values are overflowing 0-255 range. This in turn is caused by incorrect calculations in what I take to be an attempt at antialiasing in Cal_Pixel(), as well as by no control whatsoever of numeric range in ShadePixel().
Think about how you can visually debug this scene.
First are the normals correct? Display them as the colour to see.
Taking the range for each component [-1..1] to the range [0..255]:
r = 255*(n.x + 1)/2;
g = 255*(n.y + 1)/2;
b = 255*(n.z + 1)/2;
Once you think they look correct move on to the next stage and build it up stage by stage.
e.g. you might look at if your dot product is as expected (again [-1..1] because the vectors are supposedly normalised):
r = 255*(dot + 1)/2;
g = 255*(dot + 1)/2;
b = 255*(dot + 1)/2;

Java - Sorting a Set of Points Based on Both X and Y Coordinates

I have a list of point objects that need to be sorted by both X and Y coordinates, but when I pass them to a comparator object only one coordinate gets sorted (the first one called). Any ideas to why this might be happening?
static public List<Point> convertToThreeByThreeGrid(String points) {
String[] ptsArray;
List<Point> ptsList = new ArrayList<>();
String stripString = points.replace("[", "").replace("]", "").replace("(", "").replace(")", "").replace(" ", ",").trim();
ptsArray = stripString.split(",");
for(int i = 0; i < ptsArray.length; i += 2) {
int x = Integer.parseInt(ptsArray[i]);
int y = Integer.parseInt(ptsArray[i + 1]);
System.out.println("X: " + x);
System.out.println("Y: " + y);
ptsList.add(new Point(x, y));
}
Collections.sort(ptsList, new Comparator<Point>() {
public int compare(Point a, Point b) {
int result = Integer.compare((int) a.getX(), (int) b.getX());
if (result == 0 ) {
result = Integer.compare((int) a.getY(), (int) b.getY());
}
return result;
}
});
// subtract each coordinate by smallest x and y coordinate values
List<Point> convertedPtList = new ArrayList<>();
int smallestX = (int) ptsList.get(0).getX();
int smallestY = (int) ptsList.get(0).getY();
for (int i = 1; i < ptsList.size(); i++) {
int x = ((int) ptsList.get(i).getX() - smallestX);
int y = ((int) ptsList.get(i).getY() - smallestY);
convertedPtList.add(new Point(x, y));
}
return convertedPtList;
}
}
Output:
[java.awt.Point[x=10,y=26], java.awt.Point[x=10,y=26], java.awt.Point[x=10,y=28], java.awt.Point[x=12,y=26]]
[java.awt.Point[x=13,y=26], java.awt.Point[x=13,y=28], java.awt.Point[x=13,y=28], java.awt.Point[x=14,y=27], java.awt.Point[x=14,y=27], java.awt.Point[x=15,y=26], java.awt.Point[x=15,y=28], java.awt.Point[x=15,y=28]]
[java.awt.Point[x=16,y=26], java.awt.Point[x=16,y=28], java.awt.Point[x=16,y=28], java.awt.Point[x=18,y=26], java.awt.Point[x=18,y=26], java.awt.Point[x=18,y=28]]
for(int i = 0; i < ptsArray.length; i += 2) {
int x = Integer.parseInt(ptsArray[i]);
int y = Integer.parseInt(ptsArray[i+1]);
ptsList.add(new Point(x, y));
}
Collections.sort( ptsList, new Comparator<Point>() {
public int compare(Point x1, Point x2) {
int result = Double.compare(x1.getX(), x2.getX());
if ( result == 0 ) {
// both X are equal -> compare Y too
result = Double.compare(x1.getY(), x2.getY());
}
return result;
}
});
// ptsList is now sorted by both X and Y!
Edit:
To just find the lowest X and the lowest Y you can also go the 'classic' way without any (double-)sorting:
int minX = Integer.MAX_VALUE;
int minY = Integer.MAX_VALUE;
for ( Point p : ptsList ) {
final int x = (int)p.getX();
final int y = (int)p.getY();
if ( x < minX ) {
minX = x;
}
if ( y < minY ) {
minY = y;
}
}

Perlin noise generating visible "blocky" formations, Java

I've been trying to implement a perlin noise generator in java, based on this article. Homever, my generator produces noise that is not continuous but instead "blocky", forming visible lines between every even numbered -coordinate. Below is my current code:
private static final Point[] grads = {
new Point(1, 0), new Point(-1, 0), new Point(0, 1), new Point(0, -1),
new Point(1, 1), new Point(1, -1), new Point(-1, 1), new Point(-1, -1)
};
private int permutations[] = new int[512];
private int frequency;
private int seed;
private double[][] heightMap;
private double amplitude;
public PerlinNoise(int frequency, int seed, double[][] heightMap, double amplitude) {
this.frequency = frequency;
this.seed = seed; //Seed for randomizing the permutation table
this.heightMap = heightMap; //The Heightmap where the finalt result will be stored
this.amplitude = amplitude;
}
private void seedPermutationTables() {
LinkedList<PermutationValue> l = new LinkedList<PermutationValue>();
Random rand = new Random(this.seed);
for (int i = 0; i < 256; i++) {
l.add(new PermutationValue(i, rand));
}
Collections.sort(l);
for (int i = 0; i < 512; i++) {
permutations[i] = l.get(i & 255).getValue();
}
}
public void generateNoise() {
this.seedPermutationTables();
int sWidth = this.heightMap.length / frequency;
int sHeight = this.heightMap[0].length / frequency;
for (int i = 0; i < this.heightMap.length; i++) {
for (int j = 0; j < this.heightMap[i].length; j++) {
double x = (double)i / sWidth;
double y = (double)j / sHeight;
this.heightMap[i][j] = this.noise(x, y);
}
}
}
private double noise(double x, double y) {
int xi = (int)x & 255;
int yi = (int)y & 255;
double xf = x - (int)x;
double yf = y - (int)y;
double u = this.fade(xf);
double v = this.fade(yf);
int aa = permutations[permutations[xi] + yi];
int ab = permutations[permutations[xi] + yi + 1];
int ba = permutations[permutations[xi + 1] + yi];
int bb = permutations[permutations[xi + 1] + yi + 1];
double x1 = this.lerp(this.grad(aa, xf, yf), this.grad(ab, xf - 1, yf), u);
double x2 = this.lerp(this.grad(ba, xf, yf - 1), this.grad(bb, xf - 1, yf - 1), u);
double noise = this.lerp(x1, x2, v);
return (1D + noise) / 2 * this.amplitude; //The noise returns values between -1 and 1
//So we change the range to 0-amplitude
}
private double grad(int hash, double x, double y) {
hash = hash & 7;
Point p = grads[hash];
return p.x * x + p.y * y;
}
private double lerp(double a, double b, double x) {
return a + x * (b - a);
}
private double fade(double x) {
return x * x * x * (x * (x * 6 - 15) + 10);
}
private class PermutationValue implements Comparable<PermutationValue> {
private int value;
private double sortValue;
public PermutationValue(int value, Random rand) {
this.setValue(value);
this.sortValue = rand.nextDouble();
}
#Override
public int compareTo(PermutationValue pv) {
if (pv.sortValue > this.sortValue) {
return -1;
}
return 1;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
The heightmap array simply stores the height value for every pixel. Any suggestions or ideas what might be causing these formations?
hash tables can be replaced with 1-2 multiplications as in rndng fct:
blocky can come from lack of cubic interpolation or digital noise from the hash table.
in your case it sounds like it's not lerping between two values of the hash table. lerp just takes any 2 values and smooths between them. so if that's not running ok, it's blocky.
function rndng ( n: float ): float //total noise pseudo
{//random proportion -1, 1
var e = ( n *321.9)%1;
return (e*e*111.0)%2-1;
}
function lerps(o:float, v:float, alpha:float):float
{
o += ( v - o ) * alpha;
return o;
}
function lnz ( vtx: Vector3 ): float//3d noise
{
vtx= Vector3 ( Mathf.Abs(vtx.x) , Mathf.Abs(vtx.y) , Mathf.Abs(vtx.z) ) ;
var I = Vector3 (Mathf.Floor(vtx.x),Mathf.Floor(vtx.y),Mathf.Floor(vtx.z));
var D = Vector3(vtx.x%1,vtx.y%1,vtx.z%1);
D = Vector3(D.x*D.x*(3.0-2.0*D.x),D.y*D.y*(3.0-2.0*D.y),D.z*D.z*(3.0-2.0*D.z));
var W = I.x + I.y*71.0 + 125.0*I.z;
return lerps(
lerps( lerps(rndng(W+0.0),rndng(W+1.0),D.x) , lerps(rndng(W+71.0),rndng(W+72.0),D.x) , D.y)
,
lerps( lerps(rndng(W+125.0),rndng(W+126.0),D.x) , lerps(rndng(W+153.0),rndng(W+154.0),D.x) , D.y)
,
D.z
);
}
function lnzo ( vtx: Vector3 ): float
{
var total = 0.0;
for (var i:int = 1; i < 5; i ++)
{
total+= lnz2(Vector3 (vtx.x*(i*i),0.0,vtx.z*(i*i)))/(i*i);
}
return total*5;
}
function lnzh ( vtx: Vector3 ): float//3 axis 3d noise
{
vtx= Vector3 ( Mathf.Abs(vtx.z) , Mathf.Abs(vtx.z*.5-vtx.x*.866) , Mathf.Abs(vtx.z*.5+vtx.x*.866) ) ;
var I = Vector3 (Mathf.Floor(vtx.x),Mathf.Floor(vtx.y),Mathf.Floor(vtx.z));
var D = Vector3(vtx.x%1,vtx.y%1,vtx.z%1);
//D = Vector3(D.x*D.x*(3.0-2.0*D.x),D.y*D.y*(3.0-2.0*D.y),D.z*D.z*(3.0-2.0*D.z));
var W = I.x + I.y*71.0 + 125.0*I.z;
return lerps(
lerps( lerps(rndng(W+0.0),rndng(W+1.0),D.x) , lerps(rndng(W+71.0),rndng(W+72.0),D.x) , D.y)
,
lerps( lerps(rndng(W+125.0),rndng(W+126.0),D.x) , lerps(rndng(W+153.0),rndng(W+154.0),D.x) , D.y)
,
D.z
);
}
function lnz2 ( vtx: Vector3 ): float//2d noise
{
vtx= Vector3 ( Mathf.Abs(vtx.x) , Mathf.Abs(vtx.y) , Mathf.Abs(vtx.z) ) ;
var I = Vector3 (Mathf.Floor(vtx.x),Mathf.Floor(vtx.y),Mathf.Floor(vtx.z));
var D = Vector3(vtx.x%1,vtx.y%1,vtx.z%1);
D = Vector3(D.x*D.x*(3.0-2.0*D.x),D.y*D.y*(3.0-2.0*D.y),D.z*D.z*(3.0-2.0*D.z));
var W = I.x + I.y*71.0 + 125.0*I.z;
return lerps(
lerps( lerps(rndng(W+0.0),rndng(W+1.0),D.x) , lerps(rndng(W+71.0),rndng(W+72.0),D.x) , D.z)
,
lerps( rndng(W+125.0), rndng(W+126.0),D.x)
,
D.z
);
}

Categories

Resources