gKit2 light
envmap.h
1 
2 #ifndef _ENVMAP_H
3 #define _ENVMAP_H
4 
5 #include <array>
6 
7 #include "vec.h"
8 #include "color.h"
9 #include "image.h"
10 
12 struct Envmap
13 {
14  Envmap( ) : m_faces(), m_width(0) {}
15 
16  Envmap( const int size ) : m_faces(), m_width(size)
17  {
18  for(int i= 0; i < 6; i++)
19  m_faces[i]= Image(size, size);
20  }
21 
23  Envmap( const Image& image ) : m_faces(), m_width(0)
24  {
25  int w= image.width() / 4;
26  int h= image.height() / 3;
27  if(w != h)
28  return;
29 
30  m_width= w;
31 
32  // chaque face de la cubemap est un carre [image.width/4 x image.height/3] dans l'image originale
33  struct { int x, y; } faces[]= {
34  {0, 1}, // X+
35  {2, 1}, // X-
36  {1, 2}, // Y+
37  {1, 0}, // Y-
38  {1, 1}, // Z+
39  {3, 1}, // Z-
40  };
41 
42  for(int i= 0; i < 6; i++)
43  m_faces[i]= flipX(flipY(copy(image, faces[i].x*w, faces[i].y*h, w, h)));
44  }
45 
47  Envmap( const std::array<Image, 6>& faces ) : m_faces()
48  {
49  for(int i= 0; i < 6; i++)
50  m_faces[i]= flipX(flipY(faces[i]));
51 
52  m_width= m_faces[0].width();
53  for(int i= 0; i < 6; i++)
54  if(m_width != m_faces[i].width() || m_width != m_faces[i].height())
55  m_width= 0;
56  }
57 
58  int width( ) const { return m_width; }
59  int height( ) const { return m_width; }
60  bool empty() const { return m_width == 0; }
61 
63  void linear( const float gamma = 2.2f )
64  {
65  for(int i= 0; i < 6; i++)
66  for(int p= 0; p < int(m_faces[i].size()); p++)
67  {
68  Color pixel= m_faces[i](p);
69  m_faces[i](p)= Color(std::pow(pixel.r, gamma), std::pow(pixel.g, gamma), std::pow(pixel.b, gamma));
70  }
71  }
72 
74  void gamma( const float gamma = 2.2f )
75  {
76  for(int i= 0; i < 6; i++)
77  for(int p= 0; p < int(m_faces[i].size()); p++)
78  {
79  Color pixel= m_faces[i](p);
80  m_faces[i](p)= Color(std::pow(pixel.r, 1 / gamma), std::pow(pixel.g, 1 / gamma), std::pow(pixel.b, 1 / gamma));
81  }
82  }
83 
85  Image cross( ) const
86  {
87  if(empty())
88  return Image();
89 
90  // chaque face de la cubemap est un carre [image.width/4 x image.height/3] dans l'image originale
91  struct { int x, y; } faces[]= {
92  {0, 1}, // X+
93  {2, 1}, // X-
94  {1, 2}, // Y+
95  {1, 0}, // Y-
96  {1, 1}, // Z+
97  {3, 1}, // Z-
98  };
99 
100  // 3 lignes de 4 colonnes
101  Image image(4*width(), 3*height());
102  for(int i= 0; i < 6; i++)
103  {
104  Image face= flipY(flipX(m_faces[i]));
105 
106  int xmin= faces[i].x*width();
107  int ymin= faces[i].y*height();
108  for(int y= 0; y < height(); y++)
109  for(int x= 0; x < width(); x++)
110  image(xmin+x, ymin+y)= face(x, y);
111  }
112 
113  return image;
114  }
115 
117  std::array<Image, 6> faces( ) const
118  {
119  if(empty())
120  return std::array<Image, 6>();
121 
122  std::array<Image, 6> faces;
123  for(int i= 0; i < 6; i++)
124  faces[i]= flipY(flipX(m_faces[i]));
125 
126  return faces;
127  }
128 
129  Color& operator() ( const int face, const int x, const int y )
130  {
131  return m_faces[face](x, y);
132  }
133 
134  Color operator() ( const int face, const int x, const int y ) const
135  {
136  return m_faces[face](x, y);
137  }
138 
140  Color texture( const Vector& d ) const
141  {
142  // reproduit la convention opengl / renderman
143  // cf https://www.khronos.org/registry/OpenGL/specs/gl/glspec46.core.pdf#section.8.13
144 
145  float sm, tm;
146  int face= -1;
147  Vector m= Vector(std::abs(d.x), std::abs(d.y), std::abs(d.z));
148  if(m.x > m.y && m.x > m.z)
149  {
150  // X
151  if(d.x > 0)
152  {
153  face= 0;
154  sm= -d.z / m.x;
155  tm= -d.y / m.x;
156  }
157  else
158  {
159  face= 1;
160  sm= d.z / m.x;
161  tm= -d.y / m.x;
162  }
163  }
164  else if(m.y > m.z)
165  {
166  // Y
167  if(d.y > 0)
168  {
169  face= 2;
170  sm= d.x / m.y;
171  tm= d.z / m.y;
172  }
173  else
174  {
175  face= 3;
176  sm= d.x / m.y;
177  tm= -d.z / m.y;
178  }
179  }
180  else
181  {
182  // Z
183  if(d.z > 0)
184  {
185  face= 4;
186  sm= d.x / m.z;
187  tm= -d.y / m.z;
188  }
189  else
190  {
191  face= 5;
192  sm= -d.x / m.z;
193  tm= -d.y / m.z;
194  }
195  }
196 
197  assert(face != -1);
198  float s= (sm +1) / 2;
199  float t= (tm +1) / 2;
200  return m_faces[face].texture(s, t);
201  }
202 
203  // mapping direction vers pixel [0 .. w]x[0 .. h]
204  Vector envmap_pixel( const Vector& d ) { Vector texel= envmap_texel(d); return Vector(texel.x, texel.y * m_width, texel.z * m_width); }
205 
206  // mapping direction vers texel [0 .. 1]x[0 .. 1]
207  Vector envmap_texel( const Vector& d )
208  {
209  float sm, tm;
210  int face= -1;
211  Vector m= Vector(std::abs(d.x), std::abs(d.y), std::abs(d.z));
212  if(m.x > m.y && m.x > m.z)
213  {
214  // X
215  if(d.x > 0)
216  {
217  face= 0;
218  sm= -d.z / m.x;
219  tm= -d.y / m.x;
220  }
221  else
222  {
223  face= 1;
224  sm= d.z / m.x;
225  tm= -d.y / m.x;
226  }
227  }
228  else if(m.y > m.z)
229  {
230  // Y
231  if(d.y > 0)
232  {
233  face= 2;
234  sm= d.x / m.y;
235  tm= d.z / m.y;
236  }
237  else
238  {
239  face= 3;
240  sm= d.x / m.y;
241  tm= -d.z / m.y;
242  }
243  }
244  else
245  {
246  // Z
247  if(d.z > 0)
248  {
249  face= 4;
250  sm= d.x / m.z;
251  tm= -d.y / m.z;
252  }
253  else
254  {
255  face= 5;
256  sm= -d.x / m.z;
257  tm= -d.y / m.z;
258  }
259  }
260 
261  assert(face != -1);
262  float s= (sm +1) / 2;
263  float t= (tm +1) / 2;
264  return Vector(face, s, t);
265  }
266 
267  // mapping texel vers direction
268  Vector envmap_pixel_direction( const Vector& d ) { return envmap_texel_direction(int(d.x), d.y / m_width, d.z / m_width); }
269 
270  Vector envmap_texel_direction( const Vector& d ) { return envmap_texel_direction(int(d.x), d.y, d.z); }
271 
272  Vector envmap_texel_direction( const int face, const float s, const float t )
273  {
274  // retrouve le point sur le cube [-1 .. 1]
275  float sm= 2 * s -1;
276  float tm= 2 * t -1;
277  if(face == 0)
278  {
279  // X+
280  // sm= -d.z / m.x;
281  // tm= -d.y / m.x;
282  return Vector(1, -tm, -sm);
283  }
284  else if(face == 1)
285  {
286  // X-
287  // sm= d.z / m.x;
288  // tm= -d.y / m.x;
289  return Vector(-1, -tm, sm);
290  }
291  else if(face == 2)
292  {
293  // Y+
294  // sm= d.x / m.y;
295  // tm= d.z / m.y;
296  return Vector(sm, 1, tm);
297  }
298  else if(face == 3)
299  {
300  // Y-
301  // sm= d.x / m.y;
302  // tm= -d.z / m.y;
303  return Vector(sm, -1, -tm);
304  }
305  else if(face == 4)
306  {
307  // Z+
308  // sm= d.x / m.z;
309  // tm= -d.y / m.z;
310  return Vector(sm, -tm, 1);
311  }
312  else // if(face == 5)
313  {
314  // Z-
315  // sm= -d.x / m.z;
316  // tm= -d.y / m.z;
317  return Vector(-sm, -tm, -1);
318  }
319  }
320 
321 protected:
322  std::array<Image, 6> m_faces;
323  int m_width;
324 };
325 
327 Envmap read_cubemap( const char *filename );
329 Envmap read_cubemap_faces( const std::array<const char *, 6>& filenames );
331 Envmap read_cubemap_faces( const char *prefix );
332 
334 int write_cubemap( const Envmap& envmap, const char *filename );
336 int write_cubemap_faces( const Envmap& envmap, const char *prefix );
337 
338 
339 #endif
340 
representation d'une image.
Definition: image.h:21
int height() const
renvoie la hauteur de l'image.
Definition: image.h:100
int width() const
renvoie la largeur de l'image.
Definition: image.h:98
Image flipY(const Image &image)
retourne l'image
Definition: image_io.cpp:295
Image flipX(const Image &image)
retourne l'image
Definition: image_io.cpp:312
Image copy(const Image &image, const int xmin, const int ymin, const int width, const int height)
renvoie un bloc de l'image
Definition: image_io.cpp:328
representation d'une couleur (rgba) transparente ou opaque.
Definition: color.h:14
representation d'une cubemap / envmap.
Definition: envmap.h:13
Envmap(const Image &image)
extrait les 6 faces d'une image.
Definition: envmap.h:23
int height() const
hauteur d'une face.
Definition: envmap.h:59
Color texture(const Vector &d) const
renvoie la couleur de la cubemap dans la direction d, utilise les memes conventions qu'openGL / Rende...
Definition: envmap.h:140
Image cross() const
renvoie une image contenant les 6 faces de la cubemap.
Definition: envmap.h:85
Envmap(const std::array< Image, 6 > &faces)
utilise les 6 faces.
Definition: envmap.h:47
std::array< Image, 6 > faces() const
renvoie les 6 faces de la cubemap.
Definition: envmap.h:117
void linear(const float gamma=2.2f)
applique une correction gamma inverse aux donnees de la cubemap.
Definition: envmap.h:63
bool empty() const
renvoie vrai si la cubemap est initialisee.
Definition: envmap.h:60
int width() const
largeur d'une face.
Definition: envmap.h:58
void gamma(const float gamma=2.2f)
applique une correction gamma aux donnees de la cubemap.
Definition: envmap.h:74
representation d'un vecteur 3d.
Definition: vec.h:59
GLuint read_cubemap(const int unit, const char *filename, const GLenum texel_type=GL_RGBA)
charge une image, decoupe les 6 faces et renvoie une texture cubemap.