xxxxxxxxxx
426
const buffersize = 1.0;
let theShader;
let pass2Shader;
let pass3Shader;
let shaderBG;
let pointBG;
let afGraphics;
let pass3Graphics;
let framebuffer;
let depthShader;
let secs;
let polygons = [];
let normals = [];
let cityURL = "3dmodel93.txt";
let cityText;
let spD;
const lowercorner = [0, 0, 0];
const uppercorner = [1674, 1874, 62.58163]
let target = [850,1010];
// performance metrics. numbers are for square culling not circle
// range > polygons > bootup > performance
// max 48k 17 s 19 fps
// 500 23k 8 s 34 fps
// 330 10659 4s 59 fps
// 300 8859 3.5 s 60 fps
const range = 1000;
let zoomLvl = 7.0;
let cityGeom;
let model3;
function preload(){
theShader = loadShader('shader.vert','shader.frag');
pass2Shader = loadShader('shbasic.vert','shedges.frag');
model3 = loadModel('cow-nonormals.obj');
loadStrings(cityURL, parseCity, uhOh);
}
function setup() {
// createCanvas(1920, 1035);
createCanvas(windowWidth-10, windowHeight-25);
spD = pixelDensity();
pixelDensity(1);
shaderBG = createGraphics(width*buffersize,height*buffersize,WEBGL);
afGraphics = createGraphics(shaderBG.width,shaderBG.height);
framebuffer = shaderBG.createFramebuffer();
pass2Graphics = createGraphics(width,height,WEBGL);
pass2Graphics.noStroke();
pass2Shader.setUniform('texSize',width);
pointBG = createGraphics(width,height);
drawPBG();
noCursor();
shaderBG.noStroke(); //wow actually saves crazy performinz
}
function draw() {
secs = millis()*0.001;
image(pointBG,0,0,width,height);
framebuffer.begin();
shaderBG.push();
shaderBG.shader(theShader);
theShader.setUniform('time', secs);
// // funny glitch mode
// theShader.setUniform('targetX', target[0]*300);
// theShader.setUniform('targetY', target[1]*300);
// // normal mode
theShader.setUniform('targetX', target[0]*1.0);
theShader.setUniform('targetY', target[1]*1.0);
theShader.setUniform('cullRadius', 0.4 * width / (zoomLvl*1.05));
shaderBG.background(255,0);
shaderBG.rotateX(0.5*PI - mouseY/height * PI);
shaderBG.rotateZ(mouseX/width * 2*PI);
shaderBG.translate(-target[0]*zoomLvl,
-target[1]*zoomLvl,
0);
shaderBG.scale(zoomLvl);
shaderBG.model(cityGeom);
shaderBG.pop();
framebuffer.end();
//this shit dum as fuck
shaderBG.image(framebuffer.depth,-shaderBG.width/2,-shaderBG.height/2,shaderBG.width,shaderBG.height);
afGraphics.image(shaderBG,0,0,afGraphics.width,afGraphics.height);
shaderBG.background(255,0)
shaderBG.image(framebuffer,-shaderBG.width/2,-shaderBG.height/2,shaderBG.width,shaderBG.height);
pass2Shader.setUniform('colorTexture', shaderBG);
pass2Shader.setUniform('depth',afGraphics);
pass2Graphics.shader(pass2Shader);
pass2Graphics.background(255,0);
pass2Shader.setUniform('texSize',width)
pass2Shader.setUniform('bgTexture', pointBG);
pass2Graphics.rect(0,0,width,height);
image(pass2Graphics,0,0,width,height);
// shaderBG.rotateZ(mouseX/width * 2*PI);
if(keyIsPressed){
if(keyCode === LEFT_ARROW || key == "a"|| key == "A"){
let moveVect = createVector(-30/zoomLvl,0)
moveVect.rotate(-mouseX/width * 2*PI);
target[0] += moveVect.x;
target[1] += moveVect.y;
}
if(keyCode === RIGHT_ARROW|| key == "d"|| key == "D"){
let moveVect = createVector(30/zoomLvl,0)
moveVect.rotate(-mouseX/width * 2*PI);
target[0] += moveVect.x;
target[1] += moveVect.y;
}
if(keyCode === UP_ARROW|| key == "w"|| key == "W"){
let moveVect = createVector(0, -30/zoomLvl)
moveVect.rotate(-mouseX/width * 2*PI);
target[0] += moveVect.x;
target[1] += moveVect.y;
}
if(keyCode === DOWN_ARROW|| key == "s"|| key == "S"){
let moveVect = createVector(0, 30/zoomLvl)
moveVect.rotate(-mouseX/width * 2*PI);
target[0] += moveVect.x;
target[1] += moveVect.y;
}
}
text("scroll to zoom, arrows to move, Q to switch between high and low quality, space to save image", 10, 20)
}
function keyPressed(){
if(key == " "){
saveCanvas();
}
if(key == "Q" || key == "q"){
if (pixelDensity() == 1){
pixelDensity(spD)
shaderBG.pixelDensity(spD)
afGraphics.pixelDensity(spD)
framebuffer.pixelDensity(spD)
pass2Graphics.pixelDensity(spD)
pointBG.pixelDensity(spD)
drawPBG();
}
else{
pixelDensity(1)
shaderBG.pixelDensity(1)
afGraphics.pixelDensity(1)
framebuffer.pixelDensity(1)
pass2Graphics.pixelDensity(1)
pointBG.pixelDensity(1)
drawPBG();
}
}
}
function parseCity(city){
cityText = city;
print('loaded');
polygons = [];
for(let i=0; i<city.length; i++){
// for(let i=0; i<200; i++){
if(city[i] !='ob' && city[i] !='cb'){
// print(city[i]);
let numstring = '';
let points = [];
for(let j=0; j<city[i].length; j++){
if(city[i][j] != " "){
numstring += city[i][j];
}
else{
points.push(int(numstring) * 0.01 +random()*0.00001); // slight random offset to eliminate colinear faces. i dont think it matters but the warnings flood the console and it upsets me
numstring = ''
}
}
if(sqrt(
pow(points[0]-lowercorner[0]-target[0],2)+
pow(points[1]-lowercorner[1]-target[1],2)) < range
){
polygons.push([]);
for(let j=0;j<points.length;j+=3){
polygons[polygons.length-1].push(createVector(
points[j]-lowercorner[0],
points[j+1]-lowercorner[1],
points[j+2]-lowercorner[2]));
}
}
}
}
cityGeom = new createModel(polygons);
print('polygon count: ' + polygons.length);
}
function createModel(polygonArray) {
return new p5.Geometry(
// detailX and detailY are not used in this example
1, 1,
// The callback must be an anonymous function, not an arrow function in
// order for "this" to be bound correctly.
function createGeometry() {
let vertIndex = 0;
for(let i=0;i<polygonArray.length;i++){
for(let j=0;j<polygonArray[i].length;j++){
this.vertices.push(p5.Vector.mult(polygonArray[i][j],1.0));
}
let u = p5.Vector.sub(polygons[polygons.length-1][1],
polygons[polygons.length-1][0]);
let v = p5.Vector.sub(polygons[polygons.length-1][2],
polygons[polygons.length-1][0]);
let n = p5.Vector.cross(u,v).normalize();
let alph = -atan(n.y/n.x);
let beta = -p5.Vector.angleBetween(n,createVector(0,0,1));
let passArray = [];
for(let j=0;j<polygonArray[i].length;j++){
let v = polygonArray[i][j].copy();
let vz = createVector(
v.x*cos(alph)-v.y*sin(alph),
v.x*sin(alph)+v.y*cos(alph),
v.z
)
let vy = createVector(
vz.x*cos(beta)+vz.z*sin(beta),
vz.y
// -vz.x*sin(beta)+vz.z*cos(beta)
)
passArray.push(vy.copy())
}
let faceList = earClipper(passArray.slice());
for(let j=0;j<faceList.length;j++){
this.faces.push([vertIndex+faceList[j][0],vertIndex+faceList[j][1],vertIndex+faceList[j][2]]);
}
// for(let j=1;j<polygonArray[i].length-1;j++){
// this.faces.push([vertIndex,vertIndex+j,vertIndex+j+1]);
// }
vertIndex+=polygonArray[i].length;
}
this.computeNormals();
}
);
}
function earClipper(polygon){
// 0 -> 1 angle, 1->2 angle
let tempTriangles = [];
let indices = []
let initlength = polygon.length;
let dir = 1;
for(let i=0;i<polygon.length;i++){
indices.push(i);
}
let breaker = 0;
while(tempTriangles.length<initlength-2 && breaker<50){
let trinum = tempTriangles.length;
breaker++
for(let i=0; i<polygon.length-2;i++){
let angle = p5.Vector.angleBetween(
p5.Vector.sub(polygon[(i+1)%polygon.length],polygon[i]),
p5.Vector.sub(polygon[(i+2)%polygon.length],polygon[(i+1)%polygon.length]));
if(angle * dir < 0.0){
let found = false;
for(let j=0;j<polygon.length;j++){
if(i==j || (i+2)%polygon.length==j || (j+1)%polygon.length==i || (i+2)%polygon.length==(j+1)%polygon.length){
continue;
}
if(checkIntersect(
polygon[i].x,
polygon[i].y,
polygon[(i+2)%polygon.length].x,
polygon[(i+2)%polygon.length].y,
polygon[j].x,
polygon[j].y,
polygon[(j+1)%polygon.length].x,
polygon[(j+1)%polygon.length].y)){
found = true;
}
}
if(found){
continue;
}
//bounding box check. not very elegant.
if(polygon.length>3){
let xmin = min(polygon[i].x,polygon[(i+2)%polygon.length].x, polygon[(i+1)%polygon.length].x);
let xmax = max(polygon[i].x,polygon[(i+2)%polygon.length].x, polygon[(i+1)%polygon.length].x);
let ymin = min(polygon[i].y,polygon[(i+2)%polygon.length].y, polygon[(i+1)%polygon.length].y);
let ymax = max(polygon[i].y,polygon[(i+2)%polygon.length].y, polygon[(i+1)%polygon.length].y);
for (let j=0;j<polygon.length;j++){
if(polygon[j].x < xmin ||polygon[j].x > xmax ||polygon[j].y < ymin ||polygon[j].y > ymax){
found = true;
}
}
if(!found){
continue;
}
}
//we have an ear hehe
tempTriangles.push([indices[(i )%polygon.length],
indices[(i+1)%polygon.length],
indices[(i+2)%polygon.length]])
indices.splice((i+1)%polygon.length,1)
polygon.splice((i+1)%polygon.length,1)
// continue;
}
}
if(trinum-tempTriangles.length==0)
dir = dir*-1;
}
return tempTriangles;
}
function checkIntersect(x1,y1,x2,y2,x3,y3,x4,y4){
let t = ((x1-x3)*(y3-y4)-(y1-y3)*(x3-x4))/
((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4));
let u = ((x1-x3)*(y1-y2)-(y1-y3)*(x1-x2))/
((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4));
return( t<=1 && t>=0 && u<=1 && u>=0);
}
function uhOh(response){
print('sad');
print(response);
}
function drawPBG(){
pointBG.background(255);
}
function mouseWheel(event) {
if (event.deltaY > 0) {
zoomLvl *= 1.1;
} else {
zoomLvl *= 0.9;
}
}