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
|
double clip_0_1(double t)
{
return (t<0) ? 0 : (t>1 ? 1 : t);
}
double trunc(double t)
{
if (fabs(t) < 0.0001)
t=0;
return t;
}
namespace ePiX {
class Spot {
public:
Spot(const Color& col, const P& loc) : m_tint(col), m_loc(loc) { }
Color m_tint;
P m_loc;
};
class Fog {
public:
Fog(const Color& c, const double k) : m_tint(c), m_dens(k) { }
Color apply_to(const Color& col, const double dist) const
{
Color me(m_tint);
return me.blend(col, exp(-dist*m_dens));
}
private:
Color m_tint;
double m_dens;
};
// cf. facet class in facet.h
class Chip {
public:
Chip(const P& p1, const P& p2, const P& p3, const P& p4, const double s,
const Color& c)
: pt1(p1), pt2(p2), pt3(p3), pt4(p4), m_shine(s), m_tint(c)
{
m_ctr = 0.25*(p1+p2+p3+p4);
P n = (p2-p1)*(p4-p1);
n *= recip(norm(n));
m_perp=n;
}
double how_far() const { return norm(camera.viewpt()-m_ctr); }
void draw(const ePiX::Fog& fog,
const ePiX::Spot& spot,
const ePiX::Color& ambient) const
{
fill(appearance(camera.viewpt(), fog, spot, ambient));
ePiX::quad(pt1, pt2, pt3, pt4);
}
private:
P pt1, pt2, pt3, pt4; // vertices
double m_shine; // shininess
Color m_tint; // out color
P m_ctr; // our location
P m_perp; // unit normal
Color appearance(const P& viewer, const Fog& fog,
const Spot& spot, Color ambient) const
{
P spot_dir(spot.m_loc - m_ctr);
double spot_dist(norm(spot_dir));
spot_dir *= recip(spot_dist);
P view_dir(viewer - m_ctr);
double view_dist(norm(view_dir));
view_dir *= recip(view_dist);
// calculate relative intensities
//double I_ambt = pow((m_perp|view_dir), 2); // cos^2 of normal angle
double I_ambt(fabs(m_perp|view_dir)); // |cos| of normal angle
// crude but fairly effective
//double I_spot = 0.5*(1+((spot_dir*m_perp)|(m_perp*view_dir)));
// reflect spot_dir across m_perp in the plane they span,
// then take (cos(angle to viewer)^4)
P refl_dir(-spot_dir + 2*(spot_dir|m_perp)*m_perp);
double I_spot(pow((refl_dir|view_dir), 2));
// light from spot that reaches our location and is reflected to viewer
Color spot_refl(I_spot*(fog.apply_to(spot.m_tint, spot_dist)));
// not shiny -> reflect mostly ambient
Color refl(I_ambt*ambient.blend(spot_refl, m_shine));
// Color we reflect toward viewer
Color source(m_tint.filter(refl));
return fog.apply_to(source, view_dist);
}
};
class chip_distance {
public:
bool operator() (const Chip& arg1, const Chip& arg2)
{
return arg1.how_far() > arg2.how_far();
}
};
} // end of namespace
|