ProtoTracer  1.0
Real-time 3D rendering and animation engine
Loading...
Searching...
No Matches
CombineMaterial.tpp
Go to the documentation of this file.
1#pragma once
2
3template<size_t materialCount>
4CombineMaterial<materialCount>::CombineMaterial() {}
5
6template<size_t materialCount>
7void CombineMaterial<materialCount>::AddMaterial(Method method, Material* material, float opacity) {
8 if (materialsAdded < materialCount) {
9 this->method[materialsAdded] = method;
10 this->materials[materialsAdded] = material;
11 this->opacity[materialsAdded] = opacity;
12
13 materialsAdded++;
14 }
15}
16
17template<size_t materialCount>
18void CombineMaterial<materialCount>::SetMethod(uint8_t index, Method method) {
19 if (index < materialsAdded) {
20 this->method[index] = method;
21 }
22}
23
24template<size_t materialCount>
25void CombineMaterial<materialCount>::SetOpacity(uint8_t index, float opacity) {
26 if (index < materialsAdded) {
27 this->opacity[index] = opacity;
28 }
29}
30
31template<size_t materialCount>
32void CombineMaterial<materialCount>::SetMaterial(uint8_t index, Material* material) {
33 if (index < materialsAdded) {
34 materials[index] = material;
35 }
36}
37
38template<size_t materialCount>
39RGBColor CombineMaterial<materialCount>::GetRGB(const Vector3D& position, const Vector3D& normal, const Vector3D& uvw) {
40 Vector3D rgb;
41 Vector3D tempV;
42 RGBColor temp;
43
44 for (int i = 0; i < materialsAdded; i++) {
45 if (opacity[i] > 0.025f) {
46 switch (method[i]) {
47 case Base:
48 temp = materials[i]->GetRGB(position, normal, uvw);
49
50 rgb.X = temp.R;
51 rgb.Y = temp.G;
52 rgb.Z = temp.B;
53
54 rgb = rgb * opacity[i];
55
56 break;
57 case Add:
58 // Add all colors to base color
59 temp = materials[i]->GetRGB(position, normal, uvw);
60
61 rgb.X = (rgb.X + temp.R) * opacity[i] + rgb.X * (1.0f - opacity[i]);
62 rgb.Y = (rgb.Y + temp.G) * opacity[i] + rgb.Y * (1.0f - opacity[i]);
63 rgb.Z = (rgb.Z + temp.B) * opacity[i] + rgb.Z * (1.0f - opacity[i]);
64
65 break;
66 case Subtract:
67 // Subtract from base color
68 temp = materials[i]->GetRGB(position, normal, uvw);
69
70 rgb.X = (rgb.X - temp.R) * opacity[i] + rgb.X * (1.0f - opacity[i]);
71 rgb.Y = (rgb.Y - temp.G) * opacity[i] + rgb.Y * (1.0f - opacity[i]);
72 rgb.Z = (rgb.Z - temp.B) * opacity[i] + rgb.Z * (1.0f - opacity[i]);
73
74 break;
75 case Multiply:
76 // Multiply with base color
77 temp = materials[i]->GetRGB(position, normal, uvw);
78
79 rgb.X = (rgb.X * temp.R) * opacity[i] + rgb.X * (1.0f - opacity[i]);
80 rgb.Y = (rgb.Y * temp.G) * opacity[i] + rgb.Y * (1.0f - opacity[i]);
81 rgb.Z = (rgb.Z * temp.B) * opacity[i] + rgb.Z * (1.0f - opacity[i]);
82
83 break;
84 case Divide:
85 // Divide from base color
86 temp = materials[i]->GetRGB(position, normal, uvw);
87
88 rgb.X = (rgb.X / temp.R) * opacity[i] + rgb.X * (1.0f - opacity[i]);
89 rgb.Y = (rgb.Y / temp.G) * opacity[i] + rgb.Y * (1.0f - opacity[i]);
90 rgb.Z = (rgb.Z / temp.B) * opacity[i] + rgb.Z * (1.0f - opacity[i]);
91
92 break;
93 case Darken:
94 // Find minimum color in all cases
95 temp = materials[i]->GetRGB(position, normal, uvw);
96 tempV = Vector3D::Min(Vector3D(temp.R, temp.G, temp.B), rgb);
97
98 rgb = Vector3D::LERP(rgb, tempV, opacity[i]);
99
100 break;
101 case Lighten:
102 // Find maximum color in all cases
103 temp = materials[i]->GetRGB(position, normal, uvw);
104 tempV = Vector3D::Max(Vector3D(temp.R, temp.G, temp.B), rgb);
105
106 rgb = Vector3D::LERP(rgb, tempV, opacity[i]);
107
108 break;
109 case Screen:
110 // 1 - (1 - a)(1 - b)
111 temp = materials[i]->GetRGB(position, normal, uvw);
112
113 tempV.X = 255.0f - (255.0f - rgb.X) * (255.0f - temp.R);
114 tempV.Y = 255.0f - (255.0f - rgb.Y) * (255.0f - temp.G);
115 tempV.Z = 255.0f - (255.0f - rgb.Z) * (255.0f - temp.B);
116
117 rgb = Vector3D::LERP(rgb, tempV, opacity[i]);
118
119 break;
120 case Overlay:
121 // if a < 0.5, 2ab
122 // else 1 - 2(1 - a)(1 - b)
123 temp = materials[i]->GetRGB(position, normal, uvw);
124
125 if (rgb.X < 128) tempV.X = 2.0f * rgb.X * temp.R;
126 else tempV.X = 255.0f - 2.0f * (255.0f - rgb.X) * (255.0f - temp.R);
127
128 if (rgb.Y < 128) tempV.Y = 2.0f * rgb.Y * temp.G;
129 else tempV.Y = 255.0f - 2.0f * (255.0f - rgb.Y) * (255.0f - temp.G);
130
131 if (rgb.Z < 128) tempV.Z = 2.0f * rgb.Z * temp.B;
132 else tempV.Z = 255.0f - 2.0f * (255.0f - rgb.Z) * (255.0f - temp.B);
133
134 rgb = Vector3D::LERP(rgb, tempV, opacity[i]);
135
136 break;
137 case SoftLight:
138 // (1 - 2b)a^2 + 2ba
139 temp = materials[i]->GetRGB(position, normal, uvw);
140
141 tempV.X = (255.0f - 2.0f * temp.R) * (rgb.X * rgb.X) + 2.0f * (temp.R * rgb.X);
142 tempV.Y = (255.0f - 2.0f * temp.G) * (rgb.Y * rgb.Y) + 2.0f * (temp.G * rgb.Y);
143 tempV.Z = (255.0f - 2.0f * temp.B) * (rgb.Z * rgb.Z) + 2.0f * (temp.B * rgb.Z);
144
145 rgb = Vector3D::LERP(rgb, tempV, opacity[i]);
146
147 break;
148 case Replace:
149 temp = materials[i]->GetRGB(position, normal, uvw);
150
151 tempV.X = temp.R;
152 tempV.Y = temp.G;
153 tempV.Z = temp.B;
154
155 rgb = Vector3D::LERP(rgb, tempV, opacity[i]);
156
157 break;
158 case EfficientMask:
159 temp = materials[i]->GetRGB(position, normal, uvw);
160
161 if (temp.R > 128 && temp.G > 128 && temp.B > 128) {
162 rgb.X = temp.R;
163 rgb.Y = temp.G;
164 rgb.Z = temp.B;
165
166 rgb = rgb * opacity[i];
167
168 i = materialsAdded;
169
170 break;
171 }
172
173 break;
174 case Bypass:
175 materials[i]->GetRGB(position, normal, uvw);
176 break;
177 default:
178
179 break;
180 }
181 }
182 }
183
184 return RGBColor(rgb.Constrain(0, 255));
185}