processing / p5.js

p5.js is a client-side JS platform that empowers artists, designers, students, and anyone to learn to code and express themselves creatively on the web. It is based on the core principles of Processing. http://twitter.com/p5xjs —
http://p5js.org/
GNU Lesser General Public License v2.1
21.57k stars 3.3k forks source link

beginShape vertex, lights() issues #5429

Open blitzgenerative opened 3 years ago

blitzgenerative commented 3 years ago

Most appropriate sub-area of p5.js?

Details about the bug:

Run the code below. Comment out:

beginShape(TRIANGLES); for (let face_points of faces){ for (let p of face_points) { vertex(...vectors[p]); } } endShape();

or box(100)

When it is the box, the directional light is consistent. When it is the beginShape() the lighting is very bright then very dark as if the light itself is rotating in its own way? And not working properly as a result.

`const PHI = (1 + Math.sqrt(5)) / 2; let vectors = [ [-1, PHI, 0], [ 1, PHI, 0], [-1, -PHI, 0], [ 1, -PHI, 0], [0, -1, PHI], [0, 1, PHI], [0, -1, -PHI], [0, 1, -PHI], [ PHI, 0, -1], [ PHI, 0, 1], [-PHI, 0, -1], [-PHI, 0, 1] ]; let faces = [ [0, 11, 5], [0, 5, 1], [0, 1, 7], [0, 7, 10], [0, 10, 11], [1, 5, 9], [5, 11, 4], [11, 10, 2], [10, 7, 6], [7, 1, 8], [3, 9, 4], [3, 4, 2], [3, 2, 6], [3, 6, 8], [3, 8, 9], [4, 9, 5], [2, 4, 11], [6, 2, 10], [8, 6, 7], [9, 8, 1], ];

const canvasWidth = 500; const canvasHeight = 500; const fps=30; const rad=50; function norm_v(v) { const ln2 = Math.sqrt(v[0]2+v[1]2+v[2]*2) return v.map(c=> crad/ln2); }

let middle_point_cache = {}; function middle_point(point_1, point_2) { smaller_index = min(point_1, point_2); greater_index = max(point_1, point_2); let key = smaller_index.toString()+'-'+greater_index.toString(); if (key in middle_point_cache) { return middle_point_cache[key];} let middle = vectors[point_1].map((c, i)=>(c+vectors[point_2][i])/2 ); vectors.push( norm_v(middle) ); index = vectors.length - 1; middle_point_cache[key] = index; return index; }

function divide(faces) { let faces_subdiv = []; for (let tri of faces){ v1 = middle_point(tri[0], tri[1]); v2 = middle_point(tri[1], tri[2]); v3 = middle_point(tri[2], tri[0]); faces_subdiv.push([tri[0], v1, v3]); faces_subdiv.push([tri[1], v2, v1]); faces_subdiv.push([tri[2], v3, v2]); faces_subdiv.push([v1, v2, v3]); } return faces_subdiv; }

let all_cs = [];

function setup(){ const random_seed = parseInt(random(100)); randomSeed(random_seed);

createCanvas(canvasWidth, canvasHeight, WEBGL);
frameRate(fps);
background(all_cs[0],all_cs[1],all_cs[2]);

const subdiv = parseInt( random(2) )+2;//4;

for (let i = 0; i < 12; i++) {
  all_cs.push(random(255));
}
vectors = vectors.map(x=>norm_v(x));
for (let i = 0; i < subdiv; i++) {
    faces = divide(faces);
}

}

function draw() {

console.log(frameRate()) translate(0,0,200); background(all_cs[0],all_cs[1],all_cs[2]); ambientLight(128, 128, 128); directionalLight(128, 128, 128, 0, 0, -1); rotateY(0.01frameCount); rotateZ(0.01frameCount);

fill(all_cs[6],all_cs[7],all_cs[8]);
strokeWeight(0.1);
stroke(all_cs[9],all_cs[10],all_cs[11]);
//box(100)
beginShape(TRIANGLES);
for (let face_points of faces){
    for (let p of face_points) {
        vertex(...vectors[p]);
    }
}
endShape();

} `

Thank you for any help that can be provided.

welcome[bot] commented 3 years ago

Welcome! 👋 Thanks for opening your first issue here! And to ensure the community is able to respond to your issue, be sure to follow the issue template if you haven't already.

stalgiag commented 3 years ago

Hi! Thanks for the issue. The behavior with immediate mode shapes and lighting is very unpredictable because of how the normals are (or are not) calculated in shapes drawn with beginShape.

That said, could you offer the simplest possible sketch that reproduces the problem you are experiencing?

davepagurek commented 1 year ago

We could consider automatically generating normals from the faces in immediate mode (for each face, something like v2.copy().sub(v1).cross(v3.copy().sub(v1)).normalize().) We would probably also need to add a flag to indicate when a normal has been manually specified so we can avoid doing this calculation in that case. We would probably also need to test this for performance, as it would mean doing extra CPU-side calculations per face each frame (maybe we can specify an easy way to disable it? I suppose normal(0, 0, 1) would do it.)

In any case, for now this could be solved by manually specifying normal().