-
Notifications
You must be signed in to change notification settings - Fork 0
/
PhongShader.hpp
135 lines (111 loc) · 3.32 KB
/
PhongShader.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
#pragma once
#include "Vertex.h"
#include "SceneContext.h"
#include "VertexShaderMatHelper.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <memory>
class PhongShader
{
public:
using UseDerivative = std::false_type;
struct VSOut {
glm::vec4 proj_pos;
glm::vec4 normal;
glm::vec2 texcoord;
glm::vec3 world_pos;
VSOut& operator+=(const VSOut& rhs)
{
proj_pos += rhs.proj_pos;
normal += rhs.normal;
texcoord += rhs.texcoord;
world_pos += rhs.world_pos;
return *this;
}
VSOut operator+(const VSOut& rhs) const
{
return VSOut(*this) += rhs;
}
VSOut& operator*=(float v) {
proj_pos *= v;
normal *= v;
texcoord *= v;
world_pos *= v;
return *this;
}
VSOut operator*(float rhs) const
{
return VSOut(*this) *= rhs;
}
void Lerp(const VSOut& v0, const VSOut& v1, const VSOut& v2, float a, float b, float c) noexcept {
normal = v0.normal * a + v1.normal * b + v2.normal * c;
texcoord = v0.texcoord * a + v1.texcoord * b + v2.texcoord * c;
world_pos = v0.world_pos * a + v1.world_pos * b + v2.world_pos * c;
}
};
class VertexShader : public VertexShaderMatHelper {
public:
VSOut operator()(const Vertex& v) const
{
glm::vec4 world_pos = model * glm::vec4(v.position, 1.0f);
return {
proj_view * world_pos,
obj_to_world_normal * glm::vec4(v.normal, 0.0f),
v.texcoord,
glm::vec3(world_pos)
};
}
};
class PixelShader {
public:
std::shared_ptr<SceneContext> pContext;
float qpow(float x, int n) {
float res = 1;
while (n) {
if (n & 1) {
res *= x;
}
x *= x;
n >>= 1;
}
return res;
}
glm::vec4 operator()(const VSOut& v, const VSOut& ddx, const VSOut& ddy, int modelId, int meshId)
{
glm::vec3 light_pos = pContext->light->GetPosition();
glm::vec3 light_intensity = pContext->light->GetIntensity();
glm::vec3 camera_pos = pContext->camera_pos_cache;
glm::vec3 light_dir = pContext->light->GetDirection(v.world_pos);
float d = glm::length(light_pos - v.world_pos);
light_intensity /= d * d;
glm::vec3 N = glm::normalize(glm::vec3(v.normal));
glm::vec3 view_dir = glm::normalize(camera_pos - v.world_pos);
auto material_id = pContext->models[modelId]->meshes[meshId].material_idx;
auto& material = pContext->models[modelId]->materials[material_id];
glm::vec3 ka, kd, ks;
ka = material->Ka;
if (material->diffuse != nullptr)
kd = material->diffuse->Sample(v.texcoord.x, v.texcoord.y);
else
kd = material->Kd;
kd = glm::pow(kd, glm::vec3(2.2f));
if (material->specular != nullptr)
ks = material->specular->Sample(v.texcoord.x, v.texcoord.y);
else
ks = material->Ks;
glm::vec3 ambient = ka * glm::vec3(1.0f); //ka * ambient light intensity
glm::vec3 diffuse = kd * light_intensity * std::max(0.0f, glm::dot(N, light_dir));
glm::vec3 half = glm::normalize(view_dir + light_dir);
glm::vec3 specular = ks * light_intensity * qpow(std::max(0.0f, glm::dot(N, half)), 150);
glm::vec3 color = ambient + diffuse + specular;
color = glm::pow(color, glm::vec3(1.0f / 2.2f));
color.r = std::max(0.0f, std::min(1.0f, color.r)); // Saturate
color.g = std::max(0.0f, std::min(1.0f, color.g));
color.b = std::max(0.0f, std::min(1.0f, color.b));
return glm::vec4(color, 1.0f);
}
};
public:
VertexShader vs;
PixelShader ps;
};