improve cubemap bilinear sampling
We now handle all face corners correctly and follow the OpenGL recommandation of averaging the corners of all 3 adjacent faces.
This commit is contained in:
committed by
Mathias Agopian
parent
86b8a97389
commit
4764eefafc
@@ -96,37 +96,80 @@ Cubemap::Address Cubemap::getAddressFor(const double3& r) {
|
||||
*/
|
||||
void Cubemap::makeSeamless() {
|
||||
size_t dim = getDimensions();
|
||||
auto stitch = [ & ](void* dst, size_t incDst, void const* src, ssize_t incSrc) {
|
||||
for (size_t i = 0; i < dim; ++i) {
|
||||
*(Texel*)dst = *(Texel*)src;
|
||||
dst = ((uint8_t*)dst + incDst);
|
||||
src = ((uint8_t*)src + incSrc);
|
||||
}
|
||||
};
|
||||
size_t D = dim;
|
||||
|
||||
// here we assume that all faces share the same underlying image
|
||||
const size_t bpr = getImageForFace(Face::NX).getBytesPerRow();
|
||||
const size_t bpp = getImageForFace(Face::NX).getBytesPerPixel();
|
||||
|
||||
stitch(getImageForFace(Face::NX).getPixelRef(0, dim), bpp,
|
||||
getImageForFace(Face::NY).getPixelRef(0, dim - 1), -bpr);
|
||||
auto getTexel = [](Image& image, ssize_t x, ssize_t y) -> Texel* {
|
||||
return (Texel*)((uint8_t*)image.getData() + x * image.getBytesPerPixel() + y * image.getBytesPerRow());
|
||||
};
|
||||
|
||||
stitch(getImageForFace(Face::PY).getPixelRef(dim, 0), bpr,
|
||||
getImageForFace(Face::PX).getPixelRef(dim - 1, 0), -bpp);
|
||||
auto stitch = [ & ](
|
||||
Face faceDst, ssize_t xdst, ssize_t ydst, size_t incDst,
|
||||
Face faceSrc, size_t xsrc, size_t ysrc, ssize_t incSrc) {
|
||||
Image& imageDst = getImageForFace(faceDst);
|
||||
Image& imageSrc = getImageForFace(faceSrc);
|
||||
Texel* dst = getTexel(imageDst, xdst, ydst);
|
||||
Texel* src = getTexel(imageSrc, xsrc, ysrc);
|
||||
for (size_t i = 0; i < dim; ++i) {
|
||||
*dst = *src;
|
||||
dst = (Texel*)((uint8_t*)dst + incDst);
|
||||
src = (Texel*)((uint8_t*)src + incSrc);
|
||||
}
|
||||
};
|
||||
|
||||
stitch(getImageForFace(Face::PX).getPixelRef(0, dim), bpp,
|
||||
getImageForFace(Face::NY).getPixelRef(dim - 1, 0), bpr);
|
||||
auto corners = [ & ](Face face) {
|
||||
size_t L = D - 1;
|
||||
Image& image = getImageForFace(face);
|
||||
*getTexel(image, -1, -1) = (*getTexel(image, 0, 0) + *getTexel(image, -1, 0) + *getTexel(image, 0, -1)) / 3;
|
||||
*getTexel(image, L+1, -1) = (*getTexel(image, L, 0) + *getTexel(image, L+1, 0) + *getTexel(image, 0, -1)) / 3;
|
||||
*getTexel(image, -1, L+1) = (*getTexel(image, 0, L) + *getTexel(image, -1, 0) + *getTexel(image, 0, L+1)) / 3;
|
||||
*getTexel(image, L+1,L+1) = (*getTexel(image, L, L) + *getTexel(image, L+1, 0) + *getTexel(image, 0, L+1)) / 3;
|
||||
};
|
||||
|
||||
stitch(getImageForFace(Face::NY).getPixelRef(dim, 0), bpr,
|
||||
getImageForFace(Face::PX).getPixelRef(0, dim - 1), bpp);
|
||||
// +Y / Top
|
||||
stitch( Face::PY, -1, 0, bpr, Face::NX, 0, 0, bpp); // left
|
||||
stitch( Face::PY, 0, -1, bpp, Face::NZ, D-1, 0, -bpp); // top
|
||||
stitch( Face::PY, D, 0, bpr, Face::PX, D-1, 0, -bpp); // right
|
||||
stitch( Face::PY, 0, D, bpp, Face::PZ, 0, 0, bpp); // bottom
|
||||
corners(Face::PY);
|
||||
|
||||
stitch(getImageForFace(Face::NZ).getPixelRef(0, dim), bpp,
|
||||
getImageForFace(Face::NY).getPixelRef(dim - 1, dim - 1), -bpp);
|
||||
// -X / Left
|
||||
stitch( Face::NX, -1, 0, bpr, Face::NZ, D-1, 0, bpr); // left
|
||||
stitch( Face::NX, 0, -1, bpp, Face::PY, 0, 0, bpr); // top
|
||||
stitch( Face::NX, D, 0, bpr, Face::PZ, 0, 0, bpr); // right
|
||||
stitch( Face::NX, 0, D, bpp, Face::NY, 0, D-1, -bpr); // bottom
|
||||
corners(Face::NX);
|
||||
|
||||
stitch(getImageForFace(Face::NZ).getPixelRef(dim, 0), bpr,
|
||||
getImageForFace(Face::NX).getPixelRef(0, 0), bpr);
|
||||
// +Z / Front
|
||||
stitch( Face::PZ, -1, 0, bpr, Face::NX, D-1, 0, bpr); // left
|
||||
stitch( Face::PZ, 0, -1, bpp, Face::PY, 0, D-1, bpp); // top
|
||||
stitch( Face::PZ, D, 0, bpr, Face::PX, 0, 0, bpr); // right
|
||||
stitch( Face::PZ, 0, D, bpp, Face::NY, 0, 0, bpp); // bottom
|
||||
corners(Face::PZ);
|
||||
|
||||
stitch(getImageForFace(Face::NY).getPixelRef(0, dim), bpp,
|
||||
getImageForFace(Face::NZ).getPixelRef(dim - 1, dim - 1), -bpp);
|
||||
// +X / Right
|
||||
stitch( Face::PX, -1, 0, bpr, Face::PZ, D-1, 0, bpr); // left
|
||||
stitch( Face::PX, 0, -1, bpp, Face::PY, D-1, D-1, -bpr); // top
|
||||
stitch( Face::PX, D, 0, bpr, Face::NZ, 0, 0, bpr); // right
|
||||
stitch( Face::PX, 0, D, bpp, Face::NY, D-1, 0, bpr); // bottom
|
||||
corners(Face::PX);
|
||||
|
||||
// -Z / Back
|
||||
stitch( Face::NZ, -1, 0, bpr, Face::PX, D-1, 0, bpr); // left
|
||||
stitch( Face::NZ, 0, -1, bpp, Face::PY, D-1, 0, -bpp); // top
|
||||
stitch( Face::NZ, D, 0, bpr, Face::NX, 0, 0, bpr); // right
|
||||
stitch( Face::NZ, 0, D, bpp, Face::NY, D-1, 0, -bpp); // bottom
|
||||
corners(Face::NZ);
|
||||
|
||||
// -Y / Bottom
|
||||
stitch( Face::NY, -1, 0, bpr, Face::NX, D-1, D-1, -bpp); // left
|
||||
stitch( Face::NY, 0, -1, bpp, Face::PZ, 0, D-1, bpp); // top
|
||||
stitch( Face::NY, D, 0, bpr, Face::PX, 0, D-1, bpp); // right
|
||||
stitch( Face::NY, 0, D, bpp, Face::NZ, D-1, D-1, -bpp); // bottom
|
||||
corners(Face::NY);
|
||||
}
|
||||
|
||||
Cubemap::Texel Cubemap::filterAt(const Image& image, double x, double y) {
|
||||
|
||||
@@ -167,7 +167,7 @@ void CubemapUtils::downsampleCubemapLevelBoxFilter(Cubemap& dst, const Cubemap&
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
void CubemapUtils::setFaceFromCross(Cubemap& cm, Cubemap::Face face, const Image& image) {
|
||||
size_t dim = cm.getDimensions();
|
||||
size_t dim = cm.getDimensions() + 2; // 2 extra per image, for seemlessness
|
||||
size_t x = 0;
|
||||
size_t y = 0;
|
||||
switch (face) {
|
||||
@@ -191,7 +191,7 @@ void CubemapUtils::setFaceFromCross(Cubemap& cm, Cubemap::Face face, const Image
|
||||
break;
|
||||
}
|
||||
Image subImage;
|
||||
subImage.subset(image, x, y, dim, dim);
|
||||
subImage.subset(image, x + 1, y + 1, dim, dim);
|
||||
cm.setImageForFace(face, subImage);
|
||||
}
|
||||
|
||||
@@ -205,16 +205,16 @@ void CubemapUtils::setAllFacesFromCross(Cubemap& cm, const Image& image) {
|
||||
}
|
||||
|
||||
Image CubemapUtils::createCubemapImage(size_t dim, bool horizontal) {
|
||||
size_t width = 4 * dim;
|
||||
size_t height = 3 * dim;
|
||||
size_t width = 4 * (dim + 2);
|
||||
size_t height = 3 * (dim + 2);
|
||||
if (!horizontal) {
|
||||
std::swap(width, height);
|
||||
}
|
||||
|
||||
// always allocate an extra column and row, to allow the cubemap to be "seamless"
|
||||
size_t bpr = (width + 1) * sizeof(Cubemap::Texel);
|
||||
size_t bpr = width * sizeof(Cubemap::Texel);
|
||||
bpr = (bpr + 31) & ~31;
|
||||
size_t bufSize = bpr * (height + 1);
|
||||
size_t bufSize = bpr * height;
|
||||
std::unique_ptr<uint8_t[]> data(new uint8_t[bufSize]);
|
||||
memset(data.get(), 0, bufSize);
|
||||
Image image(std::move(data), width, height, bpr, sizeof(Cubemap::Texel));
|
||||
|
||||
Reference in New Issue
Block a user