mirror of
https://github.com/bkaradzic/bimg.git
synced 2026-02-17 20:52:38 +01:00
Added equirectangular projection conversion to cubemap.
This commit is contained in:
@@ -601,6 +601,14 @@ namespace bimg
|
||||
, ImageMip& _mip
|
||||
);
|
||||
|
||||
///
|
||||
ImageContainer* imageCubemapFromLatLongRgba32F(
|
||||
bx::AllocatorI* _allocator
|
||||
, const ImageContainer& _input
|
||||
, bool _useBilinearInterpolation
|
||||
, bx::Error* _err
|
||||
);
|
||||
|
||||
} // namespace bimg
|
||||
|
||||
#endif // BIMG_IMAGE_H_HEADER_GUARD
|
||||
|
||||
190
src/image.cpp
190
src/image.cpp
@@ -3759,4 +3759,194 @@ namespace bimg
|
||||
return total;
|
||||
}
|
||||
|
||||
// +----------+
|
||||
// |-z 2|
|
||||
// | ^ +y |
|
||||
// | | |
|
||||
// | +---->+x |
|
||||
// +----------+----------+----------+----------+
|
||||
// |+y 1|+y 4|+y 0|+y 5|
|
||||
// | ^ -x | ^ +z | ^ +x | ^ -z |
|
||||
// | | | | | | | | |
|
||||
// | +---->+z | +---->+x | +---->-z | +---->-x |
|
||||
// +----------+----------+----------+----------+
|
||||
// |+z 3|
|
||||
// | ^ -y |
|
||||
// | | |
|
||||
// | +---->+x |
|
||||
// +----------+
|
||||
//
|
||||
struct CubeMapFace
|
||||
{
|
||||
float uv[3][3];
|
||||
};
|
||||
|
||||
static const CubeMapFace s_cubeMapFace[] =
|
||||
{
|
||||
{{ // +x face
|
||||
{ 0.0f, 0.0f, -1.0f }, // u -> -z
|
||||
{ 0.0f, -1.0f, 0.0f }, // v -> -y
|
||||
{ 1.0f, 0.0f, 0.0f }, // +x face
|
||||
}},
|
||||
{{ // -x face
|
||||
{ 0.0f, 0.0f, 1.0f }, // u -> +z
|
||||
{ 0.0f, -1.0f, 0.0f }, // v -> -y
|
||||
{ -1.0f, 0.0f, 0.0f }, // -x face
|
||||
}},
|
||||
{{ // +y face
|
||||
{ 1.0f, 0.0f, 0.0f }, // u -> +x
|
||||
{ 0.0f, 0.0f, 1.0f }, // v -> +z
|
||||
{ 0.0f, 1.0f, 0.0f }, // +y face
|
||||
}},
|
||||
{{ // -y face
|
||||
{ 1.0f, 0.0f, 0.0f }, // u -> +x
|
||||
{ 0.0f, 0.0f, -1.0f }, // v -> -z
|
||||
{ 0.0f, -1.0f, 0.0f }, // -y face
|
||||
}},
|
||||
{{ // +z face
|
||||
{ 1.0f, 0.0f, 0.0f }, // u -> +x
|
||||
{ 0.0f, -1.0f, 0.0f }, // v -> -y
|
||||
{ 0.0f, 0.0f, 1.0f }, // +z face
|
||||
}},
|
||||
{{ // -z face
|
||||
{ -1.0f, 0.0f, 0.0f }, // u -> -x
|
||||
{ 0.0f, -1.0f, 0.0f }, // v -> -y
|
||||
{ 0.0f, 0.0f, -1.0f }, // -z face
|
||||
}},
|
||||
};
|
||||
|
||||
/// _u and _v should be center addressing and in [-1.0+invSize..1.0-invSize] range.
|
||||
void texelUvToDir(float* _result, uint8_t _side, float _u, float _v)
|
||||
{
|
||||
const CubeMapFace& face = s_cubeMapFace[_side];
|
||||
|
||||
float tmp[3];
|
||||
tmp[0] = face.uv[0][0] * _u + face.uv[1][0] * _v + face.uv[2][0];
|
||||
tmp[1] = face.uv[0][1] * _u + face.uv[1][1] * _v + face.uv[2][1];
|
||||
tmp[2] = face.uv[0][2] * _u + face.uv[1][2] * _v + face.uv[2][2];
|
||||
bx::vec3Norm(_result, tmp);
|
||||
}
|
||||
|
||||
void latLongFromDir(float* _outU, float* _outV, const float* _in)
|
||||
{
|
||||
const float phi = bx::fatan2(_in[0], _in[2]);
|
||||
const float theta = bx::facos(_in[1]);
|
||||
|
||||
*_outU = (bx::kPi + phi)/bx::kPi2;
|
||||
*_outV = theta*bx::kInvPi;
|
||||
}
|
||||
|
||||
ImageContainer* imageCubemapFromLatLongRgba32F(bx::AllocatorI* _allocator, const ImageContainer& _input, bool _useBilinearInterpolation, bx::Error* _err)
|
||||
{
|
||||
BX_ERROR_SCOPE(_err);
|
||||
|
||||
if (_input.m_depth != 1
|
||||
&& _input.m_numLayers != 1
|
||||
&& _input.m_format != TextureFormat::RGBA32F
|
||||
&& _input.m_width/2 != _input.m_height)
|
||||
{
|
||||
BX_ERROR_SET(_err, BIMG_ERROR, "Input image format is not equirectangular projection.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const uint32_t srcWidthMinusOne = _input.m_width-1;
|
||||
const uint32_t srcHeightMinusOne = _input.m_height-1;
|
||||
const uint32_t srcPitch = _input.m_width*16;
|
||||
const uint32_t dstWidth = _input.m_height/2;
|
||||
const uint32_t dstPitch = dstWidth*16;
|
||||
const float invDstWidth = 1.0f / float(dstWidth);
|
||||
|
||||
ImageContainer* output = imageAlloc(_allocator
|
||||
, _input.m_format
|
||||
, uint16_t(dstWidth)
|
||||
, uint16_t(dstWidth)
|
||||
, uint16_t(1)
|
||||
, 1
|
||||
, true
|
||||
, false
|
||||
);
|
||||
|
||||
const uint8_t* srcData = (const uint8_t*)_input.m_data;
|
||||
|
||||
for (uint8_t side = 0; side < 6 && _err->isOk(); ++side)
|
||||
{
|
||||
ImageMip mip;
|
||||
imageGetRawData(*output, side, 0, output->m_data, output->m_size, mip);
|
||||
|
||||
for (uint32_t yy = 0; yy < dstWidth; ++yy)
|
||||
{
|
||||
for (uint32_t xx = 0; xx < dstWidth; ++xx)
|
||||
{
|
||||
float* dstData = (float*)&mip.m_data[yy*dstPitch+xx*16];
|
||||
|
||||
const float uu = 2.0f*xx*invDstWidth - 1.0f;
|
||||
const float vv = 2.0f*yy*invDstWidth - 1.0f;
|
||||
|
||||
float dir[3];
|
||||
texelUvToDir(dir, side, uu, vv);
|
||||
|
||||
float srcU, srcV;
|
||||
latLongFromDir(&srcU, &srcV, dir);
|
||||
|
||||
srcU *= srcWidthMinusOne;
|
||||
srcV *= srcHeightMinusOne;
|
||||
|
||||
if (_useBilinearInterpolation)
|
||||
{
|
||||
const uint32_t x0 = uint32_t(srcU);
|
||||
const uint32_t y0 = uint32_t(srcV);
|
||||
const uint32_t x1 = bx::min(x0 + 1, srcWidthMinusOne);
|
||||
const uint32_t y1 = bx::min(y0 + 1, srcHeightMinusOne);
|
||||
|
||||
const float* src0 = (const float*)&srcData[y0*srcPitch + x0*16];
|
||||
const float* src1 = (const float*)&srcData[y0*srcPitch + x1*16];
|
||||
const float* src2 = (const float*)&srcData[y1*srcPitch + x0*16];
|
||||
const float* src3 = (const float*)&srcData[y1*srcPitch + x1*16];
|
||||
|
||||
const float tx = srcU - float(int32_t(x0) );
|
||||
const float ty = srcV - float(int32_t(y0) );
|
||||
const float omtx = 1.0f - tx;
|
||||
const float omty = 1.0f - ty;
|
||||
|
||||
float p0[4];
|
||||
bx::vec4Mul(p0, src0, omtx*omty);
|
||||
|
||||
float p1[4];
|
||||
bx::vec4Mul(p1, src1, tx*omty);
|
||||
|
||||
float p2[4];
|
||||
bx::vec4Mul(p2, src2, omtx*ty);
|
||||
|
||||
float p3[4];
|
||||
bx::vec4Mul(p3, src3, tx*ty);
|
||||
|
||||
const float rr = p0[0] + p1[0] + p2[0] + p3[0];
|
||||
const float gg = p0[1] + p1[1] + p2[1] + p3[1];
|
||||
const float bb = p0[2] + p1[2] + p2[2] + p3[2];
|
||||
const float aa = p0[3] + p1[3] + p2[3] + p3[3];
|
||||
|
||||
dstData[0] = rr;
|
||||
dstData[1] = gg;
|
||||
dstData[2] = bb;
|
||||
dstData[3] = aa;
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint32_t x0 = uint32_t(srcU);
|
||||
const uint32_t y0 = uint32_t(srcV);
|
||||
const float* src0 = (const float*)&srcData[y0*srcPitch + x0*16];
|
||||
|
||||
dstData[0] = src0[0];
|
||||
dstData[1] = src0[1];
|
||||
dstData[2] = src0[2];
|
||||
dstData[3] = src0[3];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
} // namespace bimg
|
||||
|
||||
@@ -37,6 +37,7 @@ struct Options
|
||||
, quality(bimg::Quality::Default)
|
||||
, mips(false)
|
||||
, normalMap(false)
|
||||
, equirect(false)
|
||||
, iqa(false)
|
||||
, sdf(false)
|
||||
, alphaTest(false)
|
||||
@@ -69,6 +70,7 @@ struct Options
|
||||
bimg::Quality::Enum quality;
|
||||
bool mips;
|
||||
bool normalMap;
|
||||
bool equirect;
|
||||
bool iqa;
|
||||
bool sdf;
|
||||
bool alphaTest;
|
||||
@@ -158,6 +160,7 @@ bimg::ImageContainer* convert(bx::AllocatorI* _allocator, const void* _inputData
|
||||
&& !_options.sdf
|
||||
&& !_options.alphaTest
|
||||
&& !_options.normalMap
|
||||
&& !_options.equirect
|
||||
&& !_options.iqa
|
||||
;
|
||||
|
||||
@@ -201,6 +204,23 @@ bimg::ImageContainer* convert(bx::AllocatorI* _allocator, const void* _inputData
|
||||
return output;
|
||||
}
|
||||
|
||||
if (_options.equirect)
|
||||
{
|
||||
bimg::ImageContainer* src = bimg::imageConvert(_allocator, bimg::TextureFormat::RGBA32F, *input);
|
||||
bimg::imageFree(input);
|
||||
|
||||
bimg::ImageContainer* dst = bimg::imageCubemapFromLatLongRgba32F(_allocator, *src, true, _err);
|
||||
bimg::imageFree(src);
|
||||
|
||||
if (!_err->isOk() )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
input = bimg::imageConvert(_allocator, outputFormat, *dst);
|
||||
bimg::imageFree(dst);
|
||||
}
|
||||
|
||||
output = bimg::imageAlloc(
|
||||
_allocator
|
||||
, outputFormat
|
||||
@@ -630,6 +650,7 @@ void help(const char* _error = NULL, bool _showHelp = true)
|
||||
" -q <quality> Encoding quality (default, fastest, highest).\n"
|
||||
" -m, --mips Generate mip-maps.\n"
|
||||
" -n, --normalmap Input texture is normal map.\n"
|
||||
" --equirect Input texture equirectangular projection of cubemap.\n"
|
||||
" --sdf <edge> Compute SDF texture.\n"
|
||||
" --ref <alpha> Alpha reference value.\n"
|
||||
" --iqa Image Quality Assessment\n"
|
||||
@@ -728,7 +749,8 @@ int main(int _argc, const char* _argv[])
|
||||
|
||||
options.mips = cmdLine.hasArg('m', "mips");
|
||||
options.normalMap = cmdLine.hasArg('n', "normalmap");
|
||||
options.iqa = cmdLine.hasArg('\0', "iqa");
|
||||
options.equirect = cmdLine.hasArg("equirect");
|
||||
options.iqa = cmdLine.hasArg("iqa");
|
||||
|
||||
const char* maxSize = cmdLine.findOption("max");
|
||||
if (NULL != maxSize)
|
||||
|
||||
Reference in New Issue
Block a user