PVector cam, camT, camOffset, camOffsetT, camFacing;
tr = new Terrain(20, 20, 100, 0.1, 1800, "texture.jpg");
cam = new PVector(0, -height/8, height/2);
camT = new PVector(0, -height/8, height/2);
camOffset = new PVector(0, 0, 0);
camOffsetT = new PVector(0, 0, 0);
camFacing = new PVector(0, 0, 0);
theta = radians(90+(height/2-mouseY)*0.2);
phi = radians(270+(mouseX-width/2)*0.2);
camOffsetT.set(100*sin(theta)*cos(phi), 100*cos(theta), 100*sin(theta)*sin(phi));
cam.set(lerp(cam.x, camT.x, 0.25), lerp(cam.y, camT.y, 1), lerp(cam.z, camT.z, 0.25));
camOffset.set(lerp(camOffset.x, camOffsetT.x, 0.25), lerp(camOffset.y, camOffsetT.y, 0.25), lerp(camOffset.z, camOffsetT.z, 0.25));
camFacing = PVector.add(cam, camOffset);
camPjCol = floor((cam.x+tr.cellSize*tr.cols*0.5)/tr.cellSize);
camPjRow = floor((cam.z+tr.cellSize*tr.rows*0.5)/tr.cellSize);
translate(width/2, height/2);
camera(cam.x, cam.y, cam.z, camFacing.x, camFacing.y, camFacing.z, 0, 1, 0);
tr.display(camPjCol, camPjRow);
line(0, 0, 0, coordsLength, 0, 0);
line(0, 0, 0, 0, -coordsLength, 0);
line(0, 0, 0, 0, 0, coordsLength);
float distToTl = dist(cam.x, cam.z, tr.vertices[camPjRow][camPjCol].x, tr.vertices[camPjRow][camPjCol].z);
float distToBr = dist(cam.x, cam.z, tr.vertices[camPjRow+1][camPjCol+1].x, tr.vertices[camPjRow+1][camPjCol+1].z);
ratio = getRatio(tr.vertices[camPjRow+1][camPjCol].x, tr.vertices[camPjRow+1][camPjCol].z,
tr.vertices[camPjRow][camPjCol].x, tr.vertices[camPjRow][camPjCol].z,
tr.vertices[camPjRow][camPjCol+1].x, tr.vertices[camPjRow][camPjCol+1].z,
camT.y = (ratio[0]*tr.vertices[camPjRow+1][camPjCol].y + ratio[1]*tr.vertices[camPjRow][camPjCol].y + ratio[2]*tr.vertices[camPjRow][camPjCol+1].y)-height/8;
ratio = getRatio(tr.vertices[camPjRow][camPjCol+1].x, tr.vertices[camPjRow][camPjCol+1].z,
tr.vertices[camPjRow+1][camPjCol+1].x, tr.vertices[camPjRow+1][camPjCol+1].z,
tr.vertices[camPjRow+1][camPjCol].x, tr.vertices[camPjRow+1][camPjCol].z,
camT.y = (ratio[0]*tr.vertices[camPjRow][camPjCol+1].y + ratio[1]*tr.vertices[camPjRow+1][camPjCol+1].y + ratio[2]*tr.vertices[camPjRow+1][camPjCol].y)-height/8;
float [] getRatio(float x1, float z1, float x2, float z2, float x3, float z3, float xAvg, float zAvg){
float [] result = new float[3];
result[2] = (t6*t1-t3*t4)/(t5*t1-t2*t4);
result[1] = (t3*t5-t2*t6)/(t1*t5-t2*t4);
result[0] = 1-result[2]-result[1];
Terrain(int cols, int rows, float cellSize, float noiseIncreRatio, float yRange, String path) {
this.cellSize = cellSize;
vertices = new PVector[rows][cols];
for (int i=0;i<rows;i++) {
for (int j=0;j<cols;j++) {
float x = (j-cols*0.5)*cellSize;
float y = (noise(i*noiseIncreRatio, j*noiseIncreRatio)-0.5)*yRange;
float z = (i-rows*0.5)*cellSize;
vertices[i][j] = new PVector(x, y, z);
void display(int camPjCol, int camPjRow) {
for (int i=0;i<rows-1;i++) {
for (int j=0;j<cols-1;j++) {
vertex(vertices[i+1][j].x,vertices[i+1][j].y,vertices[i+1][j].z, float(j)/cols*img.width, float(i+1)/rows*img.height);
vertex(vertices[i][j].x,vertices[i][j].y,vertices[i][j].z, float(j)/cols*img.width, float(i)/rows*img.height);
vertex(vertices[i][j+1].x,vertices[i][j+1].y,vertices[i][j+1].z, float(j+1)/cols*img.width, float(i)/rows*img.height);
vertex(vertices[i][j+1].x,vertices[i][j+1].y,vertices[i][j+1].z, float(j+1)/cols*img.width, float(i)/rows*img.height);
vertex(vertices[i+1][j+1].x,vertices[i+1][j+1].y,vertices[i+1][j+1].z, float(j+1)/cols*img.width, float(i+1)/rows*img.height);
vertex(vertices[i+1][j].x,vertices[i+1][j].y,vertices[i+1][j].z, float(j)/cols*img.width, float(i+1)/rows*img.height);
camT.x+=10*sin(theta)*cos(phi);
camT.z+=10*sin(theta)*sin(phi);
camT.x-=10*sin(theta)*cos(phi);
camT.z-=10*sin(theta)*sin(phi);
camT.x+=10*sin(theta)*cos(phi-PI/2);
camT.z+=10*sin(theta)*sin(phi-PI/2);
camT.x+=10*sin(theta)*cos(phi+PI/2);
camT.z+=10*sin(theta)*sin(phi+PI/2);
camT.x = constrain(camT.x, -tr.cols*0.5*tr.cellSize, (tr.cols*0.5-1)*tr.cellSize);
camT.z = constrain(camT.z, -tr.rows*0.5*tr.cellSize, (tr.rows*0.5-1)*tr.cellSize);