mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-07 19:23:04 +02:00
Working on cubemap seams
This commit is contained in:
parent
4a2323f3c2
commit
5bf3cdd592
4 changed files with 221 additions and 59 deletions
|
@ -15,6 +15,7 @@
|
|||
#include <tbb/blocked_range2d.h>
|
||||
|
||||
#include "RandomAndNoise.h"
|
||||
#include "Image.h"
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265359
|
||||
|
@ -22,14 +23,160 @@
|
|||
|
||||
using namespace image;
|
||||
|
||||
CubeMap::CubeMap(int width, int height, int mipCount) :
|
||||
_width(width), _height(height) {
|
||||
static const glm::vec3 FACE_NORMALS[24] = {
|
||||
// POSITIVE X
|
||||
glm::vec3(1.0f, 1.0f, 1.0f),
|
||||
glm::vec3(1.0f, 1.0f, -1.0f),
|
||||
glm::vec3(1.0f, -1.0f, 1.0f),
|
||||
glm::vec3(1.0f, -1.0f, -1.0f),
|
||||
// NEGATIVE X
|
||||
glm::vec3(-1.0f, 1.0f, -1.0f),
|
||||
glm::vec3(-1.0f, 1.0f, 1.0f),
|
||||
glm::vec3(-1.0f, -1.0f, -1.0f),
|
||||
glm::vec3(-1.0f, -1.0f, 1.0f),
|
||||
// POSITIVE Y
|
||||
glm::vec3(-1.0f, 1.0f, -1.0f),
|
||||
glm::vec3(1.0f, 1.0f, -1.0f),
|
||||
glm::vec3(-1.0f, 1.0f, 1.0f),
|
||||
glm::vec3(1.0f, 1.0f, 1.0f),
|
||||
// NEGATIVE Y
|
||||
glm::vec3(-1.0f, -1.0f, 1.0f),
|
||||
glm::vec3(1.0f, -1.0f, 1.0f),
|
||||
glm::vec3(-1.0f, -1.0f, -1.0f),
|
||||
glm::vec3(1.0f, -1.0f, -1.0f),
|
||||
// POSITIVE Z
|
||||
glm::vec3(-1.0f, 1.0f, 1.0f),
|
||||
glm::vec3(1.0f, 1.0f, 1.0f),
|
||||
glm::vec3(-1.0f, -1.0f, 1.0f),
|
||||
glm::vec3(1.0f, -1.0f, 1.0f),
|
||||
// NEGATIVE Z
|
||||
glm::vec3(1.0f, 1.0f, -1.0f),
|
||||
glm::vec3(-1.0f, 1.0f, -1.0f),
|
||||
glm::vec3(1.0f, -1.0f, -1.0f),
|
||||
glm::vec3(-1.0f, -1.0f, -1.0f)
|
||||
};
|
||||
|
||||
CubeMap::CubeMap(int width, int height, int mipCount) {
|
||||
reset(width, height, mipCount);
|
||||
}
|
||||
|
||||
CubeMap::CubeMap(gpu::TexturePointer texture, const std::atomic<bool>& abortProcessing) {
|
||||
reset(texture->getWidth(), texture->getHeight(), texture->getNumMips());
|
||||
|
||||
const auto srcTextureFormat = texture->getTexelFormat();
|
||||
|
||||
for (gpu::uint16 mipLevel = 0; mipLevel < texture->getNumMips(); ++mipLevel) {
|
||||
auto mipDims = texture->evalMipDimensions(mipLevel);
|
||||
auto destLineStride = getFaceLineStride(mipLevel);
|
||||
|
||||
for (face = 0; face < 6; face++) {
|
||||
auto sourcePixels = texture->accessStoredMipFace(mipLevel, face)->data();
|
||||
auto destPixels = editFace(mipLevel, face);
|
||||
|
||||
convertToFloat(sourcePixels, mipDims.x, mipDims.y, sizeof(uint32)*mipDims.x, srcTextureFormat, destPixels, destLineStride);
|
||||
if (abortProcessing.load()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Now copy edge rows and columns from neighbouring faces to fix
|
||||
// seam filtering issues
|
||||
seamColumnAndRow(mipLevel, gpu::Texture::CUBE_FACE_TOP_POS_Y, mipDims.x, gpu::Texture::CUBE_FACE_RIGHT_POS_X, -1, -1);
|
||||
seamColumnAndRow(mipLevel, gpu::Texture::CUBE_FACE_BOTTOM_NEG_Y, mipDims.x, gpu::Texture::CUBE_FACE_RIGHT_POS_X, mipDims.y, 1);
|
||||
seamColumnAndColumn(mipLevel, gpu::Texture::CUBE_FACE_FRONT_NEG_Z, 0, gpu::Texture::CUBE_FACE_RIGHT_POS_X, mipDims.x, 1);
|
||||
seamColumnAndColumn(mipLevel, gpu::Texture::CUBE_FACE_BACK_POS_Z, mipDims.x, gpu::Texture::CUBE_FACE_RIGHT_POS_X, -1, 1);
|
||||
|
||||
seamRowAndRow(mipLevel, gpu::Texture::CUBE_FACE_BACK_POS_Z, -1, gpu::Texture::CUBE_FACE_TOP_POS_Y, mipDims.y, 1);
|
||||
seamRowAndRow(mipLevel, gpu::Texture::CUBE_FACE_BACK_POS_Z, mipDims.y, gpu::Texture::CUBE_FACE_BOTTOM_NEG_Y, -1, 1);
|
||||
seamColumnAndColumn(mipLevel, gpu::Texture::CUBE_FACE_BACK_POS_Z, -1, gpu::Texture::CUBE_FACE_LEFT_NEG_X, mipDims.x, 1);
|
||||
|
||||
seamRowAndRow(mipLevel, gpu::Texture::CUBE_FACE_TOP_POS_Y, -1, gpu::Texture::CUBE_FACE_FRONT_NEG_Z, -1, -1);
|
||||
seamColumnAndRow(mipLevel, gpu::Texture::CUBE_FACE_TOP_POS_Y, -1, gpu::Texture::CUBE_FACE_LEFT_NEG_X, -1, 1);
|
||||
|
||||
seamColumnAndColumn(mipLevel, gpu::Texture::CUBE_FACE_LEFT_NEG_X, -1, gpu::Texture::CUBE_FACE_FRONT_NEG_Z, mipDims.x, 1);
|
||||
seamColumnAndRow(mipLevel, gpu::Texture::CUBE_FACE_BOTTOM_NEG_Y, -1, gpu::Texture::CUBE_FACE_LEFT_NEG_X, mipDims.y, -1);
|
||||
|
||||
seamRowAndRow(mipLevel, gpu::Texture::CUBE_FACE_FRONT_NEG_Z, mipDims.y, gpu::Texture::CUBE_FACE_BOTTOM_NEG_Y, mipDims.y, -1);
|
||||
|
||||
// Duplicate corner pixels
|
||||
for (face = 0; face < 6; face++) {
|
||||
auto& pixels = _mips[mipLevel][face];
|
||||
|
||||
pixels[0] = pixels[1];
|
||||
pixels[mipDims.x+1] = pixels[mipDims.x];
|
||||
pixels[(mipDims.y+1)*(mipDims.x+2)] = pixels[(mipDims.y+1)*(mipDims.x+2)+1];
|
||||
pixels[(mipDims.y+2)*(mipDims.x+2)-1] = pixels[(mipDims.y+2)*(mipDims.x+2)-2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline static std::pair<int,int> getSrcAndDst(int dim, int value) {
|
||||
int src;
|
||||
int dst;
|
||||
|
||||
if (value < 0) {
|
||||
src = 1;
|
||||
dst = 0;
|
||||
} else if (value >= dim) {
|
||||
src = dim;
|
||||
dst = dim+1;
|
||||
}
|
||||
return std::make_pair(src, dst);
|
||||
}
|
||||
|
||||
void CubeMap::seamColumnAndColumn(gpu::uint16 mipLevel, int face0, int col0, int face1, int col1, int inc) {
|
||||
auto mipDims = getMipDimensions(mipLevel);
|
||||
auto coords0 = getSrcAndDst(mipDims.x, col0);
|
||||
auto coords1 = getSrcAndDst(mipDims.x, col1);
|
||||
|
||||
copyColumnToColumn(mipLevel, face0, coords0.first, face1, coords1.second, inc);
|
||||
copyColumnToColumn(mipLevel, face1, coords1.first, face0, coords0.second, inc);
|
||||
}
|
||||
|
||||
void CubeMap::seamColumnAndRow(gpu::uint16 mipLevel, int face0, int col0, int face1, int row1, int inc) {
|
||||
auto mipDims = getMipDimensions(mipLevel);
|
||||
auto coords0 = getSrcAndDst(mipDims.x, col0);
|
||||
auto coords1 = getSrcAndDst(mipDims.y, row1);
|
||||
|
||||
copyColumnToRow(mipLevel, face0, coords0.first, face1, coords1.second, inc);
|
||||
copyRowToColumn(mipLevel, face1, coords1.first, face0, coords0.second, inc);
|
||||
}
|
||||
|
||||
void CubeMap::seamRowAndRow(gpu::uint16 mipLevel, int face0, int row0, int face1, int row1, int inc) {
|
||||
auto mipDims = getMipDimensions(mipLevel);
|
||||
auto coords0 = getSrcAndDst(mipDims.y, row0);
|
||||
auto coords1 = getSrcAndDst(mipDims.y, row1);
|
||||
|
||||
copyRowToRow(mipLevel, face0, coords0.first, face1, coords1.second, inc);
|
||||
copyRowToRow(mipLevel, face1, coords1.first, face0, coords0.second, inc);
|
||||
}
|
||||
|
||||
void CubeMap::copyColumnToColumn(gpu::uint16 mipLevel, int srcFace, int srcCol, int dstFace, int dstCol, int dstInc) {
|
||||
|
||||
}
|
||||
|
||||
void CubeMap::copyRowToRow(gpu::uint16 mipLevel, int srcFace, int srcRow, int dstFace, int dstRow, int dstInc) {
|
||||
|
||||
}
|
||||
|
||||
void CubeMap::copyColumnToRow(gpu::uint16 mipLevel, int srcFace, int srcCol, int dstFace, int dstRow, int dstInc) {
|
||||
|
||||
}
|
||||
|
||||
void CubeMap::copyRowToColumn(gpu::uint16 mipLevel, int srcFace, int srcRow, int dstFace, int dstCol, int dstInc) {
|
||||
|
||||
}
|
||||
|
||||
void CubeMap::reset(int width, int height, int mipCount) {
|
||||
assert(mipCount >0 && _width > 0 && _height > 0);
|
||||
_width = width;
|
||||
_height = height;
|
||||
_mips.resize(mipCount);
|
||||
for (auto mipLevel = 0; mipLevel < mipCount; mipLevel++) {
|
||||
auto mipWidth = std::max(1, width >> mipLevel);
|
||||
auto mipHeight = std::max(1, height >> mipLevel);
|
||||
auto mipPixelCount = mipWidth * mipHeight;
|
||||
auto mipDimensions = getMipDimensions(mipLevel);
|
||||
// Add extra pixels on edges to perform edge seam fixup (we will duplicate pixels from
|
||||
// neighbouring faces)
|
||||
auto mipPixelCount = (mipDimensions.x+2) * (mipDimensions.y+2);
|
||||
|
||||
for (auto& face : _mips[mipLevel]) {
|
||||
face.resize(mipPixelCount);
|
||||
|
@ -37,6 +184,14 @@ CubeMap::CubeMap(int width, int height, int mipCount) :
|
|||
}
|
||||
}
|
||||
|
||||
glm::vec4* CubeMap::editFace(gpu::uint16 mipLevel, int face) {
|
||||
return _mips[mipLevel][face].data() + 3 + _width;
|
||||
}
|
||||
|
||||
const glm::vec4* CubeMap::getFace(gpu::uint16 mipLevel, int face) const;
|
||||
size_t CubeMap::getFaceLineStride(gpu::uint16 mipLevel) const;
|
||||
|
||||
|
||||
glm::vec4 CubeMap::fetchLod(const glm::vec3& dir, float lod) const {
|
||||
// TODO
|
||||
return glm::vec4(0.0f);
|
||||
|
@ -155,40 +310,7 @@ void CubeMap::convolveForGGX(CubeMap& output, const std::atomic<bool>& abortProc
|
|||
}
|
||||
|
||||
void CubeMap::convolveMipFaceForGGX(const GGXSamples& samples, CubeMap& output, gpu::uint16 mipLevel, int face, const std::atomic<bool>& abortProcessing) const {
|
||||
static const glm::vec3 NORMALS[24] = {
|
||||
// POSITIVE X
|
||||
glm::vec3(1.0f, 1.0f, 1.0f),
|
||||
glm::vec3(1.0f, 1.0f, -1.0f),
|
||||
glm::vec3(1.0f, -1.0f, 1.0f),
|
||||
glm::vec3(1.0f, -1.0f, -1.0f),
|
||||
// NEGATIVE X
|
||||
glm::vec3(-1.0f, 1.0f, -1.0f),
|
||||
glm::vec3(-1.0f, 1.0f, 1.0f),
|
||||
glm::vec3(-1.0f, -1.0f, -1.0f),
|
||||
glm::vec3(-1.0f, -1.0f, 1.0f),
|
||||
// POSITIVE Y
|
||||
glm::vec3(-1.0f, 1.0f, -1.0f),
|
||||
glm::vec3(1.0f, 1.0f, -1.0f),
|
||||
glm::vec3(-1.0f, 1.0f, 1.0f),
|
||||
glm::vec3(1.0f, 1.0f, 1.0f),
|
||||
// NEGATIVE Y
|
||||
glm::vec3(-1.0f, -1.0f, 1.0f),
|
||||
glm::vec3(1.0f, -1.0f, 1.0f),
|
||||
glm::vec3(-1.0f, -1.0f, -1.0f),
|
||||
glm::vec3(1.0f, -1.0f, -1.0f),
|
||||
// POSITIVE Z
|
||||
glm::vec3(-1.0f, 1.0f, 1.0f),
|
||||
glm::vec3(1.0f, 1.0f, 1.0f),
|
||||
glm::vec3(-1.0f, -1.0f, 1.0f),
|
||||
glm::vec3(1.0f, -1.0f, 1.0f),
|
||||
// NEGATIVE Z
|
||||
glm::vec3(1.0f, 1.0f, -1.0f),
|
||||
glm::vec3(-1.0f, 1.0f, -1.0f),
|
||||
glm::vec3(1.0f, -1.0f, -1.0f),
|
||||
glm::vec3(-1.0f, -1.0f, -1.0f)
|
||||
};
|
||||
|
||||
const glm::vec3* faceNormals = NORMALS + face * 4;
|
||||
const glm::vec3* faceNormals = FACE_NORMALS + face * 4;
|
||||
const glm::vec3 deltaXNormalLo = faceNormals[1] - faceNormals[0];
|
||||
const glm::vec3 deltaXNormalHi = faceNormals[3] - faceNormals[2];
|
||||
auto& outputFace = output._mips[mipLevel][face];
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#ifndef hifi_image_CubeMap_h
|
||||
#define hifi_image_CubeMap_h
|
||||
|
||||
#include <gpu/Forward.h>
|
||||
#include <gpu/Texture.h>
|
||||
#include <glm/vec4.hpp>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
@ -22,15 +22,34 @@ namespace image {
|
|||
|
||||
class CubeMap {
|
||||
public:
|
||||
|
||||
using Face = std::vector<glm::vec4>;
|
||||
using Faces = std::array<Face, 6>;
|
||||
|
||||
|
||||
CubeMap(int width, int height, int mipCount);
|
||||
CubeMap(gpu::TexturePointer texture, const std::atomic<bool>& abortProcessing = false);
|
||||
|
||||
void reset(int width, int height, int mipCount);
|
||||
|
||||
gpu::uint16 getMipCount() const { return (gpu::uint16)_mips.size(); }
|
||||
Faces& editMip(gpu::uint16 mipLevel) { return _mips[mipLevel]; }
|
||||
const Faces& getMip(gpu::uint16 mipLevel) const { return _mips[mipLevel]; }
|
||||
int getMipWidth(gpu::uint16 mipLevel) const {
|
||||
return std::max(1, _width >> mipLevel);
|
||||
}
|
||||
int getMipHeight(gpu::uint16 mipLevel) const {
|
||||
return std::max(1, _height >> mipLevel);
|
||||
}
|
||||
gpu::Vec2i getMipDimensions(gpu::uint16 mipLevel) const {
|
||||
return gpu::Vec2i(getMipWidth(mipLevel), getMipHeight(mipLevel));
|
||||
}
|
||||
|
||||
glm::vec4* editFace(gpu::uint16 mipLevel, int face) {
|
||||
return _mips[mipLevel][face].data() + getFaceLineStride(mipLevel) + 1;
|
||||
}
|
||||
|
||||
const glm::vec4* getFace(gpu::uint16 mipLevel, int face) const {
|
||||
return _mips[mipLevel][face].data() + getFaceLineStride(mipLevel) + 1;
|
||||
}
|
||||
|
||||
size_t getFaceLineStride(gpu::uint16 mipLevel) const {
|
||||
return getMipWidth(mipLevel)+2;
|
||||
}
|
||||
|
||||
void convolveForGGX(CubeMap& output, const std::atomic<bool>& abortProcessing) const;
|
||||
glm::vec4 fetchLod(const glm::vec3& dir, float lod) const;
|
||||
|
@ -39,6 +58,9 @@ namespace image {
|
|||
|
||||
struct GGXSamples;
|
||||
|
||||
using Face = std::vector<glm::vec4>;
|
||||
using Faces = std::array<Face, 6>;
|
||||
|
||||
int _width;
|
||||
int _height;
|
||||
std::vector<Faces> _mips;
|
||||
|
@ -46,6 +68,16 @@ namespace image {
|
|||
static void generateGGXSamples(GGXSamples& data, float roughness, const int resolution);
|
||||
void convolveMipFaceForGGX(const GGXSamples& samples, CubeMap& output, gpu::uint16 mipLevel, int face, const std::atomic<bool>& abortProcessing) const;
|
||||
glm::vec4 computeConvolution(const glm::vec3& normal, const GGXSamples& samples) const;
|
||||
|
||||
void seamColumnAndColumn(gpu::uint16 mipLevel, int face0, int col0, int face1, int col1, int inc);
|
||||
void seamColumnAndRow(gpu::uint16 mipLevel, int face0, int col0, int face1, int row1, int inc);
|
||||
void seamRowAndRow(gpu::uint16 mipLevel, int face0, int row0, int face1, int row1, int inc);
|
||||
|
||||
void copyColumnToColumn(gpu::uint16 mipLevel, int srcFace, int srcCol, int dstFace, int dstCol, int dstInc);
|
||||
void copyColumnToRow(gpu::uint16 mipLevel, int srcFace, int srcCol, int dstFace, int dstRow, int dstInc);
|
||||
void copyRowToRow(gpu::uint16 mipLevel, int srcFace, int srcRow, int dstFace, int dstRow, int dstInc);
|
||||
void copyRowToColumn(gpu::uint16 mipLevel, int srcFace, int srcRow, int dstFace, int dstCol, int dstInc);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -521,14 +521,15 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
void convertToFloat(const unsigned char* source, int width, int height, int lineStride, gpu::Element sourceFormat, std::vector<glm::vec4>& output) {
|
||||
std::vector<glm::vec4>::iterator outputIt;
|
||||
void image::convertToFloat(const unsigned char* source, int width, int height, int srcLineByteStride, gpu::Element sourceFormat,
|
||||
glm::vec4* output, int outputLinePixelStride) {
|
||||
glm::vec4* outputIt;
|
||||
auto unpackFunc = getUnpackingFunction(sourceFormat);
|
||||
|
||||
output.resize(width * height);
|
||||
outputIt = output.begin();
|
||||
outputLinePixelStride -= width;
|
||||
outputIt = output;
|
||||
for (auto lineNb = 0; lineNb < height; lineNb++) {
|
||||
const uint32* srcPixelIt = reinterpret_cast<const uint32*>(source + lineNb * lineStride);
|
||||
const uint32* srcPixelIt = reinterpret_cast<const uint32*>(source + lineNb * srcLineByteStride);
|
||||
const uint32* srcPixelEnd = srcPixelIt + width;
|
||||
|
||||
while (srcPixelIt < srcPixelEnd) {
|
||||
|
@ -536,17 +537,19 @@ void convertToFloat(const unsigned char* source, int width, int height, int line
|
|||
++srcPixelIt;
|
||||
++outputIt;
|
||||
}
|
||||
outputIt += outputLinePixelStride;
|
||||
}
|
||||
assert(outputIt == output.end());
|
||||
}
|
||||
|
||||
void convertFromFloat(unsigned char* output, int width, int height, int lineStride, gpu::Element outputFormat, const std::vector<glm::vec4>& source) {
|
||||
std::vector<glm::vec4>::const_iterator sourceIt;
|
||||
void image::convertFromFloat(unsigned char* output, int width, int height, int outputLineByteStride, gpu::Element outputFormat,
|
||||
const glm::vec4* source, int srcLinePixelStride) {
|
||||
const glm::vec4* sourceIt;
|
||||
auto packFunc = getPackingFunction(outputFormat);
|
||||
|
||||
sourceIt = source.begin();
|
||||
srcLinePixelStride -= width;
|
||||
sourceIt = source;
|
||||
for (auto lineNb = 0; lineNb < height; lineNb++) {
|
||||
uint32* outPixelIt = reinterpret_cast<uint32*>(output + lineNb * lineStride);
|
||||
uint32* outPixelIt = reinterpret_cast<uint32*>(output + lineNb * outputLineByteStride);
|
||||
uint32* outPixelEnd = outPixelIt + width;
|
||||
|
||||
while (outPixelIt < outPixelEnd) {
|
||||
|
@ -554,8 +557,8 @@ void convertFromFloat(unsigned char* output, int width, int height, int lineStri
|
|||
++outPixelIt;
|
||||
++sourceIt;
|
||||
}
|
||||
sourceIt += srcLinePixelStride;
|
||||
}
|
||||
assert(sourceIt == source.end());
|
||||
}
|
||||
|
||||
void generateHDRMips(gpu::Texture* texture, QImage&& image, BackendTarget target, const std::atomic<bool>& abortProcessing, int face) {
|
||||
|
@ -594,7 +597,8 @@ void generateHDRMips(gpu::Texture* texture, QImage&& image, BackendTarget target
|
|||
return;
|
||||
}
|
||||
|
||||
convertToFloat(localCopy.bits(), width, height, localCopy.bytesPerLine(), HDR_FORMAT, data);
|
||||
data.resize(width * height);
|
||||
convertToFloat(localCopy.bits(), width, height, localCopy.bytesPerLine(), HDR_FORMAT, data.data(), width);
|
||||
|
||||
// We're done with the localCopy, free up the memory to avoid bloating the heap
|
||||
localCopy = QImage(); // QImage doesn't have a clear function, so override it with an empty one.
|
||||
|
|
|
@ -27,7 +27,11 @@ extern const QImage::Format QIMAGE_HDRFORMAT;
|
|||
|
||||
std::function<gpu::uint32(const glm::vec3&)> getHDRPackingFunction();
|
||||
std::function<glm::vec3(gpu::uint32)> getHDRUnpackingFunction();
|
||||
|
||||
void convertToFloat(const unsigned char* source, int width, int height, int srcLineByteStride, gpu::Element sourceFormat,
|
||||
glm::vec4* output, int outputLinePixelStride);
|
||||
void convertFromFloat(unsigned char* output, int width, int height, int outputLineByteStride, gpu::Element outputFormat,
|
||||
const glm::vec4* source, int srcLinePixelStride);
|
||||
|
||||
namespace TextureUsage {
|
||||
|
||||
enum Type {
|
||||
|
|
Loading…
Reference in a new issue