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.; 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//mapping-a-sphere-to-a-cube/#
- http://paulbourke.net/geometry/transformationprojection/
- http://paulbourke.net/miscellaneous/cubemaps/
- https://blog.csdn.net/juebai123/article/details/ 基于修改lookat生成
- https://github.com/Tomius/ReLoEd/blob/master/src/glsl/engine/cube2sphere.glsl
- https://github.com/wwtalwtaw/learnopengl/blob/master/cube.vs
6. 可执行工程下载
稍后上传

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/64147.html