xxxxxxxxxx
483
// performance testing sketch
// just disabling and enabling shaders doesnt seem to do a lot
// probably running all these big objects is the main issue
// vert shaders and geometry are fine but im either asking too much of the frag shader or doing too many weird passes. but im thinking its one of the shaders, find out which ones the bottleneck (probably edge detection)
// ok the framebuffer is a pretty bad fps drop but even without it i cant get it above 20fps which is worrying
// running on pixeldensity 1 makes it run a bit better but also introduces horrible aliasing. this is just a resolution issue ig
// the color shader has branching paths which is bad i think
// eliminate sin and cos functions in shaders? (there are none actually lol)
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;
let qtext = 'low';
const lowercorner = [0, 0, 0];
const uppercorner = [1674, 1874, 62.58163]
// const lowercorner = [79409, 450938, -5.03208];
// const uppercorner = [81083, 452812, 57.54955]
// let target = [(uppercorner[0]-lowercorner[0])*0.5,
// (uppercorner[1]-lowercorner[1])*0.5];
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 = 300;
let zoomLvl = 7.0;
let cityGeom;
let model3;
function preload(){
theShader = loadShader('shader.vert','shader.frag');
pass2Shader = loadShader('shbasic.vert','shedges.frag');
// // PASS 3 COMMENTED
// pass3Shader = loadShader('shbasic.vert','shpixelize.frag');
model3 = loadModel('cow-nonormals.obj');
loadStrings(cityURL, parseCity, uhOh);
}
function setup() {
// createCanvas(1920, 1035);
createCanvas(1536, 820);
spD = pixelDensity();
pixelDensity(1);
shaderBG = createGraphics(width*buffersize,height*buffersize,WEBGL);
afGraphics = createGraphics(shaderBG.width,shaderBG.height);
framebuffer = shaderBG.createFramebuffer();
// // PASS 3 COMMENTED
// pass3Graphics = createGraphics(width,height,WEBGL);
// pass3Graphics.noStroke();
// pass3Shader.setUniform('texSize',width);
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(secs);
shaderBG.rotateZ(mouseX/width * 2*PI);
// shaderBG.model(model3);
shaderBG.translate(-target[0]*zoomLvl,
-target[1]*zoomLvl,
0);
shaderBG.scale(zoomLvl);
shaderBG.model(cityGeom);
// //make a tree
// shaderBG.translate(target[0],target[1], 7.5);
// shaderBG.rotateX(1.6);
// shaderBG.cylinder(1, 15,5);
// shaderBG.translate(0.0,7.5,0.0 );
// shaderBG.sphere(5, 5, 5)
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);
// // PASS 3 COMMENTED
// pass3Graphics.shader(pass3Shader);
// pass3Graphics.background(255,0);
// pass3Shader.setUniform('colorTexture', pass2Graphics);
// pass3Shader.setUniform('texSize',width);
// pass3Shader.setUniform('depth',afGraphics);
// pass3Shader.setUniform('time', secs);
// pass3Shader.setUniform('mouseX', mouseX);
// pass3Shader.setUniform('mouseY', mouseY);
// pass3Graphics.rect(0,0,width,height);
image(pass2Graphics,0,0,width,height);
text('quality: ' + qtext + ', left-click to change',0,10);
// text('fps:'+frameRate(),0,10);
// text('zoom_lvl:' + zoomLvl,0,20);
// text('poly_count:' + polygons.length,0,30);
// text('target_x:' + target[0],0,40);
// text('target_y:' + target[1],0,50);
// rect(mouseX-12.5*cos(secs), mouseY-12.5*sin(secs*1.2), 25*cos(secs), 25*sin(secs*1.2))
// noLoop();
}
function keyPressed(){
if(keyCode === LEFT_ARROW){
target[0] += 10;
}
if(keyCode === RIGHT_ARROW){
target[0] -= 10;
}
if(keyCode === UP_ARROW){
target[1] += 10;
}
if(keyCode === DOWN_ARROW){
target[1] -= 10;
}
}
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 mouseClicked(){
if (pixelDensity() == 1){
// saveCanvas();
qtext = 'low'
pixelDensity(spD)
shaderBG.pixelDensity(spD)
afGraphics.pixelDensity(spD)
framebuffer.pixelDensity(spD)
pass2Graphics.pixelDensity(spD)
pointBG.pixelDensity(spD)
drawPBG();
}
else{
qtext = 'high'
pixelDensity(1)
shaderBG.pixelDensity(1)
afGraphics.pixelDensity(1)
framebuffer.pixelDensity(1)
pass2Graphics.pixelDensity(1)
pointBG.pixelDensity(1)
drawPBG();
}
}
function drawPBG(){
pointBG.background(255);
// points
// const rast=30;
// for(let i=rast/2;i<width;i+=rast){
// for(let j=rast/2;j<height;j+=rast){
// pointBG.point(i,j);
// }
// }
// // lines
// const rast=60;
// const symbSize = 5;
// for(let i=rast/2;i<width;i+=rast){
// for(let j=rast/2;j<height;j+=rast){
// pointBG.line(i,j-symbSize,i,j+symbSize);
// pointBG.line(i-symbSize,j,i+symbSize,j);
// }
// }
}
function mouseMoved(){
// target = [(uppercorner[0]-lowercorner[0]) * (0.3+(mouseX/width)*0.7),
// (uppercorner[1]-lowercorner[1]) * (0.3+(mouseY/height)*0.7)];
// parseCity(cityText);
}
function mouseWheel(event) {
if (event.deltaY > 0) {
zoomLvl *= 1.1;
} else {
zoomLvl *= 0.9;
}
}