1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
struct material {
pen[] p; // diffusepen,ambientpen,emissivepen,specularpen
real opacity;
real shininess;
real granularity;
void operator init(pen diffusepen=black, pen ambientpen=black,
pen emissivepen=black, pen specularpen=mediumgray,
real opacity=opacity(diffusepen),
real shininess=defaultshininess,
real granularity=-1) {
p=new pen[] {diffusepen,ambientpen,emissivepen,specularpen};
this.opacity=opacity;
this.shininess=shininess;
this.granularity=granularity;
}
void operator init(material m, real granularity=m.granularity) {
p=copy(m.p);
opacity=m.opacity;
shininess=m.shininess;
this.granularity=granularity;
}
pen diffuse() {return p[0];}
pen ambient() {return p[1];}
pen emissive() {return p[2];}
pen specular() {return p[3];}
void diffuse(pen q) {p[0]=q;}
void ambient(pen q) {p[1]=q;}
void emissive(pen q) {p[2]=q;}
void specular(pen q) {p[3]=q;}
}
void write(file file, string s="", material x, suffix suffix=none)
{
write(file,s);
write(file,"{");
write(file,"diffuse=",x.diffuse());
write(file,", ambient=",x.ambient());
write(file,", emissive=",x.emissive());
write(file,", specular=",x.specular());
write(file,", opacity=",x.opacity);
write(file,", shininess=",x.shininess);
write(file,", granularity=",x.granularity);
write(file,"}",suffix);
}
void write(string s="", material x, suffix suffix=endl)
{
write(stdout,s,x,suffix);
}
bool operator == (material m, material n)
{
return all(m.p == n.p) && m.opacity == n.opacity &&
m.shininess == n.shininess && m.granularity == n.granularity;
}
material operator cast(pen p)
{
return material(p);
}
material[] operator cast(pen[] p)
{
return sequence(new material(int i) {return p[i];},p.length);
}
pen operator ecast(material m)
{
return m.p.length > 0 ? m.diffuse() : nullpen;
}
material emissive(material m, real granularity=m.granularity)
{
return material(black+opacity(m.opacity),black,m.diffuse(),black,m.opacity,1,
granularity);
}
pen color(triple normal, material m, light light, transform3 T=light.T) {
triple[] position=light.position;
if(invisible((pen) m)) return invisible;
if(position.length == 0) return m.diffuse();
normal=unit(T*normal);
if(settings.twosided) normal *= sgn(normal.z);
real s=m.shininess*128;
real[] Diffuse=rgba(m.diffuse());
real[] Ambient=rgba(m.ambient());
real[] Specular=rgba(m.specular());
real[] p=rgba(m.emissive());
for(int i=0; i < position.length; ++i) {
triple L=light.viewport ? position[i] : T*position[i];
real Ldotn=max(dot(normal,L),0);
p += light.ambient[i]*Ambient+Ldotn*light.diffuse[i]*Diffuse;
// Apply specularfactor to partially compensate non-pixel-based rendering.
if(Ldotn > 0) // Phong-Blinn model of specular reflection
p += dot(normal,unit(L+Z))^s*light.specularfactor*
light.specular[i]*Specular;
}
return rgb(p[0],p[1],p[2])+opacity(opacity(m.diffuse()));
}
light operator * (transform3 t, light light)
{
light light=light(light);
if(!light.viewport) light.position=shiftless(t)*light.position;
return light;
}
light operator cast(triple v) {return light(v);}
light Viewport=light(ambient=gray(0.1),specularfactor=3,viewport=true,
(0.25,-0.25,1));
light White=light(new pen[] {rgb(0.38,0.38,0.45),rgb(0.6,0.6,0.67),
rgb(0.5,0.5,0.57)},specularfactor=3,
new triple[] {(-2,-1.5,-0.5),(2,1.1,-2.5),(-0.5,0,2)});
light Headlamp=light(gray(0.8),ambient=gray(0.1),specular=gray(0.7),
specularfactor=3,viewport=true,dir(42,48));
currentlight=Headlamp;
light nolight;
|