Fixed gamma with ETC SRGB8

This commit is contained in:
Olivier Prat 2019-04-03 18:19:27 +02:00
commit 150508dc18
4 changed files with 57 additions and 26 deletions

View file

@ -15,13 +15,14 @@
#include <tbb/blocked_range2d.h>
#include "RandomAndNoise.h"
#include "TextureProcessing.h"
#include "ImageLogging.h"
#ifndef M_PI
#define M_PI 3.14159265359
#endif
#include <nvtt/nvtt.h>
using namespace image;
static const glm::vec3 FACE_NORMALS[24] = {
@ -321,7 +322,7 @@ CubeMap::CubeMap(int width, int height, int mipCount) {
reset(width, height, mipCount);
}
CubeMap::CubeMap(const std::vector<Image>& faces, gpu::Element srcTextureFormat, int mipCount, const std::atomic<bool>& abortProcessing) {
CubeMap::CubeMap(const std::vector<Image>& faces, int mipCount, const std::atomic<bool>& abortProcessing) {
reset(faces.front().getWidth(), faces.front().getHeight(), mipCount);
int face;
@ -330,13 +331,11 @@ CubeMap::CubeMap(const std::vector<Image>& faces, gpu::Element srcTextureFormat,
surface.setAlphaMode(nvtt::AlphaMode_None);
surface.setWrapMode(nvtt::WrapMode_Mirror);
std::vector<glm::vec4> floatPixels;
floatPixels.resize(_width * _height);
// Compute mips
for (face = 0; face < 6; face++) {
convertToFloatFromPacked(faces[face].getBits(), _width, _height, faces[face].getBytesPerLineCount(), srcTextureFormat, floatPixels.data(), _width);
surface.setImage(nvtt::InputFormat_RGBA_32F, _width, _height, 1, &floatPixels.front().x);
Image faceImage = faces[face].getConvertedToFormat(Image::Format_RGBAF);
surface.setImage(nvtt::InputFormat_RGBA_32F, _width, _height, 1, faceImage.editBits());
auto mipLevel = 0;
copySurface(surface, editFace(0, face), getMipLineStride(0));
@ -359,6 +358,18 @@ CubeMap::CubeMap(const std::vector<Image>& faces, gpu::Element srcTextureFormat,
}
}
void CubeMap::applyGamma(float value) {
for (auto& mip : _mips) {
for (auto& face : mip) {
for (auto& pixel : face) {
pixel.r = std::pow(pixel.r, value);
pixel.g = std::pow(pixel.g, value);
pixel.b = std::pow(pixel.b, value);
}
}
}
}
void CubeMap::copyFace(int width, int height, const glm::vec4* source, size_t srcLineStride, glm::vec4* dest, size_t dstLineStride) {
for (int y = 0; y < height; y++) {
std::copy(source, source + width, dest);

View file

@ -31,11 +31,13 @@ namespace image {
public:
CubeMap(int width, int height, int mipCount);
CubeMap(const std::vector<Image>& faces, gpu::Element faceFormat, int mipCount, const std::atomic<bool>& abortProcessing = false);
CubeMap(const std::vector<Image>& faces, int mipCount, const std::atomic<bool>& abortProcessing = false);
void reset(int width, int height, int mipCount);
void copyTo(CubeMap& other) const;
void applyGamma(float value);
gpu::uint16 getMipCount() const { return (gpu::uint16)_mips.size(); }
int getMipWidth(gpu::uint16 mipLevel) const {
return std::max(1, _width >> mipLevel);

View file

@ -75,8 +75,8 @@ Image Image::getScaled(glm::uvec2 dstSize, AspectRatioMode ratioMode, Transforma
glm::vec4* floatPixels = new glm::vec4[getWidth()*getHeight()];
auto unpackFunc = getHDRUnpackingFunction();
auto floatDataIt = floatPixels;
for (auto lineNb = 0; lineNb < getHeight(); lineNb++) {
const glm::uint32* srcPixelIt = reinterpret_cast<const glm::uint32*>(getScanLine(lineNb));
for (glm::uint32 lineNb = 0; lineNb < getHeight(); lineNb++) {
const glm::uint32* srcPixelIt = reinterpret_cast<const glm::uint32*>(getScanLine((int)lineNb));
const glm::uint32* srcPixelEnd = srcPixelIt + getWidth();
while (srcPixelIt < srcPixelEnd) {
@ -96,7 +96,7 @@ Image Image::getScaled(glm::uvec2 dstSize, AspectRatioMode ratioMode, Transforma
if (transformMode == Qt::TransformationMode::FastTransformation) {
filter = nvtt::ResizeFilter_Box;
}
surface.resize(dstSize.x, dstSize.y, 1, nvtt::ResizeFilter_Box);
surface.resize(dstSize.x, dstSize.y, 1, filter);
auto srcRedIt = reinterpret_cast<const float*>(surface.channel(0));
auto srcGreenIt = reinterpret_cast<const float*>(surface.channel(1));
@ -124,8 +124,8 @@ Image Image::getScaled(glm::uvec2 dstSize, AspectRatioMode ratioMode, Transforma
QImage resizedImage((int)dstSize.x, (int)dstSize.y, (QImage::Format)Image::Format_PACKED_FLOAT);
auto packFunc = getHDRPackingFunction();
for (auto lineNb = 0; lineNb < dstSize.y; lineNb++) {
glm::uint32* dstPixelIt = reinterpret_cast<glm::uint32*>(resizedImage.scanLine(lineNb));
for (glm::uint32 lineNb = 0; lineNb < dstSize.y; lineNb++) {
glm::uint32* dstPixelIt = reinterpret_cast<glm::uint32*>(resizedImage.scanLine((int)lineNb));
glm::uint32* dstPixelEnd = dstPixelIt + dstSize.x;
while (dstPixelIt < dstPixelEnd) {

View file

@ -615,7 +615,7 @@ nvtt::OutputHandler* getNVTTCompressionOutputHandler(gpu::Texture* outputTexture
}
}
void convertToHDRTexture(gpu::Texture* texture, Image&& image, BackendTarget target, int baseMipLevel, bool buildMips, const std::atomic<bool>& abortProcessing, int face) {
void convertImageToHDRTexture(gpu::Texture* texture, Image&& image, BackendTarget target, int baseMipLevel, bool buildMips, const std::atomic<bool>& abortProcessing, int face) {
assert(image.hasFloatFormat());
Image localCopy = image.getConvertedToFormat(Image::Format_RGBAF);
@ -658,21 +658,20 @@ void convertToHDRTexture(gpu::Texture* texture, Image&& image, BackendTarget tar
}
}
void convertToLDRTexture(gpu::Texture* texture, Image&& image, BackendTarget target, int baseMipLevel, bool buildMips, const std::atomic<bool>& abortProcessing, int face) {
void convertImageToLDRTexture(gpu::Texture* texture, Image&& image, BackendTarget target, int baseMipLevel, bool buildMips, const std::atomic<bool>& abortProcessing, int face) {
// Take a local copy to force move construction
// https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#f18-for-consume-parameters-pass-by-x-and-stdmove-the-parameter
Image localCopy = std::move(image);
assert(localCopy.getFormat() != Image::Format_PACKED_FLOAT);
if (localCopy.getFormat() != Image::Format_ARGB32) {
localCopy = localCopy.getConvertedToFormat(Image::Format_ARGB32);
}
const int width = localCopy.getWidth(), height = localCopy.getHeight();
auto mipFormat = texture->getStoredMipFormat();
int mipLevel = baseMipLevel;
if (target != BackendTarget::GLES32) {
if (localCopy.getFormat() != Image::Format_ARGB32) {
localCopy = localCopy.getConvertedToFormat(Image::Format_ARGB32);
}
const void* data = static_cast<const void*>(localCopy.getBits());
nvtt::TextureType textureType = nvtt::TextureType_2D;
nvtt::InputFormat inputFormat = nvtt::InputFormat_BGRA_8UB;
@ -864,12 +863,12 @@ void convertImageToTexture(gpu::Texture* texture, Image& image, BackendTarget ta
PROFILE_RANGE(resource_parse, "convertToTextureWithMips");
if (target == BackendTarget::GLES32) {
convertToLDRTexture(texture, std::move(image), target, baseMipLevel, buildMips, abortProcessing, face);
convertImageToLDRTexture(texture, std::move(image), target, baseMipLevel, buildMips, abortProcessing, face);
} else {
if (image.hasFloatFormat()) {
convertToHDRTexture(texture, std::move(image), target, baseMipLevel, buildMips, abortProcessing, face);
convertImageToHDRTexture(texture, std::move(image), target, baseMipLevel, buildMips, abortProcessing, face);
} else {
convertToLDRTexture(texture, std::move(image), target, baseMipLevel, buildMips, abortProcessing, face);
convertImageToLDRTexture(texture, std::move(image), target, baseMipLevel, buildMips, abortProcessing, face);
}
}
}
@ -1487,12 +1486,31 @@ Image convertToHDRFormat(Image&& srcImage, gpu::Element format) {
return hdrImage;
}
void convolveForGGX(const std::vector<Image>& faces, gpu::Element faceFormat, gpu::Texture* texture, BackendTarget target, const std::atomic<bool>& abortProcessing = false) {
static bool isLinearTextureFormat(gpu::Element format) {
return !((format == gpu::Element::COLOR_SRGBA_32)
|| (format == gpu::Element::COLOR_SBGRA_32)
|| (format == gpu::Element::COLOR_SR_8)
|| (format == gpu::Element::COLOR_COMPRESSED_BCX_SRGB)
|| (format == gpu::Element::COLOR_COMPRESSED_BCX_SRGBA_MASK)
|| (format == gpu::Element::COLOR_COMPRESSED_BCX_SRGBA)
|| (format == gpu::Element::COLOR_COMPRESSED_BCX_SRGBA_HIGH)
|| (format == gpu::Element::COLOR_COMPRESSED_ETC2_SRGB)
|| (format == gpu::Element::COLOR_COMPRESSED_ETC2_SRGBA)
|| (format == gpu::Element::COLOR_COMPRESSED_ETC2_SRGB_PUNCHTHROUGH_ALPHA));
}
void convolveForGGX(const std::vector<Image>& faces, gpu::Texture* texture, BackendTarget target, const std::atomic<bool>& abortProcessing = false) {
PROFILE_RANGE(resource_parse, "convolveForGGX");
CubeMap source(faces, faceFormat, texture->getNumMips(), abortProcessing);
CubeMap source(faces, texture->getNumMips(), abortProcessing);
CubeMap output(texture->getWidth(), texture->getHeight(), texture->getNumMips());
if (!faces.front().hasFloatFormat()) {
source.applyGamma(2.2f);
}
source.convolveForGGX(output, abortProcessing);
if (!isLinearTextureFormat(texture->getTexelFormat())) {
output.applyGamma(1.0f/2.2f);
}
for (int face = 0; face < 6; face++) {
for (gpu::uint16 mipLevel = 0; mipLevel < output.getMipCount(); mipLevel++) {
@ -1601,7 +1619,7 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(Image&& srcIm
if (options & CUBE_GGX_CONVOLVE) {
// Performs and convolution AND mip map generation
convolveForGGX(faces, GPU_CUBEMAP_HDR_FORMAT, theTexture.get(), target, abortProcessing);
convolveForGGX(faces, theTexture.get(), target, abortProcessing);
} else {
// Create mip maps and compress to final format in one go
for (uint8 face = 0; face < faces.size(); ++face) {