mirror of
https://github.com/lubosz/overte.git
synced 2025-04-08 04:42:20 +02:00
Finished convolution code
This commit is contained in:
parent
07ce44cd04
commit
2397d5919f
4 changed files with 340 additions and 155 deletions
|
@ -56,117 +56,231 @@ static const glm::vec3 FACE_NORMALS[24] = {
|
|||
glm::vec3(-1.0f, -1.0f, -1.0f)
|
||||
};
|
||||
|
||||
struct CubeFaceMip {
|
||||
CubeFaceMip(gpu::uint16 level, const CubeMap* cubemap) {
|
||||
_dims = cubemap->getMipDimensions(level);
|
||||
_lineStride = _dims.x + 2;
|
||||
}
|
||||
|
||||
gpu::Vec2i _dims;
|
||||
int _lineStride;
|
||||
};
|
||||
|
||||
class CubeMap::ConstMip : public CubeFaceMip {
|
||||
public:
|
||||
|
||||
ConstMip(gpu::uint16 level, const CubeMap* cubemap) :
|
||||
CubeFaceMip(level, cubemap), _faces(cubemap->_mips[level]) {
|
||||
}
|
||||
|
||||
glm::vec4 fetch(int face, glm::vec2 uv) const {
|
||||
glm::vec2 coordFrac = uv * glm::vec2(_dims) + 0.5f;
|
||||
glm::vec2 coords = glm::floor(coordFrac);
|
||||
|
||||
coordFrac -= coords;
|
||||
|
||||
const auto* pixels = _faces[face].data();
|
||||
gpu::Vec2i loCoords(coords);
|
||||
const int offset = loCoords.x + loCoords.y * _lineStride;
|
||||
glm::vec4 colorLL = pixels[offset];
|
||||
glm::vec4 colorHL = pixels[offset +1 ];
|
||||
glm::vec4 colorLH = pixels[offset + _lineStride];
|
||||
glm::vec4 colorHH = pixels[offset + 1 + _lineStride];
|
||||
|
||||
colorLL += (colorHL - colorLL) * coordFrac.x;
|
||||
colorLH += (colorHH - colorLH) * coordFrac.x;
|
||||
return colorLL + (colorLH - colorLL) * coordFrac.y;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
const Faces& _faces;
|
||||
|
||||
};
|
||||
|
||||
class CubeMap::Mip : public CubeFaceMip {
|
||||
public:
|
||||
|
||||
Mip(gpu::uint16 level, CubeMap* cubemap) :
|
||||
CubeFaceMip(level, cubemap), _faces(cubemap->_mips[level]) {
|
||||
}
|
||||
|
||||
void applySeams() {
|
||||
// Copy edge rows and columns from neighbouring faces to fix seam filtering issues
|
||||
seamColumnAndRow(gpu::Texture::CUBE_FACE_TOP_POS_Y, _dims.x, gpu::Texture::CUBE_FACE_RIGHT_POS_X, -1, -1);
|
||||
seamColumnAndRow(gpu::Texture::CUBE_FACE_BOTTOM_NEG_Y, _dims.x, gpu::Texture::CUBE_FACE_RIGHT_POS_X, _dims.y, 1);
|
||||
seamColumnAndColumn(gpu::Texture::CUBE_FACE_FRONT_NEG_Z, 0, gpu::Texture::CUBE_FACE_RIGHT_POS_X, _dims.x, 1);
|
||||
seamColumnAndColumn(gpu::Texture::CUBE_FACE_BACK_POS_Z, _dims.x, gpu::Texture::CUBE_FACE_RIGHT_POS_X, -1, 1);
|
||||
|
||||
seamRowAndRow(gpu::Texture::CUBE_FACE_BACK_POS_Z, -1, gpu::Texture::CUBE_FACE_TOP_POS_Y, _dims.y, 1);
|
||||
seamRowAndRow(gpu::Texture::CUBE_FACE_BACK_POS_Z, _dims.y, gpu::Texture::CUBE_FACE_BOTTOM_NEG_Y, -1, 1);
|
||||
seamColumnAndColumn(gpu::Texture::CUBE_FACE_BACK_POS_Z, -1, gpu::Texture::CUBE_FACE_LEFT_NEG_X, _dims.x, 1);
|
||||
|
||||
seamRowAndRow(gpu::Texture::CUBE_FACE_TOP_POS_Y, -1, gpu::Texture::CUBE_FACE_FRONT_NEG_Z, -1, -1);
|
||||
seamColumnAndRow(gpu::Texture::CUBE_FACE_TOP_POS_Y, -1, gpu::Texture::CUBE_FACE_LEFT_NEG_X, -1, 1);
|
||||
|
||||
seamColumnAndColumn(gpu::Texture::CUBE_FACE_LEFT_NEG_X, -1, gpu::Texture::CUBE_FACE_FRONT_NEG_Z, _dims.x, 1);
|
||||
seamColumnAndRow(gpu::Texture::CUBE_FACE_BOTTOM_NEG_Y, -1, gpu::Texture::CUBE_FACE_LEFT_NEG_X, _dims.y, -1);
|
||||
|
||||
seamRowAndRow(gpu::Texture::CUBE_FACE_FRONT_NEG_Z, _dims.y, gpu::Texture::CUBE_FACE_BOTTOM_NEG_Y, _dims.y, -1);
|
||||
|
||||
// Duplicate corner pixels
|
||||
for (int face = 0; face < 6; face++) {
|
||||
auto& pixels = _faces[face];
|
||||
|
||||
pixels[0] = pixels[1];
|
||||
pixels[_dims.x + 1] = pixels[_dims.x];
|
||||
pixels[(_dims.y + 1)*(_dims.x + 2)] = pixels[(_dims.y + 1)*(_dims.x + 2) + 1];
|
||||
pixels[(_dims.y + 2)*(_dims.x + 2) - 1] = pixels[(_dims.y + 2)*(_dims.x + 2) - 2];
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Faces& _faces;
|
||||
|
||||
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 seamColumnAndColumn(int face0, int col0, int face1, int col1, int inc) {
|
||||
auto coords0 = getSrcAndDst(_dims.x, col0);
|
||||
auto coords1 = getSrcAndDst(_dims.x, col1);
|
||||
|
||||
copyColumnToColumn(face0, coords0.first, face1, coords1.second, inc);
|
||||
copyColumnToColumn(face1, coords1.first, face0, coords0.second, inc);
|
||||
}
|
||||
|
||||
void seamColumnAndRow(int face0, int col0, int face1, int row1, int inc) {
|
||||
auto coords0 = getSrcAndDst(_dims.x, col0);
|
||||
auto coords1 = getSrcAndDst(_dims.y, row1);
|
||||
|
||||
copyColumnToRow(face0, coords0.first, face1, coords1.second, inc);
|
||||
copyRowToColumn(face1, coords1.first, face0, coords0.second, inc);
|
||||
}
|
||||
|
||||
void seamRowAndRow(int face0, int row0, int face1, int row1, int inc) {
|
||||
auto coords0 = getSrcAndDst(_dims.y, row0);
|
||||
auto coords1 = getSrcAndDst(_dims.y, row1);
|
||||
|
||||
copyRowToRow(face0, coords0.first, face1, coords1.second, inc);
|
||||
copyRowToRow(face1, coords1.first, face0, coords0.second, inc);
|
||||
}
|
||||
|
||||
inline static void copy(const glm::vec4* srcFirst, const glm::vec4* srcLast, int srcStride, glm::vec4* dstBegin, int dstStride) {
|
||||
while (srcFirst <= srcLast) {
|
||||
*dstBegin = *srcFirst;
|
||||
srcFirst += srcStride;
|
||||
dstBegin += dstStride;
|
||||
}
|
||||
}
|
||||
|
||||
void copyColumnToColumn(int srcFace, int srcCol, int dstFace, int dstCol, const int dstInc) {
|
||||
const auto lastOffset = _lineStride * (_dims.y - 1);
|
||||
auto srcFirst = _faces[srcFace].data() + srcCol + _lineStride;
|
||||
auto srcLast = srcFirst + lastOffset;
|
||||
|
||||
auto dstFirst = _faces[dstFace].data() + dstCol + _lineStride;
|
||||
auto dstLast = dstFirst + lastOffset;
|
||||
const auto dstStride = _lineStride * dstInc;
|
||||
|
||||
if (dstInc < 0) {
|
||||
std::swap(dstFirst, dstLast);
|
||||
}
|
||||
|
||||
copy(srcFirst, srcLast, _lineStride, dstFirst, dstStride);
|
||||
}
|
||||
|
||||
void copyRowToRow(int srcFace, int srcRow, int dstFace, int dstRow, const int dstInc) {
|
||||
const auto lastOffset =(_dims.x - 1);
|
||||
auto srcFirst = _faces[srcFace].data() + srcRow * _lineStride + 1;
|
||||
auto srcLast = srcFirst + lastOffset;
|
||||
|
||||
auto dstFirst = _faces[dstFace].data() + dstRow * _lineStride + 1;
|
||||
auto dstLast = dstFirst + lastOffset;
|
||||
|
||||
if (dstInc < 0) {
|
||||
std::swap(dstFirst, dstLast);
|
||||
}
|
||||
|
||||
copy(srcFirst, srcLast, 1, dstFirst, dstInc);
|
||||
}
|
||||
|
||||
void copyColumnToRow(int srcFace, int srcCol, int dstFace, int dstRow, int dstInc) {
|
||||
const auto srcLastOffset = _lineStride * (_dims.y - 1);
|
||||
auto srcFirst = _faces[srcFace].data() + srcCol + _lineStride;
|
||||
auto srcLast = srcFirst + srcLastOffset;
|
||||
|
||||
const auto dstLastOffset = (_dims.x - 1);
|
||||
auto dstFirst = _faces[dstFace].data() + dstRow * _lineStride + 1;
|
||||
auto dstLast = dstFirst + dstLastOffset;
|
||||
|
||||
if (dstInc < 0) {
|
||||
std::swap(dstFirst, dstLast);
|
||||
}
|
||||
|
||||
copy(srcFirst, srcLast, _lineStride, dstFirst, dstInc);
|
||||
}
|
||||
|
||||
void copyRowToColumn(int srcFace, int srcRow, int dstFace, int dstCol, int dstInc) {
|
||||
const auto srcLastOffset = (_dims.x - 1);
|
||||
auto srcFirst = _faces[srcFace].data() + srcRow * _lineStride + 1;
|
||||
auto srcLast = srcFirst + srcLastOffset;
|
||||
|
||||
const auto dstLastOffset = _lineStride * (_dims.y - 1);
|
||||
auto dstFirst = _faces[dstFace].data() + dstCol + _lineStride;
|
||||
auto dstLast = dstFirst + dstLastOffset;
|
||||
const auto dstStride = _lineStride * dstInc;
|
||||
|
||||
if (dstInc < 0) {
|
||||
std::swap(dstFirst, dstLast);
|
||||
}
|
||||
|
||||
copy(srcFirst, srcLast, 1, dstFirst, dstStride);
|
||||
}
|
||||
};
|
||||
|
||||
CubeMap::CubeMap(int width, int height, int mipCount) {
|
||||
reset(width, height, mipCount);
|
||||
}
|
||||
|
||||
CubeMap::CubeMap(gpu::TexturePointer texture, const std::atomic<bool>& abortProcessing) {
|
||||
CubeMap::CubeMap(gpu::Texture* texture, const std::atomic<bool>& abortProcessing) {
|
||||
reset(texture->getWidth(), texture->getHeight(), texture->getNumMips());
|
||||
|
||||
const auto srcTextureFormat = texture->getTexelFormat();
|
||||
int face;
|
||||
|
||||
for (gpu::uint16 mipLevel = 0; mipLevel < texture->getNumMips(); ++mipLevel) {
|
||||
auto mipDims = texture->evalMipDimensions(mipLevel);
|
||||
auto destLineStride = getFaceLineStride(mipLevel);
|
||||
auto srcLineStride = (int) (sizeof(gpu::uint32)*mipDims.x);
|
||||
auto dstLineStride = 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);
|
||||
convertToFloat(sourcePixels, mipDims.x, mipDims.y, srcLineStride, srcTextureFormat, destPixels, dstLineStride);
|
||||
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);
|
||||
Mip mip(mipLevel, this);
|
||||
|
||||
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];
|
||||
}
|
||||
mip.applySeams();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -184,17 +298,123 @@ void CubeMap::reset(int width, int height, int mipCount) {
|
|||
}
|
||||
}
|
||||
|
||||
glm::vec4* CubeMap::editFace(gpu::uint16 mipLevel, int face) {
|
||||
return _mips[mipLevel][face].data() + 3 + _width;
|
||||
void CubeMap::copyTo(gpu::Texture* texture, const std::atomic<bool>& abortProcessing) const {
|
||||
assert(_width == texture->getWidth() && _height == texture->getHeight() && texture->getNumMips() == _mips.size());
|
||||
|
||||
// Convert all mip data back from float
|
||||
unsigned char* convertedPixels = new unsigned char[_width * _height * sizeof(gpu::uint32)];
|
||||
const auto textureFormat = texture->getTexelFormat();
|
||||
|
||||
for (gpu::uint16 mipLevel = 0; mipLevel < texture->getNumMips(); ++mipLevel) {
|
||||
auto mipDims = texture->evalMipDimensions(mipLevel);
|
||||
auto mipSize = texture->evalMipFaceSize(mipLevel);
|
||||
auto srcLineStride = getFaceLineStride(mipLevel);
|
||||
auto dstLineStride = (int)(sizeof(gpu::uint32)*mipDims.x);
|
||||
|
||||
for (auto face = 0; face < 6; face++) {
|
||||
auto srcPixels = getFace(mipLevel, face);
|
||||
|
||||
convertFromFloat(convertedPixels, mipDims.x, mipDims.y, dstLineStride, textureFormat, srcPixels, srcLineStride);
|
||||
texture->assignStoredMipFace(mipLevel, face, mipSize, convertedPixels);
|
||||
if (abortProcessing.load()) {
|
||||
delete[] convertedPixels;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete[] convertedPixels;
|
||||
}
|
||||
|
||||
const glm::vec4* CubeMap::getFace(gpu::uint16 mipLevel, int face) const;
|
||||
size_t CubeMap::getFaceLineStride(gpu::uint16 mipLevel) const;
|
||||
void CubeMap::getFaceUV(const glm::vec3& dir, int* index, glm::vec2* uv) {
|
||||
// Taken from https://en.wikipedia.org/wiki/Cube_mapping
|
||||
float absX = std::abs(dir.x);
|
||||
float absY = std::abs(dir.y);
|
||||
float absZ = std::abs(dir.z);
|
||||
|
||||
auto isXPositive = dir.x > 0;
|
||||
auto isYPositive = dir.y > 0;
|
||||
auto isZPositive = dir.z > 0;
|
||||
|
||||
float maxAxis, uc, vc;
|
||||
|
||||
// POSITIVE X
|
||||
if (isXPositive && absX >= absY && absX >= absZ) {
|
||||
// u (0 to 1) goes from +z to -z
|
||||
// v (0 to 1) goes from -y to +y
|
||||
maxAxis = absX;
|
||||
uc = -dir.z;
|
||||
vc = -dir.y;
|
||||
*index = 0;
|
||||
}
|
||||
// NEGATIVE X
|
||||
else if (!isXPositive && absX >= absY && absX >= absZ) {
|
||||
// u (0 to 1) goes from -z to +z
|
||||
// v (0 to 1) goes from -y to +y
|
||||
maxAxis = absX;
|
||||
uc = dir.z;
|
||||
vc = -dir.y;
|
||||
*index = 1;
|
||||
}
|
||||
// POSITIVE Y
|
||||
else if (isYPositive && absY >= absX && absY >= absZ) {
|
||||
// u (0 to 1) goes from -x to +x
|
||||
// v (0 to 1) goes from +z to -z
|
||||
maxAxis = absY;
|
||||
uc = dir.x;
|
||||
vc = dir.z;
|
||||
*index = 2;
|
||||
}
|
||||
// NEGATIVE Y
|
||||
else if (!isYPositive && absY >= absX && absY >= absZ) {
|
||||
// u (0 to 1) goes from -x to +x
|
||||
// v (0 to 1) goes from -z to +z
|
||||
maxAxis = absY;
|
||||
uc = dir.x;
|
||||
vc = -dir.z;
|
||||
*index = 3;
|
||||
}
|
||||
// POSITIVE Z
|
||||
else if (isZPositive && absZ >= absX && absZ >= absY) {
|
||||
// u (0 to 1) goes from -x to +x
|
||||
// v (0 to 1) goes from -y to +y
|
||||
maxAxis = absZ;
|
||||
uc = dir.x;
|
||||
vc = -dir.y;
|
||||
*index = 4;
|
||||
}
|
||||
// NEGATIVE Z
|
||||
else if (!isZPositive && absZ >= absX && absZ >= absY) {
|
||||
// u (0 to 1) goes from +x to -x
|
||||
// v (0 to 1) goes from -y to +y
|
||||
maxAxis = absZ;
|
||||
uc = -dir.x;
|
||||
vc = -dir.y;
|
||||
*index = 5;
|
||||
}
|
||||
|
||||
// Convert range from -1 to 1 to 0 to 1
|
||||
uv->x = 0.5f * (uc / maxAxis + 1.0f);
|
||||
uv->y = 0.5f * (vc / maxAxis + 1.0f);
|
||||
}
|
||||
|
||||
glm::vec4 CubeMap::fetchLod(const glm::vec3& dir, float lod) const {
|
||||
// TODO
|
||||
return glm::vec4(0.0f);
|
||||
gpu::uint16 loLevel = (gpu::uint16)std::floor(lod);
|
||||
gpu::uint16 hiLevel = (gpu::uint16)std::ceil(lod);
|
||||
float lodFrac = lod - (float)loLevel;
|
||||
ConstMip loMip(loLevel, this);
|
||||
ConstMip hiMip(hiLevel, this);
|
||||
int face;
|
||||
glm::vec2 uv;
|
||||
glm::vec4 loColor;
|
||||
glm::vec4 hiColor;
|
||||
|
||||
getFaceUV(dir, &face, &uv);
|
||||
|
||||
loColor = loMip.fetch(face, uv);
|
||||
hiColor = hiMip.fetch(face, uv);
|
||||
|
||||
return loColor + (hiColor - loColor) * lodFrac;
|
||||
}
|
||||
|
||||
static glm::vec3 sampleGGX(const glm::vec2& Xi, const float roughness) {
|
||||
|
@ -283,7 +503,7 @@ void CubeMap::generateGGXSamples(GGXSamples& data, float roughness, const int re
|
|||
void CubeMap::convolveForGGX(CubeMap& output, const std::atomic<bool>& abortProcessing) const {
|
||||
// This should match fragment.glsl values, too
|
||||
static const float ROUGHNESS_1_MIP_RESOLUTION = 1.5f;
|
||||
static const gpu::uint16 MAX_SAMPLE_COUNT = 4000;
|
||||
static const size_t MAX_SAMPLE_COUNT = 4000;
|
||||
|
||||
const auto mipCount = getMipCount();
|
||||
GGXSamples params;
|
||||
|
@ -294,10 +514,17 @@ void CubeMap::convolveForGGX(CubeMap& output, const std::atomic<bool>& abortProc
|
|||
// This is the inverse code found in fragment.glsl in evaluateAmbientLighting
|
||||
float levelAlpha = float(mipLevel) / (mipCount - ROUGHNESS_1_MIP_RESOLUTION);
|
||||
float mipRoughness = levelAlpha * (1.0f + 2.0f * levelAlpha) / 3.0f;
|
||||
|
||||
mipRoughness = std::max(1e-3f, mipRoughness);
|
||||
mipRoughness = std::min(1.0f, mipRoughness);
|
||||
|
||||
params.points.resize(std::min<size_t>(MAX_SAMPLE_COUNT, 1U + size_t(4000 * mipRoughness * mipRoughness)));
|
||||
size_t mipTotalPixelCount = getMipWidth(mipLevel) * getMipHeight(mipLevel) * 6;
|
||||
size_t sampleCount = 1U + size_t(4000 * mipRoughness * mipRoughness);
|
||||
|
||||
sampleCount = std::min(sampleCount, 2 * mipTotalPixelCount);
|
||||
sampleCount = std::min(MAX_SAMPLE_COUNT, 4 * mipTotalPixelCount);
|
||||
|
||||
params.points.resize(sampleCount);
|
||||
generateGGXSamples(params, mipRoughness, _width);
|
||||
|
||||
for (int face = 0; face < 6; face++) {
|
||||
|
@ -313,7 +540,8 @@ void CubeMap::convolveMipFaceForGGX(const GGXSamples& samples, CubeMap& output,
|
|||
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];
|
||||
auto outputFacePixels = output.editFace(mipLevel, face);
|
||||
auto outputLineStride = output.getFaceLineStride(mipLevel);
|
||||
|
||||
tbb::parallel_for(tbb::blocked_range2d<int, int>(0, _width, 16, 0, _height, 16), [&](const tbb::blocked_range2d<int, int>& range) {
|
||||
auto rowRange = range.rows();
|
||||
|
@ -330,7 +558,7 @@ void CubeMap::convolveMipFaceForGGX(const GGXSamples& samples, CubeMap& output,
|
|||
// Interpolate normal for this pixel
|
||||
const glm::vec3 normal = glm::normalize(normalYLo + deltaYNormal * yAlpha);
|
||||
|
||||
outputFace[x + y * _width] = computeConvolution(normal, samples);
|
||||
outputFacePixels[x + y * outputLineStride] = computeConvolution(normal, samples);
|
||||
}
|
||||
|
||||
if (abortProcessing.load()) {
|
||||
|
|
|
@ -24,9 +24,10 @@ namespace image {
|
|||
public:
|
||||
|
||||
CubeMap(int width, int height, int mipCount);
|
||||
CubeMap(gpu::TexturePointer texture, const std::atomic<bool>& abortProcessing = false);
|
||||
CubeMap(gpu::Texture* texture, const std::atomic<bool>& abortProcessing = false);
|
||||
|
||||
void reset(int width, int height, int mipCount);
|
||||
void copyTo(gpu::Texture* texture, const std::atomic<bool>& abortProcessing = false) const;
|
||||
|
||||
gpu::uint16 getMipCount() const { return (gpu::uint16)_mips.size(); }
|
||||
int getMipWidth(gpu::uint16 mipLevel) const {
|
||||
|
@ -57,6 +58,8 @@ namespace image {
|
|||
private:
|
||||
|
||||
struct GGXSamples;
|
||||
class Mip;
|
||||
class ConstMip;
|
||||
|
||||
using Face = std::vector<glm::vec4>;
|
||||
using Faces = std::array<Face, 6>;
|
||||
|
@ -65,19 +68,11 @@ namespace image {
|
|||
int _height;
|
||||
std::vector<Faces> _mips;
|
||||
|
||||
static void getFaceUV(const glm::vec3& dir, int* index, glm::vec2* uv);
|
||||
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,8 +521,8 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
void image::convertToFloat(const unsigned char* source, int width, int height, int srcLineByteStride, gpu::Element sourceFormat,
|
||||
glm::vec4* output, int outputLinePixelStride) {
|
||||
void image::convertToFloat(const unsigned char* source, int width, int height, size_t srcLineByteStride, gpu::Element sourceFormat,
|
||||
glm::vec4* output, size_t outputLinePixelStride) {
|
||||
glm::vec4* outputIt;
|
||||
auto unpackFunc = getUnpackingFunction(sourceFormat);
|
||||
|
||||
|
@ -541,8 +541,8 @@ void image::convertToFloat(const unsigned char* source, int width, int height, i
|
|||
}
|
||||
}
|
||||
|
||||
void image::convertFromFloat(unsigned char* output, int width, int height, int outputLineByteStride, gpu::Element outputFormat,
|
||||
const glm::vec4* source, int srcLinePixelStride) {
|
||||
void image::convertFromFloat(unsigned char* output, int width, int height, size_t outputLineByteStride, gpu::Element outputFormat,
|
||||
const glm::vec4* source, size_t srcLinePixelStride) {
|
||||
const glm::vec4* sourceIt;
|
||||
auto packFunc = getPackingFunction(outputFormat);
|
||||
|
||||
|
@ -856,49 +856,11 @@ void generateMips(gpu::Texture* texture, QImage&& image, BackendTarget target, c
|
|||
|
||||
void convolveForGGX(gpu::Texture* texture, BackendTarget target, const std::atomic<bool>& abortProcessing = false) {
|
||||
PROFILE_RANGE(resource_parse, "convolveForGGX");
|
||||
CubeMap source(texture->getWidth(), texture->getHeight(), texture->getNumMips());
|
||||
CubeMap source(texture, abortProcessing);
|
||||
CubeMap output(texture->getWidth(), texture->getHeight(), texture->getNumMips());
|
||||
gpu::uint16 mipLevel;
|
||||
int face;
|
||||
const auto textureFormat = texture->getTexelFormat();
|
||||
|
||||
// Convert all mip data to float as source
|
||||
for (mipLevel = 0; mipLevel < source.getMipCount(); ++mipLevel) {
|
||||
auto mipDims = texture->evalMipDimensions(mipLevel);
|
||||
auto& mip = source.editMip(mipLevel);
|
||||
|
||||
for (face = 0; face < 6; face++) {
|
||||
auto sourcePixels = texture->accessStoredMipFace(mipLevel, face)->data();
|
||||
convertToFloat(sourcePixels, mipDims.x, mipDims.y, sizeof(uint32)*mipDims.x, textureFormat, mip[face]);
|
||||
if (abortProcessing.load()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
source.convolveForGGX(output, abortProcessing);
|
||||
|
||||
if (!abortProcessing) {
|
||||
// Convert all mip data back from float
|
||||
unsigned char* convertedPixels = new unsigned char[texture->getWidth() * texture->getHeight() * sizeof(uint32)];
|
||||
|
||||
for (mipLevel = 0; mipLevel < output.getMipCount(); ++mipLevel) {
|
||||
auto mipDims = texture->evalMipDimensions(mipLevel);
|
||||
auto mipSize = texture->evalMipFaceSize(mipLevel);
|
||||
auto& mip = output.getMip(mipLevel);
|
||||
|
||||
for (face = 0; face < 6; face++) {
|
||||
convertFromFloat(convertedPixels, mipDims.x, mipDims.y, sizeof(uint32)*mipDims.x, textureFormat, mip[face]);
|
||||
texture->assignStoredMipFace(mipLevel, face, mipSize, convertedPixels);
|
||||
if (abortProcessing.load()) {
|
||||
delete[] convertedPixels;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete[] convertedPixels;
|
||||
}
|
||||
output.copyTo(texture, abortProcessing);
|
||||
}
|
||||
|
||||
void processTextureAlpha(const QImage& srcImage, bool& validAlpha, bool& alphaAsMask) {
|
||||
|
|
|
@ -27,10 +27,10 @@ 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);
|
||||
void convertToFloat(const unsigned char* source, int width, int height, size_t srcLineByteStride, gpu::Element sourceFormat,
|
||||
glm::vec4* output, size_t outputLinePixelStride);
|
||||
void convertFromFloat(unsigned char* output, int width, int height, size_t outputLineByteStride, gpu::Element outputFormat,
|
||||
const glm::vec4* source, size_t srcLinePixelStride);
|
||||
|
||||
namespace TextureUsage {
|
||||
|
||||
|
|
Loading…
Reference in a new issue