xxxxxxxxxx
180
let max_angle = 15;
let max_angle_slider;
let seg_count = 10;
let seg_count_slider;
let light_angle;
const inf = 10000000;
let arrow_w;
let arrow_tip_w;
function setup() {
createCanvas(960, 540);
max_angle_slider = createSlider(0, 80, max_angle);
max_angle_slider.position(10, 10);
max_angle_slider.size(120);
seg_count_slider = createSlider(10, 1000, seg_count);
seg_count_slider.position(10, 30);
seg_count_slider.size(120);
light_angle = radians(90+45);
arrow_w = width/10;
arrow_tip_w = width/10/10 * 1.2;
}
function arrow(x, y, angle, w, tip_w) {
angle = 2*PI-angle;
line(x ,y, x+w*cos(angle), y+w*sin(angle))
push();
translate(x+w*cos(angle), y+w*sin(angle));
rotate(angle-PI);
rotate(radians(15));
line(0, 0, tip_w, 0);
rotate(radians(-2*15));
line(0, 0, tip_w, 0);
pop();
}
function draw_visualization() {
const circle_w = width * 0.55;
const line_segment_w = width * 0.12;
// half-circle and line segments
push();
noFill();
strokeWeight(2);
stroke("rgba(255,255,255,0.2)");
arc(0, 0, circle_w, circle_w, PI, 0)
stroke("white");
line(-circle_w/2 - line_segment_w, 0, -circle_w/2, 0); // left line segment
line(circle_w/2, 0, circle_w/2 + line_segment_w, 0); // right line segment
pop();
// surface segments
let seg_angles = Array(seg_count).fill(0);
let seg_w = circle_w/seg_count;
// randomize surface segments
randomSeed(69);
for(let i=0; i<seg_count; i++) {
seg_angles[i] = ((random()-0.5)*2)*max_angle;
}
// draw surface segments
push();
stroke("white");
noFill();
strokeWeight(2);
beginShape();
vertex(-circle_w/2, 0);
for(let i=0; i<seg_count; i++){
vertex(-circle_w/2+i*seg_w, -seg_w/2*tan(-radians(seg_angles[i])));
vertex(-circle_w/2+seg_w*(i+1), seg_w/2*tan(-radians(seg_angles[i])));
}
vertex(circle_w/2, 0);
endShape();
pop();
// light rays
push();
stroke("rgba(255,255,255,0.1)");
for(let i=0; i<seg_count; i++) {
line(-inf, -inf*tan(-light_angle), -circle_w/2 + seg_w/2 + i*seg_w, 0);
}
pop();
// reflected rays
push();
for(let i=0; i<seg_count; i++) {
stroke("white");
let refl_angle = light_angle - PI/2 + radians(seg_angles[i]);
if(refl_angle < 0) {
refl_angle = map(random(), 0, 1, 0, PI);
}
arrow(-circle_w/2 + seg_w/2 + i*seg_w, 0, refl_angle, arrow_w, arrow_tip_w);
// line( -circle_w/2 + seg_w/2 + i*seg_w, 0, inf, -inf*tan(-light_angle),);
}
pop();
// histogram of reflected rays
push();
angle_histogram = Array(180).fill(0);
for(let angle of seg_angles) {
let refl_angle = light_angle - PI/2 + radians(angle);
if(refl_angle < 0) {
refl_angle = map(random(), 0, 1, 0, PI);
}
angle_histogram[floor(degrees(refl_angle))]++;
}
let max_freq = Math.max(angle_histogram);
translate(width*-0.2, height*0.25);
stroke("white");
line(0,0,width*0.2*2, 0);
line(0, 0, 0, height*-0.2);
let offset = width*0.01;
for(let angle=0; angle<180; angle++) {
let x = map(angle, 0, 180, offset, width*0.2*2);
strokeWeight(2);
line(x, 0, x, map(angle_histogram[angle], 0, max_freq, 0, -height*0.18));
if(angle%15 == 0) {
push();
noStroke();
fill("white");
textSize(12);
translate(x, 10);
rotate(radians(45));
textAlign(CENTER, CENTER);
text(angle.toString(), 0, 0);
pop();
}
}
pop();
}
function draw() {
background(25);
// set sliders
max_angle = max_angle_slider.value()
seg_count = seg_count_slider.value();
// title
const title_top_margin = 40;
push();
fill("white");
noStroke();
textSize(width * 0.03);
textAlign(CENTER, CENTER);
textStyle(BOLD)
text("Ray Reflectance", width/2 , title_top_margin);
textSize(width * 0.03 * 0.6);
fill("rgba(255,255,255,0.2)");
textStyle(NORMAL)
text("by Gholamreza Dar", width/2 , title_top_margin + width * 0.025);
pop();
// UI
// Visualization
push()
translate(width/2, height/2);
translate(0, height * 0.19);
draw_visualization();
pop()
}