-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathblinn_phong.hpp
187 lines (154 loc) · 6.54 KB
/
blinn_phong.hpp
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#pragma once
#include "common_header.hpp"
#include "shader.hpp"
#include "OBJ_Loader.h"
#include <iostream>
struct BlinnPhongAttribute {
objl::Vertex vertex;
objl::Material material;
Mat3 TBN;
std::shared_ptr<const Image> map_Kd = nullptr;
std::shared_ptr<const Image> map_Ka = nullptr;
std::shared_ptr<const Image> map_Ks = nullptr;
std::shared_ptr<const Image> map_bump = nullptr;
};
struct Light {
Vec3 pos;
RGBAColor intensity;
};
class BlinnPhongUniform {
public:
std::vector<Light> lights;
};
class BlinnPhongProperty: public AbstractInterpolatable {
public:
BlinnPhongProperty() = default;
BlinnPhongProperty(const Vec3& normal,
const Vec2& uv,
const Mat3& TBN,
const objl::Material& material,
const Mat4& M,
const Vec3& camera_pos,
std::shared_ptr<const Image> map_Kd,
std::shared_ptr<const Image> map_Ka,
std::shared_ptr<const Image> map_Ks,
std::shared_ptr<const Image> map_bump):
normal_world_n(normal), uv(uv), map_Kd(map_Kd),
map_Ka(map_Ka), map_Ks(map_Ks), material(material),
M(M), camera_pos(camera_pos), map_bump(map_bump), TBN(TBN) {}
Vec3 normal_world_n;
Vec2 uv;
Mat3 TBN;
std::shared_ptr<const Image> map_Kd = nullptr;
std::shared_ptr<const Image> map_Ka = nullptr;
std::shared_ptr<const Image> map_Ks = nullptr;
std::shared_ptr<const Image> map_bump = nullptr;
Mat4 M;
Vec3 camera_pos;
objl::Material material;
// TODO 这其实很不合理。。。要求插值顺序了。。
// TODO: assert map_Kd is the same
BlinnPhongProperty operator+(const BlinnPhongProperty& other) const {
return BlinnPhongProperty{ normal_world_n + other.normal_world_n, uv + other.uv, TBN, material, M, camera_pos, map_Kd, map_Ka, map_Ks, map_bump };
}
BlinnPhongProperty operator*(float k) const {
return BlinnPhongProperty{ normal_world_n * k, uv * k, TBN, material, M, camera_pos, map_Kd, map_Ka, map_Ks, map_bump };
}
};
class BlinnPhongVShader: public VShader<BlinnPhongAttribute, BlinnPhongProperty, BlinnPhongUniform> {
public:
virtual Vertex<BlinnPhongProperty> shade(
const BlinnPhongAttribute& attr,
const BlinnPhongUniform& _,
const RasterizerInfo& info
) const {
auto& data = attr.vertex;
Vertex<BlinnPhongProperty> vert;
// vert
vert.pos_model = { data.Position.X, data.Position.Y, data.Position.Z };
vert.properties.normal_world_n = to_vec3_as_dir(info.M * to_vec4_as_dir({ data.Normal.X, data.Normal.Y, data.Normal.Z })).normalized();
vert.properties.TBN = attr.TBN;
// material
vert.properties.map_Kd = attr.map_Kd;
vert.properties.map_Ka = attr.map_Ka;
vert.properties.map_Ks = attr.map_Ks;
vert.properties.map_bump = attr.map_bump;
vert.properties.uv = { attr.vertex.TextureCoordinate.X, attr.vertex.TextureCoordinate.Y };
vert.properties.material = attr.material;
// rasterizer
vert.properties.M = info.M;
vert.properties.camera_pos = info.camera_pos;
return vert;
}
};
RGBAColor objl_vec3_to_color(const objl::Vector3& vec3) {
return RGBAColor{ vec3.X, vec3.Y, vec3.Z, 1.0 };
}
RGBAColor get_texture(std::shared_ptr<const Image> texture, const Vec2& uv) {
if(!texture) {
return RGBAColor{1.0, 1.0, 1.0, 1.0};
}
auto [width, height] = texture->size();
auto texture_color = texture->getPixel(
std::max<int>(0, std::min<int>(width - 1, lround(uv[0] * (width - 1)))),
std::max<int>(0, std::min<int>(height - 1, lround(uv[1] * (height - 1))))
);
return texture_color;
}
class BlinnPhongFShader: public FShader<BlinnPhongProperty, BlinnPhongUniform> {
public:
virtual RGBAColor shade(
const Fragment<BlinnPhongProperty>& fragment,
const BlinnPhongUniform& uniform
) const {
RGBAColor out = {0, 0, 0, 1};
auto normal_world = fragment.properties.normal_world_n.normalized();
// bump mapping (normal)
// 改变的:表面法向量
if(fragment.properties.map_bump != nullptr) {
// change normal_world
auto normal_c = get_texture(fragment.properties.map_bump, fragment.properties.uv);
Vec3 normal_tangent {
normal_c.r * 2 - 1,
normal_c.g * 2 - 1,
normal_c.b * 2 - 1
};
Vec3 normal_model = fragment.properties.TBN * normal_tangent;
normal_world = to_vec3_as_dir(fragment.properties.M * to_vec4_as_dir(normal_model)).normalized();
}
// what if no map ?
{
for(auto light: uniform.lights) {
auto light_pos_world = light.pos;
//// kd
// texture
auto texture_color = get_texture(fragment.properties.map_Kd, fragment.properties.uv);
// coefficient
auto k = std::max<float>(0, dot_product(
normal_world,
(light_pos_world - fragment.pos_world).normalized()
));
auto r_squared = (light.pos - fragment.pos_world).norm2_squared();
auto eff = k / r_squared;
auto c = objl_vec3_to_color(fragment.properties.material.Kd) * texture_color * light.intensity * eff;
out += c;
//// ks
// texture
auto highlight_texture_color = get_texture(fragment.properties.map_Ks, fragment.properties.uv);
auto h = ((fragment.properties.camera_pos - fragment.pos_world).normalized() + (light_pos_world - fragment.pos_world).normalized()).normalized();
auto s = objl_vec3_to_color(fragment.properties.material.Ks) *
highlight_texture_color *
pow( (float)std::max<float>(0, dot_product(normal_world, h)), (float) fragment.properties.material.Ns);
out += s;
}
}
{
// Ka
auto texture_color = get_texture(fragment.properties.map_Ka, fragment.properties.uv);
auto a = objl_vec3_to_color(fragment.properties.material.Ka) * texture_color;
out += a;
}
out.a = 1.0;
return out.clip();
}
};