1.介绍
将一张全景图片贴在立方体天空盒上,需要uv进行映射,分别对应六个面的纹理;
2.实现
查阅了网上,发现大概有如下几种实现方式;
由于直接需要将数据做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.参考
6. 可执行工程下载
稍后上传