class Vector{
private double x;
private double y;
public Vector(Point point) {
this.x = point.getDoubleX();
this.y = point.getDoubleY();
}
public Vector(double x, double y) {
this.x = x;
this.y = y;
}
public void setVectorX(double x) {
this.x = x;
}
public void setVectorY(double y) {
this.y = y;
}
public double getVectorX() {
return x;
}
public double getVectorY() {
return y;
}
public double length() {
return Math.sqrt(x*x + y*y);
}
public Vector normalize() {
double length = this.length();
Vector nV =new Vector((double)x/length, (double)y/length);
return nV;
}
public Vector directionVectorFromStartToEnd(double startX, double startY, double endX, double endY) {
Vector nV =new Vector(endX- startX, endY - startY);
return nV;
}
public Vector subtract(Vector vector) {
Vector vec = new Vector(this.x - vector.getVectorX(),
this.y - vector.getVectorY());
return vec;
}
public Vector add(Vector vector) {
Vector vec = new Vector(this.x + vector.getVectorX(),
this.y + vector.getVectorY());
return vec;
}
/*
* 벡터간 내적을 수행한다.
*/
public double dot(Vector vector) {
double value = vector.getVectorX() * x + vector.getVectorY() * y;
return value;
}
}
double lerp(double startLoc,
double startValue,
double endLoc,
double endValue,
double loc) {
double t = (double)(loc - startLoc)/(double)(endLoc - startLoc);
double value = (endValue - startValue) * t + startValue;
return value;
}
public double getValue(int x, int y) {
double realX = (double)x/(double)pixelPerGrid;
double realY = (double)y/(double)pixelPerGrid;
int gridX = (int)realX;
int gridY = (int)realY;
Vector calcVector = new Vector(realX,realY);
/*
* 그리드 좌표는 왼쪽 위 좌표로 구해지며, 어떤 공간의 그리드 좌표를 구했으면
* 각 x, y + 1 최대로 하여금 격자로 계산을 수행해야 함.
*/
Vector leftTopRandomValue = randomVectors[gridY][gridX];
Vector rightTopRandomValue = randomVectors[gridY][gridX+1];
Vector leftBottomRandomValue = randomVectors[gridY+1][gridX];
Vector rightBottomRandomValue = randomVectors[gridY+1][gridX+1];
Vector leftTop = new Vector(gridX, gridY);
Vector leftTopDirection = calcVector.subtract(leftTop);
Vector rightTop = new Vector(gridX+1, gridY);
Vector rightTopDirection = calcVector.subtract(rightTop);
Vector leftBottom = new Vector(gridX, gridY+1);
Vector leftBottomDirection = calcVector.subtract(leftBottom);
Vector rightBottom = new Vector(gridX+1, gridY+1);
Vector rightBottomDirection = calcVector.subtract(rightBottom);
double leftTopValue = leftTopDirection.dot(leftTopRandomValue);
double rightTopValue = rightTopDirection.dot(rightTopRandomValue);
double leftBottomValue = leftBottomDirection.dot(leftBottomRandomValue);
double rightBottomValue = rightBottomDirection.dot(rightBottomRandomValue);
double lerpedTop = lerp(gridX,leftTopValue, gridX+1,rightTopValue, realX);
double lerpedBottom = lerp(gridX,leftBottomValue, gridX+1,rightBottomValue, realX);
double learpedCenter = lerp(gridY, lerpedTop,gridY+1, lerpedBottom, realY);
return learpedCenter;
}
1. 초기화
그리드 격자에 고유한 랜덤 방향 벡터를 할당한다.
이 때 크기는 1인 방향 벡터를 생성해야 한다.
public void init(int cols, int rows, int pixelPerGrid) {
randomVectors = new Vector[rows][cols];
/*
* 벡터 난수 할당
*/
for(int y=0;y<rows;y++) {
for(int x=0;x<cols;x++) {
Vector vc = new Vector(
Math.random()*2-1,
Math.random()*2-1
);
vc = vc.normalize();
randomVectors[y][x] = vc;
}
}
this.pixelPerGrid = pixelPerGrid;
}
각 그리드에 대해서 임의의 방향 벡터를 생성한다. 이 때 노말라이즈를 다시 하는 이유는, x가 -1~1 범위, y가 -1 ~ 1 범위로 생성되더라도 둘 다 1 1 인 경우, 크기가 sqrt(2) 가 되기 때문에, 1이 아니게 된다. 따라서 sqrt(2)로 다시 나눠주기 위해 노말라이즈를 한다.
2. 점까지의 방향 벡터 구하기
인접하는 그리드 꼭짓점 4개와 구하고자 하는 좌표의 정점까지의 방향 벡터를 구한다.