Gain/Persistence in Simplex Noise based on slope - java

I'm currently working on a terrain engine and I'm experimenting a little bit with noise. It's so fascinating to see what different structures, functions and pure imagination can create with just a few lines of code. Recently I saw this post: http://squall-digital.com/ProceduralGeneration.html, I was definitely intrigued by all of these techniques, but especially the first one caught my attention. The programmer made the gain (or persistence) of the noise to be proportional to the slope of the noise on that point. I'm currently trying to achieve this but I don't think I'm on the right track.
I'm currently using simplex noise. I know the author of the article uses Perlin Noise and yes, I have seen how to calculate the derivative of Perlin Noise, but obviously this implementation wouldn't work because of the fundamental differences in how Perlin and Simplex noise are generated. I thus set out on my own way to try and approximate the slope of noise on a given position.
I came up with the following "algorithm":
Calculate neighboring points of noise [(x + 1, z), (x - 1, z), (x, z + 1), (x, z - 1)].
Calculate their respective noise value
Calculate differenceX and differenceZ in noise values on the x-axis and the z-axis respectively
Create vectors from origin: (2, differenceX, 0) and (0, differenceZ, 2)
Scale to vectors of length 1
Add y-components of the resulting unit vectors
use this y-component as the "slope" approximated at the given point.
Now I have implemented this in code (I added "3D" vectors for the purpose of ease of understanding)
private static float slope(OpenSimplex2F simplex, float x, float z, float noise) {
float[] neighbours = getStraightNeighbours(simplex, x, z);
float xSlope = (neighbours[1] - neighbours[0]) / (2.0f * x);
float zSlope = (neighbours[3] - neighbours[2]) / (2.0f * z);
float[] vecX = new float[] { 1, xSlope, 0 };
float[] vecZ = new float[] { 0, zSlope, 1 };
float scaleX = Maths.sqrt(1.0f + xSlope * xSlope);
float scaleZ = Maths.sqrt(1.0f + zSlope * zSlope);
for (int i = 0; i < 3; i++) {
vecX[i] /= scaleX;
vecZ[i] /= scaleZ;
}
float[] grad = new float[] {
vecX[0] + vecZ[0],
vecX[1] + vecZ[1],
vecX[2] + vecZ[2]
};
return grad[1];
}
Now this gives me extremely underwhelming and rest assured, wrong results: Result
Is there anyone that can explain me if this is a good technique to approximate the slope of if this is completely wrong. I'm not the biggest math genius so I was already happy I could figure this out and that it produced a result in the first place. If anyone has a resource linked to the derivative of simplex noise (which would be a life saver, obviously), it'd be really appreciated!

Related

Trying to create a physics engine in java from documentary which uses c++

I am just messing around a bit in processing since i know it better than any other language and stumbled up on this website Custom 2d physics engine. So far so good. i am at the point where i have 2 rectangles colliding and i need to resolve the collision. According to the paper i should use the code :
void ResolveCollision( Object A, Object B )
{
// Calculate relative velocity
Vec2 rv = B.velocity - A.velocity
// Calculate relative velocity in terms of the normal direction
float velAlongNormal = DotProduct( rv, normal )
// Do not resolve if velocities are separating
if(velAlongNormal > 0)
return;
// Calculate restitution
float e = min( A.restitution, B.restitution)
// Calculate impulse scalar
float j = -(1 + e) * velAlongNormal
j /= 1 / A.mass + 1 / B.mass
// Apply impulse
Vec2 impulse = j * normal
A.velocity -= 1 / A.mass * impulse
B.velocity += 1 / B.mass * impulse
}
This is written in C++ so i would need to port it to java. And here i get stuck on two things. 1: What does the author mean with "normal"? how do i get the "normal"? thing 2 are these 3 lines of code:
Vec2 impulse = j * normal
A.velocity -= 1 / A.mass * impulse
B.velocity += 1 / B.mass * impulse
He creates a vector wich has only 1 number? j * normal?
I don'really have a clear picture on what exactly happens which does not really benefit me.
He is probably referring to this as "normal". So normal is a vector with 2 elements since you are referring to a tutorial for 2D physics. And j*normal will multiply each element of normal with the scalar j.
normal, velocity and impulse are vectors with 2 elements for coordinates x, y. From the series of tutorials you are referring to, you can see normal defined here towards the end.
The "normal" vector at a point on the boundary of a 2D or 3D shape is the vector that is:
perpendicular to the boundary at that point;
has length 1; and
points outward instead of inside the shape
The normal vector is the same all along a straight line (2d) or flat surface (3d), so you will also hear people talk about the "normal" of the line or surface in these cases.
The normal vector is used for all kinds of important calculations in graphics and physics code.
How exactly to calculate the normal vector for a point, line, or surface depends on what data structures you have representing the geometry of your objects.

Mathematical Equation Conversion

I'm attempting to write a method that determines the area of a polygon (complex or simple) on a sphere. I have a paper that was written by a few guys at the JPL that more or less give you the equations for these calculations.
The pdf file can be found here:
http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
The equation can be found on page 7, under "The Spherical Case - Approximation":
I also typed the equation in Word:
Spherical_Case_Equation
I need assistance with converting this equation into the standard form (I think that's the right terminology). I've already done something similar for the Planer Case:
private double calcArea(Point2D[] shape) {
int n = shape.length;
double sum = 0.0;
if (n < 3) return 0.0;
for (int i = 0; i < n-1 ; i++) {
sum += (shape[i].getX() * shape[i+1].getY()) - (shape[i+1].getX() * shape[i].getY());
}
System.out.println(0.5 * Math.abs(sum));
return 0.5 * Math.abs(sum);
}
I just need help with doing something similar for the spherical case. Any assistance will be greatly appreciated.
I haven't read the paper you referenced. The area of a spherical polygon is proportional to the angle excess.
Area = r²(Σ Aᵢ - (n - 2)π)
To compute the corner angles, you may start with the 3D coordinates of your points. So at corner i you have vertex p[i] = (x[i],y[i],z[i]) and adjacent vertices p[i-1] and p[i+1] (resp p[(i+n-1)%n] and p[(i+1)%n] to get this cyclically correct). Then the cross products
v₁ = p[i] × p[i-1]
v₂ = p[i] × p[i+1]
will be orthogonal to the planes spanned by the incident edges and the origin which is the center of the sphere. Noe the angle between two vectors in space is given by
Aᵢ = arccos(⟨v₁,v₂⟩ / (‖v₁‖ * ‖v₂‖))
where ⟨v₁,v₂⟩ denotes the dot product between these two vectors which is proportional to the cosine of the angle, and ‖v₁‖ denotes the length of the first vector, likewise ‖v₂‖ for the second.

Bertrand's Paradox Simulation

So, I saw this on Hacker News the other day: http://web.mit.edu/tee/www/bertrand/problem.html
It basically says what's the probability that a random chord on a circle with radius of 1 has a length greater than the square root of 3.
Looking at it, it seems obvious that the answer is 1/3, but comments on HN have people who are smarter than me debating this. https://news.ycombinator.com/item?id=10000926
I didn't want to debate, but I did want to make sure I wasn't crazy. So I coded what I thought would prove it to be P = 1/3, but I end up getting P ~ .36. So, something's got to be wrong with my code.
Can I get a sanity check?
package com.jonas.betrand;
import java.awt.geom.Point2D;
import java.util.Random;
public class Paradox {
final static double ROOT_THREE = Math.sqrt(3);
public static void main(String[] args) {
int greater = 0;
int less = 0;
for (int i = 0; i < 1000000; i++) {
Point2D.Double a = getRandomPoint();
Point2D.Double b = getRandomPoint();
//pythagorean
if (Math.sqrt(Math.pow((a.x - b.x), 2) + Math.pow((a.y - b.y), 2)) > ROOT_THREE) {
greater++;
} else {
less++;
}
}
System.out.println("Probability Observerd: " + (double)greater/(greater+less));
}
public static Point2D.Double getRandomPoint() {
//get an x such that -1 < x < 1
double x = Math.random();
boolean xsign = new Random().nextBoolean();
if (!xsign) {
x *= -1;
}
//formula for a circle centered on origin with radius 1: x^2 + y^2 = 1
double y = Math.sqrt(1 - (Math.pow(x, 2)));
boolean ysign = new Random().nextBoolean();
if (!ysign) {
y *= -1;
}
Point2D.Double point = new Point2D.Double(x, y);
return point;
}
}
EDIT: Thanks to a bunch of people setting me straight, I found that my method of finding a random point wasn't indeed so random. Here is a fix for that function which returns about 1/3.
public static Point2D.Double getRandomPoint() {
//get an x such that -1 < x < 1
double x = Math.random();
Random r = new Random();
if (!r.nextBoolean()) {
x *= -1;
}
//circle centered on origin: x^2 + y^2 = r^2. r is 1.
double y = Math.sqrt(1 - (Math.pow(x, 2)));
if (!r.nextBoolean()) {
y *= -1;
}
if (r.nextBoolean()) {
return new Point2D.Double(x, y);
} else {
return new Point2D.Double(y, x);
}
}
I believe you need to assume one fixed point say at (0, 1) and then choose a random amount of rotation in [0, 2*pi] around the circle for the location of the second point of the chord.
Just for the hell of it I wrote your incorrect version in Swift (learn Swift!):
struct P {
let x, y: Double
init() {
x = (Double(arc4random()) / 0xFFFFFFFF) * 2 - 1
y = sqrt(1 - x * x) * (arc4random() % 2 == 0 ? 1 : -1)
}
func dist(other: P) -> Double {
return sqrt((x - other.x) * (x - other.x) + (y - other.y) * (y - other.y))
}
}
let root3 = sqrt(3.0)
let total = 100_000_000
var samples = 0
for var i = 0; i < total; i++ {
if P().dist(P()) > root3 {
samples++
}
}
println(Double(samples) / Double(total))
And the answer is indeed 0.36. As the comments have been explaining, a random X value is more likely to choose the "flattened area" around pi/2 and highly unlikely to choose the "vertically squeezed" area around 0 and pi.
It is easily fixed however in the constructor for P:
(Double(arc4random()) / 0xFFFFFFFF is fancy-speak for random floating point number in [0, 1))
let angle = Double(arc4random()) / 0xFFFFFFFF * M_PI * 2
x = cos(angle)
y = sin(angle)
// outputs 0.33334509
Bertrand's paradox is exactly that: a paradox. The answer can be argued to be 1/3 or 1/2 depending on how the problem is interpreted. It seems you took the random chord approach where one side of the line is fixed and then you draw a random chord to any part of the circle. Using this method, the chances of drawing a chord that is longer than sqrt(3) is indeed 1/3.
But if you use a different approach, I'll call it the random radius approach, you'll see that it can be 1/2! The random radius is this, you draw a radius in the circle, and then you take a random chord that this radius bisects. At this point, a random chord will be longer than sqrt(3) 1/2 of the time.
Lastly, the random midpoint method. Choose a random point in the circle, and then draw a chord with this random point as the midpoint of the chord. If this point falls within a concentric circle of radius 1/2, then the chord is shorter than sqrt(3). If it falls outside the concentric circle, it is longer than sqrt(3). A circle of radius 1/2 has 1/4 the area of a circle with radius 1, so the chance of a chord smaller than sqrt(3) is 1/4.
As for your code, I haven't had time to look at it yet, but hope this clarifies the paradox (which is just an incomplete question not actually a paradox) :D
I would argue that the Bertrand paradox is less a paradox and more a cautionary lesson in probability. It's really asking the question: What do you mean by random?
Bertrand argued that there are three natural but different methods for randomly choosing a chord, giving three distinct answers. But of course, there are other random methods, but these methods are arguably not the most natural ones (that is, not the first that come to mind). For example, we could randomly position the two chord endpoints in a non-uniform manner. Or we position the chord midpoint according to some non-uniform density, like a truncated bi-variate normal.
To simulate the three methods with a programming language, you need to be able to generate uniform random variables on the unit interval, which is what all standard (pseudo)-random number generators should do. For one of the methods/solutions (the random midpoint one), you then have to take the square root of one of the uniform random variables. You then multiple the random variables by a suitable factor (or rescale). Then for each simulation method (or solution), some geometry gives the expressions for the two endpoints.
For more details, I have written a post about this problem. I recommend the links and books I have cited at the end of that post, under the section Further reading. For example, see Section 1.3 in this new set of published lecture notes. The Bertrand paradox is also in The Pleasures of Probability by Isaac. It’s covered in a non-mathematical way in the book Paradoxes from A to Z by Clark.
I have also uploaded some simulation code in MATLAB, R and Python, which can be found here.
For example, in Python (with NumPy):
import numpy as np; #NumPy package for arrays, random number generation, etc
import matplotlib.pyplot as plt #for plotting
from matplotlib import collections as mc #for plotting line chords
###START Parameters START###
#Simulation disk dimensions
xx0=0; yy0=0; #center of disk
r=1; #disk radius
numbLines=10**2;#number of lines
###END Parameters END###
###START Simulate three solutions on a disk START###
#Solution A
thetaA1=2*np.pi*np.random.uniform(0,1,numbLines); #choose angular component uniformly
thetaA2=2*np.pi*np.random.uniform(0,1,numbLines); #choose angular component uniformly
#calculate chord endpoints
xxA1=xx0+r*np.cos(thetaA1);
yyA1=yy0+r*np.sin(thetaA1);
xxA2=xx0+r*np.cos(thetaA2);
yyA2=yy0+r*np.sin(thetaA2);
#calculate midpoints of chords
xxA0=(xxA1+xxA2)/2; yyA0=(yyA1+yyA2)/2;
#Solution B
thetaB=2*np.pi*np.random.uniform(0,1,numbLines); #choose angular component uniformly
pB=r*np.random.uniform(0,1,numbLines); #choose radial component uniformly
qB=np.sqrt(r**2-pB**2); #distance to circle edge (alonge line)
#calculate trig values
sin_thetaB=np.sin(thetaB);
cos_thetaB=np.cos(thetaB);
#calculate chord endpoints
xxB1=xx0+pB*cos_thetaB+qB*sin_thetaB;
yyB1=yy0+pB*sin_thetaB-qB*cos_thetaB;
xxB2=xx0+pB*cos_thetaB-qB*sin_thetaB;
yyB2=yy0+pB*sin_thetaB+qB*cos_thetaB;
#calculate midpoints of chords
xxB0=(xxB1+xxB2)/2; yyB0=(yyB1+yyB2)/2;
#Solution C
#choose a point uniformly in the disk
thetaC=2*np.pi*np.random.uniform(0,1,numbLines); #choose angular component uniformly
pC=r*np.sqrt(np.random.uniform(0,1,numbLines)); #choose radial component
qC=np.sqrt(r**2-pC**2); #distance to circle edge (alonge line)
#calculate trig values
sin_thetaC=np.sin(thetaC);
cos_thetaC=np.cos(thetaC);
#calculate chord endpoints
xxC1=xx0+pC*cos_thetaC+qC*sin_thetaC;
yyC1=yy0+pC*sin_thetaC-qC*cos_thetaC;
xxC2=xx0+pC*cos_thetaC-qC*sin_thetaC;
yyC2=yy0+pC*sin_thetaC+qC*cos_thetaC;
#calculate midpoints of chords
xxC0=(xxC1+xxC2)/2; yyC0=(yyC1+yyC2)/2;
###END Simulate three solutions on a disk END###

Wireframe sphere with latitude/longitude OpenGL

I'm trying to create a wireframe sphere using openGL that has latitude and longitude lines. Currently I'm running into an issue that I think I'm simply overlooking and with a bit of help can quickly correct with creating the sphere. My code is the following inside of a class that creates displays:
double rho = 1;
gl.glBegin(GL2.GL_LINE_LOOP);
for (int i = 0; i< 360; i++){
theta = i/180 * Math.PI;
for (int j = 0; j< 360; j++){
double phi = j/180 * Math.PI;
double x = rho * Math.sin(phi) * Math.cos(theta);
double y = rho * Math.sin(phi) * Math.sin(theta);
double z = rho * Math.sin(phi);
gl.glVertex3d(x, y, z);
}
gl.glEnd();
}
From this code I'm currently not getting anything to display. What am I missing?
There are number of problems in this code:
As already pointed out in the comments, the glBegin() and glEnd() are unbalanced. The glBegin() needs to be inside the first loop.
The second angle should only loop from 0 to 180, not 360. This is based on the definition of spherical coordinates.
In the divisions i/180 and j/180, both values are of type int, therefore the operation is an integer division. With the values used, the result of those divisions will always be 0 or 1.
The calculation of the z-coordinate needs to use cos(phi) instead of sin(phi).
Not wrong, but just recommendations:
There's no need to use double precision values. OpenGL will use single precision anyway.
As mentioned in the comments, the code is using legacy features that are deprecated and deleted in modern versions of OpenGL.
Sticking with the immediate mode drawing, fixing these problems should result in working (untested) code:
float radius = 1.0f;
for (int i = 0; i <= 360; i++) {
gl.glBegin(GL2.GL_LINE_LOOP);
float theta = i * (Math.PI / 180.0f);
for (int j = 0; j <= 180; j++) {
float phi = j * (Math.PI / 180.0f);
float x = radius * Math.sin(phi) * Math.cos(theta);
float y = radius * Math.sin(phi) * Math.sin(theta);
float z = radius * Math.cos(phi);
gl.glVertex3f(x, y, z);
}
gl.glEnd();
}
This will give you the longitude lines. The code for the latitude lines will be very similar, with the two loops swapped.
As for the discussion about deprecated/legacy features, this is somewhat broad to be covered here. So just a very quick summary:
What you're using here is typically called "immediate mode drawing". This is the way OpenGL worked in the original version. More efficient ways of specifying vertex data were introduced around 20 years ago. Initially is was Vertex Arrays, then Vertex Buffer Objects (VBO). Vertex Array Objects (VAO) were introduced later to make the state setup more efficient.
With OpenGL 3.2, which was introduced in 2009, two "profiles" were defined:
Core Profile: Deletes the deprecated legacy features, including immediate mode drawing.
Compatibility Profile: Still supports all features to maintain backwards compatibility.
If you write new code, particularly if you just start learning, there's no good reason to learn legacy features. The initial threshold is slightly higher when using the Core Profile (mainly because it requires you to write your own shaders in GLSL), but it's well worth it. Current versions of OpenGL ES are also much closer to the Core Profile, and do not have any of these legacy featues.

Fibonacci Spiral - Robocode

Does anyone know how I could make a spiral motion following the Fibonacci pattern around a point in Robocode? I have methods like setTurnRight (double), setAhead (double), getX () and getY ().
I tried to make a simple spiral, without the required standard, that way, but it did not work ... It was more like a circle.
this.setAhead(this.direction * Double.POSITIVE_INFINITY);
if (this.direction == 1) {
this.setTurnRight(Utils.normalRelativeAngleDegrees(this.enemy.getBearing() + 60));
} else {
this.setTurnRight(Utils.normalRelativeAngleDegrees(this.enemy.getBearing() + 120));
}
physics of the game:
http://robowiki.net/wiki/Robocode/Game_Physics
Robocode Logarithmic Spiral
Here is a working run method to make a bot follow a logarithmic spiral and I believe it is a close approximation of the golden spiral (which is the spiral that can be approximated with the Fibonacci numbers).
public void run() {
double v = 5;
double c = Math.PI*2;
double a = .1;
double b = .0053468;
setMaxVelocity(v);
setAhead(100*999);
setTurnRight(360*999);
while(true)
{
double t = getTime();
double f = a*Math.pow(Math.E,b*t);
double w = v/(c*f);
setMaxTurnRate(w);
execute();
System.out.println(t+"\t"+w);
}
}
Explanation
To move in a circle (trivial spiral), you keep constant speed (how fast the bot is moving) and constant revolution speed (how fast the bot is turning). There are several ways to go from this trivial spiral movement to something more interesting. The simplest way to move in a spiral is to keep constant speed and vary the revolution speed. This answer from the game development exchange gives a good walk through on how to get an approximate equation for revolution speed.
w = v / (2*pi*t) or w = v / (2*pi*f(t)) where:
w = revolution speed
v = speed
pi = 3.14...
t = time or f(t) = function of the radius over time
This equation gives a way to move along a spiral and we can choose any spiral we want by specifying a f(t). To get the correct radius function for the golden spiral, check out this wiki page about the golden spiral. It gives this equation:
r = a*e^(b*theta) or in other words f(t) = a*e^(b*t) where:
f(t) = our radius function
a = arbitrary constant for scaling the spiral
e = Euler's constant
b = .0053468 (or .3063489 if using radians)
t = time
Conclusion
All that is left is to incorporate this code into your bot and choose your own values for a and v. v will determine the speed of the bot, so a larger v is a good idea (max is 10) and since the max for w is 8, you should scale a accordingly so that w stays between 0 and 8 for as long as possible (which is why I've included the println).
[NOTE: I couldn't think of an easy way to superimpose the golden spiral on the bot's path to check it's accuracy. So while it is clearly a logarithmic spiral, I am unsure to what degree it approximates the desired golden spiral ]

Categories