1.介绍

  将一张全景图片贴在立方体天空盒上,需要uv进行映射,分别对应六个面的纹理; 

2.实现

 查阅了网上,发现大概有如下几种实现方式;

* 基于opencv进行分割,  保存出6张图片
* 基于opengl,通过改变LookAt摄像机方向,获取6张texture通过FBO,再通过glreadpixel读回数据进行保存;
由于直接需要将数据做cubmap,所以我实现的方式是:将全景图片分别映射到6块内存,每块内存通过

glTexImage2D()直接送到GPU。

这样使用Cubmap直接渲染,无需再保存以及读取6张图片的过程;

3.代码
void SphereCubeTexture::create_spherecube_texture() { std::thread prc[6]; int
index = _resource_name.rfind("."); if (index == std::string::npos) {
LOG_ERR("invalid cube texture file name"); return; } std::string prefix =
_resource_name.substr(0, index); std::string extend =
_resource_name.substr(index); _texture_data = new
TextureData(GL_TEXTURE_CUBE_MAP, GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE,
GL_CLAMP_TO_EDGE); if (_miplevel) {
_texture_data->set_sample(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE,
GL_CLAMP_TO_EDGE); } int width = 0; int height = 0; int n = 0; unsigned char
*image = nullptr; std::string pic_name; const short face_szie = 6; // pic_name
= prefix + extend; image = stbi_load(pic_name.c_str(), &width, &height, &n); {
for (int lx = 0; lx < face_szie; lx++) { { int sphere_height = height,
sphere_width = width; unsigned char *im = new unsigned char[_tile_size *
_tile_size * n]; for (int tile_y = 0; tile_y < _tile_size; tile_y++) { for (int
tile_x = 0; tile_x < _tile_size; tile_x++) { float theta, phi; std::tie(theta,
phi) = (this->face_func[lx])(*this, tile_y, tile_x); int sp_x =
this->phi2width(sphere_width, phi); int sp_y =
this->theta2height(sphere_height, theta); for (int k = 0; k < 4; ++k) {
im[(_tile_size * tile_y + tile_x) * n + k] = image[(width * sp_y + sp_x) * n +
k]; } } } if (im) { _memory += _tile_size * _tile_size * n;
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + lx, 0, _texture_info.components,
_tile_size, _tile_size, 0, _texture_info.format, _texture_info.type, im);
delete[] im; im = nullptr; } } } set_width(width); set_height(height); }
_available = true; stbi_image_free(image); image = nullptr; return; } float
SphereCubeTexture::update_phi(float phi, int major_dir, int minor_dir, float
major_m, float major_p, float minor_m, float minor_p) const { if (major_dir <
_half_size) { return phi + major_m; } else if (major_dir > _half_size) { return
phi + major_p; } else if (minor_dir < _half_size) { return minor_m; } else {
return minor_p; } } vec2f SphereCubeTexture::func_up(int tile_y, int tile_x) {
float theta = _cache_zp[tile_y][tile_x]; float phi =
_cache_phi[tile_x][tile_y]; phi = update_phi(phi, tile_y, tile_x, pi, 0,
-half_pi, half_pi); return vec2f(theta, phi); } vec2f
SphereCubeTexture::func_front(int tile_y, int tile_x) { float theta =
_cache_xypm[_tile_size - tile_y - 1][_tile_size - tile_x - 1]; float phi =
_cache_phi[tile_x][_tile_size - 1]; phi = update_phi(phi, tile_y, tile_x, 0, 0,
-half_pi, half_pi); return vec2f(theta, phi); } vec2f
SphereCubeTexture::func_right(int tile_y, int tile_x) { float theta, phi;
std::tie(theta, phi) = func_front(tile_y, tile_x); phi += half_pi; if (phi >
doub_pi) { phi -= doub_pi; } return vec2f(theta, phi); } vec2f
SphereCubeTexture::func_back(int tile_y, int tile_x) { float theta, phi;
std::tie(theta, phi) = func_front(tile_y, tile_x); phi += 2 * half_pi; if (phi
> doub_pi) { phi -= doub_pi; } return vec2f(theta, phi); } vec2f
SphereCubeTexture::func_left(int tile_y, int tile_x) { float theta, phi;
std::tie(theta, phi) = func_front(tile_y, tile_x); phi += 3 * half_pi; if (phi
> doub_pi) { phi -= doub_pi; } return vec2f(theta, phi); } vec2f
SphereCubeTexture::func_down(int tile_y, int tile_x) { float theta =
_cache_zm[tile_y][tile_x]; float phi = _cache_phi[tile_x][_tile_size - tile_y -
1]; phi = update_phi(phi, tile_y, tile_x, 0, pi, -half_pi, half_pi); return
vec2f(theta, phi); } float SphereCubeTexture::phi2width(int width, float phi)
const { float x = 0.5 * width * (phi * inv_pi + 1); if (x < 1) { return x +
width; } else if (x > width) { return x - width; } else { return x; } } float
SphereCubeTexture::theta2height(int height, float theta) const { return height
* theta * inv_pi; }
4. 改进

   大量的数据在cpu进行运算,运算量比较大,可以考虑将整个过程放进GPU进行运算;Like this:

  
const float isqrt2 = 0.70710676908493042; vec3 cubify(const in vec3 s) { float
xx2 = s.x * s.x * 2.0; float yy2 = s.y * s.y * 2.0; vec2 v = vec2(xx2 – yy2,
yy2 – xx2); float ii = v.y – 3.0; ii *= ii; float isqrt = -sqrt(ii – 12.0 *
xx2) + 3.0; v = sqrt(v + isqrt); v *= isqrt2; return sign(s) * vec3(v, 1.0); }
vec3 sphere2cube(const in vec3 sphere) { vec3 f = abs(sphere); bool a = f.y >=
f.x && f.y >= f.z; bool b = f.x >= f.z; return a ? cubify(sphere.xzy).xzy : b ?
cubify(sphere.yzx).zxy : cubify(sphere); }
5.参考

* https://stackoverflow.com/questions/2656899/mapping-a-sphere-to-a-cube/#
<https://stackoverflow.com/questions/2656899/mapping-a-sphere-to-a-cube/#>
* http://paulbourke.net/geometry/transformationprojection/
<http://paulbourke.net/geometry/transformationprojection/>
* http://paulbourke.net/miscellaneous/cubemaps/
<http://paulbourke.net/miscellaneous/cubemaps/>
* https://blog.csdn.net/juebai123/article/details/79475937
<https://blog.csdn.net/juebai123/article/details/79475937> 基于修改lookat生成
*
https://github.com/Tomius/ReLoEd/blob/master/src/glsl/engine/cube2sphere.glsl
<https://github.com/Tomius/ReLoEd/blob/master/src/glsl/engine/cube2sphere.glsl> 
* https://github.com/wwtalwtaw/learnopengl/blob/master/cube.vs
<https://github.com/wwtalwtaw/learnopengl/blob/master/cube.vs>
 

6. 可执行工程下载

   稍后上传

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信