mirror of
https://github.com/overte-org/overte.git
synced 2025-04-16 00:41:16 +02:00
Integrate the PR from ALessandro through a different Texture Type and a different TextureLoader to transform a bump map into a normal map
This commit is contained in:
parent
3614812681
commit
6a714f405c
8 changed files with 168 additions and 335 deletions
|
@ -1080,9 +1080,10 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
} else if (type.contains("transparentcolor")) { // it should be TransparentColor...
|
||||
// THis is how Maya assign a texture that affect diffuse color AND transparency ?
|
||||
diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||
} else if (type.contains("bump") || type.contains("normal")) {
|
||||
} else if (type.contains("bump")) {
|
||||
bumpTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||
|
||||
} else if (type.contains("normal")) {
|
||||
normalTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||
} else if (type.contains("specular") || type.contains("reflection")) {
|
||||
specularTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||
|
||||
|
|
|
@ -112,7 +112,9 @@ public:
|
|||
Transform transform;
|
||||
int texcoordSet;
|
||||
QString texcoordSetName;
|
||||
|
||||
|
||||
bool isBumpmap{ false };
|
||||
|
||||
bool isNull() const { return name.isEmpty() && filename.isEmpty() && content.isEmpty(); }
|
||||
};
|
||||
|
||||
|
@ -394,6 +396,7 @@ public:
|
|||
|
||||
QHash<QString, QString> diffuseTextures;
|
||||
QHash<QString, QString> bumpTextures;
|
||||
QHash<QString, QString> normalTextures;
|
||||
QHash<QString, QString> specularTextures;
|
||||
QHash<QString, QString> emissiveTextures;
|
||||
QHash<QString, QString> ambientTextures;
|
||||
|
|
|
@ -86,13 +86,21 @@ void FBXReader::consolidateFBXMaterials() {
|
|||
|
||||
FBXTexture normalTexture;
|
||||
QString bumpTextureID = bumpTextures.value(material.materialID);
|
||||
if (!bumpTextureID.isNull()) {
|
||||
normalTexture = getTexture(bumpTextureID);
|
||||
|
||||
QString normalTextureID = normalTextures.value(material.materialID);
|
||||
if (!normalTextureID.isNull()) {
|
||||
normalTexture = getTexture(normalTextureID);
|
||||
normalTexture.isBumpmap = false;
|
||||
|
||||
material.normalTexture = normalTexture;
|
||||
detectDifferentUVs |= (normalTexture.texcoordSet != 0) || (!normalTexture.transform.isIdentity());
|
||||
} else if (!bumpTextureID.isNull()) {
|
||||
normalTexture = getTexture(bumpTextureID);
|
||||
normalTexture.isBumpmap = true;
|
||||
|
||||
material.normalTexture = normalTexture;
|
||||
|
||||
detectDifferentUVs |= (normalTexture.texcoordSet != 0) || (!normalTexture.transform.isIdentity());
|
||||
}
|
||||
|
||||
|
||||
FBXTexture specularTexture;
|
||||
QString specularTextureID = specularTextures.value(material.materialID);
|
||||
|
|
|
@ -182,11 +182,10 @@ Texture::~Texture() {
|
|||
NetworkTexture::NetworkTexture(const QUrl& url, TextureType type, const QByteArray& content) :
|
||||
Resource(url, !content.isEmpty()),
|
||||
_type(type),
|
||||
_translucent(false),
|
||||
_width(0),
|
||||
_height(0) {
|
||||
|
||||
_textureStorage.reset(new model::TextureStorage());
|
||||
_textureSource.reset(new model::TextureSource());
|
||||
|
||||
if (!url.isValid()) {
|
||||
_loaded = true;
|
||||
|
@ -202,13 +201,12 @@ NetworkTexture::NetworkTexture(const QUrl& url, TextureType type, const QByteArr
|
|||
|
||||
NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content) :
|
||||
Resource(url, !content.isEmpty()),
|
||||
// _type(type),
|
||||
_type(CUSTOM_TEXTURE),
|
||||
_textureLoader(textureLoader),
|
||||
_translucent(false),
|
||||
_width(0),
|
||||
_height(0) {
|
||||
|
||||
_textureStorage.reset(new model::TextureStorage());
|
||||
_textureSource.reset(new model::TextureSource());
|
||||
|
||||
if (!url.isValid()) {
|
||||
_loaded = true;
|
||||
|
@ -223,11 +221,27 @@ NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& texture
|
|||
}
|
||||
|
||||
NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const {
|
||||
if (_type != CUBE_TEXTURE) {
|
||||
|
||||
return TextureLoaderFunc(model::TextureStorage::create2DTextureFromImage);
|
||||
} else {
|
||||
return TextureLoaderFunc(model::TextureStorage::createCubeTextureFromImage);
|
||||
switch (_type) {
|
||||
case CUBE_TEXTURE: {
|
||||
return TextureLoaderFunc(model::TextureSource::createCubeTextureFromImage);
|
||||
break;
|
||||
}
|
||||
case BUMP_TEXTURE: {
|
||||
return TextureLoaderFunc(model::TextureSource::createNormalTextureFromBumpImage);
|
||||
break;
|
||||
}
|
||||
case CUSTOM_TEXTURE: {
|
||||
return _textureLoader;
|
||||
break;
|
||||
}
|
||||
case DEFAULT_TEXTURE:
|
||||
case NORMAL_TEXTURE:
|
||||
case SPECULAR_TEXTURE:
|
||||
case EMISSIVE_TEXTURE:
|
||||
default: {
|
||||
return TextureLoaderFunc(model::TextureSource::create2DTextureFromImage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -278,42 +292,6 @@ void listSupportedImageFormats() {
|
|||
});
|
||||
}
|
||||
|
||||
/*
|
||||
class CubeLayout {
|
||||
public:
|
||||
int _widthRatio = 1;
|
||||
int _heightRatio = 1;
|
||||
|
||||
class Face {
|
||||
public:
|
||||
int _x = 0;
|
||||
int _y = 0;
|
||||
bool _horizontalMirror = false;
|
||||
bool _verticalMirror = false;
|
||||
|
||||
Face() {}
|
||||
Face(int x, int y, bool horizontalMirror, bool verticalMirror) : _x(x), _y(y), _horizontalMirror(horizontalMirror), _verticalMirror(verticalMirror) {}
|
||||
};
|
||||
|
||||
Face _faceXPos;
|
||||
Face _faceXNeg;
|
||||
Face _faceYPos;
|
||||
Face _faceYNeg;
|
||||
Face _faceZPos;
|
||||
Face _faceZNeg;
|
||||
|
||||
CubeLayout(int wr, int hr, Face fXP, Face fXN, Face fYP, Face fYN, Face fZP, Face fZN) :
|
||||
_widthRatio(wr),
|
||||
_heightRatio(hr),
|
||||
_faceXPos(fXP),
|
||||
_faceXNeg(fXN),
|
||||
_faceYPos(fYP),
|
||||
_faceYNeg(fYN),
|
||||
_faceZPos(fZP),
|
||||
_faceZNeg(fZN) {}
|
||||
};
|
||||
*/
|
||||
|
||||
void ImageReader::run() {
|
||||
QSharedPointer<Resource> texture = _texture.toStrongRef();
|
||||
if (texture.isNull()) {
|
||||
|
@ -347,259 +325,25 @@ void ImageReader::run() {
|
|||
if (ntex) {
|
||||
theTexture = ntex->getTextureLoader()(image, _url.toString().toStdString());
|
||||
}
|
||||
|
||||
/*
|
||||
int imageArea = image.width() * image.height();
|
||||
|
||||
gpu::Texture* theTexture = nullptr;
|
||||
|
||||
if (ntex && (ntex->getType() == CUBE_TEXTURE)) {
|
||||
qCDebug(gpunetwork) << "Cube map size:" << _url << image.width() << image.height();
|
||||
}
|
||||
|
||||
int opaquePixels = 0;
|
||||
int translucentPixels = 0;
|
||||
bool isTransparent = false;
|
||||
int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
|
||||
const int EIGHT_BIT_MAXIMUM = 255;
|
||||
QColor averageColor(EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM);
|
||||
|
||||
if (!image.hasAlphaChannel()) {
|
||||
if (image.format() != QImage::Format_RGB888) {
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
// int redTotal = 0, greenTotal = 0, blueTotal = 0;
|
||||
for (int y = 0; y < image.height(); y++) {
|
||||
for (int x = 0; x < image.width(); x++) {
|
||||
QRgb rgb = image.pixel(x, y);
|
||||
redTotal += qRed(rgb);
|
||||
greenTotal += qGreen(rgb);
|
||||
blueTotal += qBlue(rgb);
|
||||
}
|
||||
}
|
||||
if (imageArea > 0) {
|
||||
averageColor.setRgb(redTotal / imageArea, greenTotal / imageArea, blueTotal / imageArea);
|
||||
}
|
||||
} else {
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
|
||||
// check for translucency/false transparency
|
||||
// int opaquePixels = 0;
|
||||
// int translucentPixels = 0;
|
||||
// int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
|
||||
for (int y = 0; y < image.height(); y++) {
|
||||
for (int x = 0; x < image.width(); x++) {
|
||||
QRgb rgb = image.pixel(x, y);
|
||||
redTotal += qRed(rgb);
|
||||
greenTotal += qGreen(rgb);
|
||||
blueTotal += qBlue(rgb);
|
||||
int alpha = qAlpha(rgb);
|
||||
alphaTotal += alpha;
|
||||
if (alpha == EIGHT_BIT_MAXIMUM) {
|
||||
opaquePixels++;
|
||||
} else if (alpha != 0) {
|
||||
translucentPixels++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opaquePixels == imageArea) {
|
||||
qCDebug(gpunetwork) << "Image with alpha channel is completely opaque:" << _url;
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
|
||||
averageColor = QColor(redTotal / imageArea,
|
||||
greenTotal / imageArea, blueTotal / imageArea, alphaTotal / imageArea);
|
||||
|
||||
isTransparent = (translucentPixels >= imageArea / 2);
|
||||
}
|
||||
|
||||
gpu::Texture* theTexture = nullptr;
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
|
||||
// bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
bool isLinearRGB = !(_type == CUBE_TEXTURE); //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
if (image.hasAlphaChannel()) {
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
||||
}
|
||||
|
||||
if (_type == CUBE_TEXTURE) {
|
||||
|
||||
const CubeLayout CUBEMAP_LAYOUTS[] = {
|
||||
// Here is the expected layout for the faces in an image with the 1/6 aspect ratio:
|
||||
//
|
||||
// WIDTH
|
||||
// <------>
|
||||
// ^ +------+
|
||||
// | | |
|
||||
// | | +X |
|
||||
// | | |
|
||||
// H +------+
|
||||
// E | |
|
||||
// I | -X |
|
||||
// G | |
|
||||
// H +------+
|
||||
// T | |
|
||||
// | | +Y |
|
||||
// | | |
|
||||
// | +------+
|
||||
// | | |
|
||||
// | | -Y |
|
||||
// | | |
|
||||
// H +------+
|
||||
// E | |
|
||||
// I | +Z |
|
||||
// G | |
|
||||
// H +------+
|
||||
// T | |
|
||||
// | | -Z |
|
||||
// | | |
|
||||
// V +------+
|
||||
//
|
||||
// FaceWidth = width = height / 6
|
||||
{ 1, 6,
|
||||
{0, 0, true, false},
|
||||
{0, 1, true, false},
|
||||
{0, 2, false, true},
|
||||
{0, 3, false, true},
|
||||
{0, 4, true, false},
|
||||
{0, 5, true, false}
|
||||
},
|
||||
|
||||
// Here is the expected layout for the faces in an image with the 3/4 aspect ratio:
|
||||
//
|
||||
// <-----------WIDTH----------->
|
||||
// ^ +------+------+------+------+
|
||||
// | | | | | |
|
||||
// | | | +Y | | |
|
||||
// | | | | | |
|
||||
// H +------+------+------+------+
|
||||
// E | | | | |
|
||||
// I | -X | -Z | +X | +Z |
|
||||
// G | | | | |
|
||||
// H +------+------+------+------+
|
||||
// T | | | | |
|
||||
// | | | -Y | | |
|
||||
// | | | | | |
|
||||
// V +------+------+------+------+
|
||||
//
|
||||
// FaceWidth = width / 4 = height / 3
|
||||
{ 4, 3,
|
||||
{2, 1, true, false},
|
||||
{0, 1, true, false},
|
||||
{1, 0, false, true},
|
||||
{1, 2, false, true},
|
||||
{3, 1, true, false},
|
||||
{1, 1, true, false}
|
||||
},
|
||||
|
||||
// Here is the expected layout for the faces in an image with the 4/3 aspect ratio:
|
||||
//
|
||||
// <-------WIDTH-------->
|
||||
// ^ +------+------+------+
|
||||
// | | | | |
|
||||
// | | | +Y | |
|
||||
// | | | | |
|
||||
// H +------+------+------+
|
||||
// E | | | |
|
||||
// I | -X | -Z | +X |
|
||||
// G | | | |
|
||||
// H +------+------+------+
|
||||
// T | | | |
|
||||
// | | | -Y | |
|
||||
// | | | | |
|
||||
// | +------+------+------+
|
||||
// | | | | |
|
||||
// | | | +Z! | | <+Z is upside down!
|
||||
// | | | | |
|
||||
// V +------+------+------+
|
||||
//
|
||||
// FaceWidth = width / 3 = height / 4
|
||||
{ 3, 4,
|
||||
{2, 1, true, false},
|
||||
{0, 1, true, false},
|
||||
{1, 0, false, true},
|
||||
{1, 2, false, true},
|
||||
{1, 3, false, true},
|
||||
{1, 1, true, false}
|
||||
}
|
||||
};
|
||||
const int NUM_CUBEMAP_LAYOUTS = sizeof(CUBEMAP_LAYOUTS) / sizeof(CubeLayout);
|
||||
|
||||
// Find the layout of the cubemap in the 2D image
|
||||
int foundLayout = -1;
|
||||
for (int i = 0; i < NUM_CUBEMAP_LAYOUTS; i++) {
|
||||
if ((image.height() * CUBEMAP_LAYOUTS[i]._widthRatio) == (image.width() * CUBEMAP_LAYOUTS[i]._heightRatio)) {
|
||||
foundLayout = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<QImage> faces;
|
||||
// If found, go extract the faces as separate images
|
||||
if (foundLayout >= 0) {
|
||||
auto& layout = CUBEMAP_LAYOUTS[foundLayout];
|
||||
int faceWidth = image.width() / layout._widthRatio;
|
||||
|
||||
faces.push_back(image.copy(QRect(layout._faceXPos._x * faceWidth, layout._faceXPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXPos._horizontalMirror, layout._faceXPos._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceXNeg._x * faceWidth, layout._faceXNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXNeg._horizontalMirror, layout._faceXNeg._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceYPos._x * faceWidth, layout._faceYPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYPos._horizontalMirror, layout._faceYPos._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceYNeg._x * faceWidth, layout._faceYNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYNeg._horizontalMirror, layout._faceYNeg._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceZPos._x * faceWidth, layout._faceZPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZPos._horizontalMirror, layout._faceZPos._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceZNeg._x * faceWidth, layout._faceZNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZNeg._horizontalMirror, layout._faceZNeg._verticalMirror));
|
||||
} else {
|
||||
qCDebug(gpunetwork) << "Failed to find a known cube map layout from this image:" << _url;
|
||||
return;
|
||||
}
|
||||
|
||||
// If the 6 faces have been created go on and define the true Texture
|
||||
if (faces.size() == gpu::Texture::NUM_FACES_PER_TYPE[gpu::Texture::TEX_CUBE]) {
|
||||
theTexture = gpu::Texture::createCube(formatGPU, faces[0].width(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP));
|
||||
theTexture->autoGenerateMips(-1);
|
||||
int f = 0;
|
||||
for (auto& face : faces) {
|
||||
theTexture->assignStoredMipFace(0, formatMip, face.byteCount(), face.constBits(), f);
|
||||
f++;
|
||||
}
|
||||
|
||||
// GEnerate irradiance while we are at it
|
||||
theTexture->generateIrradiance();
|
||||
}
|
||||
|
||||
} else {
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
||||
theTexture->autoGenerateMips(-1);
|
||||
}
|
||||
}
|
||||
*/
|
||||
QMetaObject::invokeMethod(texture.data(), "setImage",
|
||||
Q_ARG(const QImage&, image),
|
||||
Q_ARG(void*, theTexture),
|
||||
// Q_ARG(bool, isTransparent),
|
||||
// Q_ARG(const QColor&, averageColor),
|
||||
Q_ARG(int, originalWidth), Q_ARG(int, originalHeight));
|
||||
|
||||
|
||||
}
|
||||
|
||||
void NetworkTexture::setImage(const QImage& image, void* voidTexture,/* bool translucent, const QColor& averageColor, */ int originalWidth,
|
||||
void NetworkTexture::setImage(const QImage& image, void* voidTexture, int originalWidth,
|
||||
int originalHeight) {
|
||||
// _translucent = translucent;
|
||||
// _averageColor = averageColor;
|
||||
_originalWidth = originalWidth;
|
||||
_originalHeight = originalHeight;
|
||||
|
||||
gpu::Texture* texture = static_cast<gpu::Texture*>(voidTexture);
|
||||
|
||||
// Passing ownership
|
||||
// _gpuTexture.reset(texture);
|
||||
_textureStorage->resetTexture(texture);
|
||||
auto gpuTexture = _textureStorage->getGPUTexture();
|
||||
_textureSource->resetTexture(texture);
|
||||
auto gpuTexture = _textureSource->getGPUTexture();
|
||||
|
||||
if (gpuTexture) {
|
||||
_width = gpuTexture->getWidth();
|
||||
|
|
|
@ -29,7 +29,7 @@ class NetworkTexture;
|
|||
|
||||
typedef QSharedPointer<NetworkTexture> NetworkTexturePointer;
|
||||
|
||||
enum TextureType { DEFAULT_TEXTURE, NORMAL_TEXTURE, SPECULAR_TEXTURE, EMISSIVE_TEXTURE, SPLAT_TEXTURE, CUBE_TEXTURE };
|
||||
enum TextureType { DEFAULT_TEXTURE, NORMAL_TEXTURE, BUMP_TEXTURE, SPECULAR_TEXTURE, EMISSIVE_TEXTURE, CUBE_TEXTURE, CUSTOM_TEXTURE };
|
||||
|
||||
/// Stores cached textures, including render-to-texture targets.
|
||||
class TextureCache : public ResourceCache, public Dependency {
|
||||
|
@ -97,9 +97,8 @@ public:
|
|||
Texture();
|
||||
~Texture();
|
||||
|
||||
//const gpu::TexturePointer& getGPUTexture() const { return _gpuTexture; }
|
||||
const gpu::TexturePointer getGPUTexture() const { return _textureStorage->getGPUTexture(); }
|
||||
model::TextureStoragePointer _textureStorage;
|
||||
const gpu::TexturePointer getGPUTexture() const { return _textureSource->getGPUTexture(); }
|
||||
model::TextureSourcePointer _textureSource;
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -118,18 +117,10 @@ public:
|
|||
NetworkTexture(const QUrl& url, TextureType type, const QByteArray& content);
|
||||
NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content);
|
||||
|
||||
/// Checks whether it "looks like" this texture is translucent
|
||||
/// (majority of pixels neither fully opaque or fully transparent).
|
||||
// bool isTranslucent() const { return _translucent; }
|
||||
|
||||
/// Returns the lazily-computed average texture color.
|
||||
// const QColor& getAverageColor() const { return _averageColor; }
|
||||
|
||||
int getOriginalWidth() const { return _originalWidth; }
|
||||
int getOriginalHeight() const { return _originalHeight; }
|
||||
int getWidth() const { return _width; }
|
||||
int getHeight() const { return _height; }
|
||||
// TextureType getType() const { return _type; }
|
||||
|
||||
TextureLoaderFunc getTextureLoader() const;
|
||||
|
||||
|
@ -139,8 +130,7 @@ protected:
|
|||
|
||||
Q_INVOKABLE void loadContent(const QByteArray& content);
|
||||
// FIXME: This void* should be a gpu::Texture* but i cannot get it to work for now, moving on...
|
||||
Q_INVOKABLE void setImage(const QImage& image, void* texture, /*bool translucent, const QColor& averageColor, */int originalWidth,
|
||||
int originalHeight);
|
||||
Q_INVOKABLE void setImage(const QImage& image, void* texture, int originalWidth, int originalHeight);
|
||||
|
||||
virtual void imageLoaded(const QImage& image);
|
||||
|
||||
|
@ -148,8 +138,6 @@ protected:
|
|||
|
||||
private:
|
||||
TextureLoaderFunc _textureLoader;
|
||||
bool _translucent;
|
||||
QColor _averageColor;
|
||||
int _originalWidth;
|
||||
int _originalHeight;
|
||||
int _width;
|
||||
|
|
|
@ -19,25 +19,25 @@
|
|||
using namespace model;
|
||||
using namespace gpu;
|
||||
|
||||
// TextureStorage
|
||||
TextureStorage::TextureStorage()
|
||||
// TextureSource
|
||||
TextureSource::TextureSource()
|
||||
{/* : Texture::Storage()//,
|
||||
// _gpuTexture(Texture::createFromStorage(this))*/
|
||||
}
|
||||
|
||||
TextureStorage::~TextureStorage() {
|
||||
TextureSource::~TextureSource() {
|
||||
}
|
||||
|
||||
void TextureStorage::reset(const QUrl& url, const TextureUsage& usage) {
|
||||
void TextureSource::reset(const QUrl& url, const TextureUsage& usage) {
|
||||
_imageUrl = url;
|
||||
_usage = usage;
|
||||
}
|
||||
|
||||
void TextureStorage::resetTexture(gpu::Texture* texture) {
|
||||
void TextureSource::resetTexture(gpu::Texture* texture) {
|
||||
_gpuTexture.reset(texture);
|
||||
}
|
||||
|
||||
bool TextureStorage::isDefined() const {
|
||||
bool TextureSource::isDefined() const {
|
||||
if (_gpuTexture) {
|
||||
return _gpuTexture->isDefined();
|
||||
} else {
|
||||
|
@ -46,21 +46,21 @@ bool TextureStorage::isDefined() const {
|
|||
}
|
||||
|
||||
|
||||
void TextureMap::setTextureStorage(TextureStoragePointer& texStorage) {
|
||||
_textureStorage = texStorage;
|
||||
void TextureMap::setTextureSource(TextureSourcePointer& texStorage) {
|
||||
_textureSource = texStorage;
|
||||
}
|
||||
|
||||
bool TextureMap::isDefined() const {
|
||||
if (_textureStorage) {
|
||||
return _textureStorage->isDefined();
|
||||
if (_textureSource) {
|
||||
return _textureSource->isDefined();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
gpu::TextureView TextureMap::getTextureView() const {
|
||||
if (_textureStorage) {
|
||||
return gpu::TextureView(_textureStorage->getGPUTexture(), 0);
|
||||
if (_textureSource) {
|
||||
return gpu::TextureView(_textureSource->getGPUTexture(), 0);
|
||||
} else {
|
||||
return gpu::TextureView();
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ void TextureMap::setLightmapOffsetScale(float offset, float scale) {
|
|||
|
||||
|
||||
|
||||
gpu::Texture* TextureStorage::create2DTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
gpu::Texture* TextureSource::create2DTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
QImage image = srcImage;
|
||||
|
||||
int imageArea = image.width() * image.height();
|
||||
|
@ -145,7 +145,7 @@ gpu::Texture* TextureStorage::create2DTextureFromImage(const QImage& srcImage, c
|
|||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
|
||||
// bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
bool isLinearRGB = false; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
|
@ -163,6 +163,94 @@ gpu::Texture* TextureStorage::create2DTextureFromImage(const QImage& srcImage, c
|
|||
return theTexture;
|
||||
}
|
||||
|
||||
int clampPixelCoordinate(int coordinate, int maxCoordinate) {
|
||||
return coordinate - ((int)(coordinate < 0) * coordinate) + ((int)(coordinate > maxCoordinate) * (maxCoordinate - coordinate));
|
||||
}
|
||||
|
||||
const int RGBA_MAX = 255;
|
||||
|
||||
// transform -1 - 1 to 0 - 255 (from sobel value to rgb)
|
||||
double mapComponent(double sobelValue) {
|
||||
const double factor = RGBA_MAX / 2.0;
|
||||
return (sobelValue + 1.0) * factor;
|
||||
}
|
||||
|
||||
gpu::Texture* TextureSource::createNormalTextureFromBumpImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
QImage image = srcImage;
|
||||
|
||||
// PR 5540 by AlessandroSigna
|
||||
// integrated here as a specialized TextureLoader for bumpmaps
|
||||
// The conversion is done using the Sobel Filter to calculate the derivatives from the grayscale image
|
||||
const double pStrength = 2.0;
|
||||
int width = image.width();
|
||||
int height = image.height();
|
||||
QImage result(width, height, image.format());
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
const int iNextClamped = clampPixelCoordinate(i + 1, width - 1);
|
||||
const int iPrevClamped = clampPixelCoordinate(i - 1, width - 1);
|
||||
|
||||
for (int j = 0; j < height; j++) {
|
||||
const int jNextClamped = clampPixelCoordinate(j + 1, height - 1);
|
||||
const int jPrevClamped = clampPixelCoordinate(j - 1, height - 1);
|
||||
|
||||
// surrounding pixels
|
||||
const QRgb topLeft = image.pixel(iPrevClamped, jPrevClamped);
|
||||
const QRgb top = image.pixel(iPrevClamped, j);
|
||||
const QRgb topRight = image.pixel(iPrevClamped, jNextClamped);
|
||||
const QRgb right = image.pixel(i, jNextClamped);
|
||||
const QRgb bottomRight = image.pixel(iNextClamped, jNextClamped);
|
||||
const QRgb bottom = image.pixel(iNextClamped, j);
|
||||
const QRgb bottomLeft = image.pixel(iNextClamped, jPrevClamped);
|
||||
const QRgb left = image.pixel(i, jPrevClamped);
|
||||
|
||||
// take their gray intensities
|
||||
// since it's a grayscale image, the value of each component RGB is the same
|
||||
const double tl = qRed(topLeft);
|
||||
const double t = qRed(top);
|
||||
const double tr = qRed(topRight);
|
||||
const double r = qRed(right);
|
||||
const double br = qRed(bottomRight);
|
||||
const double b = qRed(bottom);
|
||||
const double bl = qRed(bottomLeft);
|
||||
const double l = qRed(left);
|
||||
|
||||
// apply the sobel filter
|
||||
const double dX = (tr + pStrength * r + br) - (tl + pStrength * l + bl);
|
||||
const double dY = (bl + pStrength * b + br) - (tl + pStrength * t + tr);
|
||||
const double dZ = RGBA_MAX / pStrength;
|
||||
|
||||
glm::vec3 v(dX, dY, dZ);
|
||||
glm::normalize(v);
|
||||
|
||||
// convert to rgb from the value obtained computing the filter
|
||||
QRgb qRgbValue = qRgb(mapComponent(v.x), mapComponent(v.y), mapComponent(v.z));
|
||||
result.setPixel(i, j, qRgbValue);
|
||||
}
|
||||
}
|
||||
|
||||
gpu::Texture* theTexture = nullptr;
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
|
||||
// bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
if (image.hasAlphaChannel()) {
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
||||
}
|
||||
|
||||
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
||||
theTexture->autoGenerateMips(-1);
|
||||
}
|
||||
|
||||
return theTexture;
|
||||
}
|
||||
|
||||
class CubeLayout {
|
||||
public:
|
||||
int _widthRatio = 1;
|
||||
|
@ -197,7 +285,7 @@ public:
|
|||
_faceZNeg(fZN) {}
|
||||
};
|
||||
|
||||
gpu::Texture* TextureStorage::createCubeTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
gpu::Texture* TextureSource::createCubeTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
QImage image = srcImage;
|
||||
|
||||
int imageArea = image.width() * image.height();
|
||||
|
|
|
@ -32,13 +32,13 @@ public:
|
|||
int _environmentUsage = 0;
|
||||
};
|
||||
|
||||
// TextureStorage is a specialized version of the gpu::Texture::Storage
|
||||
// TextureSource is a specialized version of the gpu::Texture::Storage
|
||||
// It provides the mechanism to create a texture from a Url and the intended usage
|
||||
// that guides the internal format used
|
||||
class TextureStorage {
|
||||
class TextureSource {
|
||||
public:
|
||||
TextureStorage();
|
||||
~TextureStorage();
|
||||
TextureSource();
|
||||
~TextureSource();
|
||||
|
||||
const QUrl& getUrl() const { return _imageUrl; }
|
||||
gpu::Texture::Type getType() const { return _usage._type; }
|
||||
|
@ -51,6 +51,7 @@ public:
|
|||
bool isDefined() const;
|
||||
|
||||
static gpu::Texture* create2DTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||
static gpu::Texture* createNormalTextureFromBumpImage(const QImage& image, const std::string& srcImageName);
|
||||
static gpu::Texture* createCubeTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||
|
||||
protected:
|
||||
|
@ -58,7 +59,7 @@ protected:
|
|||
TextureUsage _usage;
|
||||
QUrl _imageUrl;
|
||||
};
|
||||
typedef std::shared_ptr< TextureStorage > TextureStoragePointer;
|
||||
typedef std::shared_ptr< TextureSource > TextureSourcePointer;
|
||||
|
||||
|
||||
|
||||
|
@ -66,7 +67,7 @@ class TextureMap {
|
|||
public:
|
||||
TextureMap() {}
|
||||
|
||||
void setTextureStorage(TextureStoragePointer& texStorage);
|
||||
void setTextureSource(TextureSourcePointer& texStorage);
|
||||
|
||||
bool isDefined() const;
|
||||
gpu::TextureView getTextureView() const;
|
||||
|
@ -78,7 +79,7 @@ public:
|
|||
const glm::vec2& getLightmapOffsetScale() const { return _lightmapOffsetScale; }
|
||||
|
||||
protected:
|
||||
TextureStoragePointer _textureStorage;
|
||||
TextureSourcePointer _textureSource;
|
||||
|
||||
Transform _texcoordTransform;
|
||||
glm::vec2 _lightmapOffsetScale{ 0.0f, 1.0f };
|
||||
|
@ -87,5 +88,5 @@ typedef std::shared_ptr< TextureMap > TextureMapPointer;
|
|||
|
||||
};
|
||||
|
||||
#endif // hifi_model_TextureStorage_h
|
||||
#endif // hifi_model_TextureMap_h
|
||||
|
||||
|
|
|
@ -2072,17 +2072,17 @@ static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const
|
|||
networkMaterial->diffuseTextureName = material.diffuseTexture.name;
|
||||
|
||||
auto diffuseMap = model::TextureMapPointer(new model::TextureMap());
|
||||
diffuseMap->setTextureStorage(networkMaterial->diffuseTexture->_textureStorage);
|
||||
diffuseMap->setTextureSource(networkMaterial->diffuseTexture->_textureSource);
|
||||
diffuseMap->setTextureTransform(material.diffuseTexture.transform);
|
||||
|
||||
material._material->setTextureMap(model::MaterialKey::DIFFUSE_MAP, diffuseMap);
|
||||
}
|
||||
if (!material.normalTexture.filename.isEmpty()) {
|
||||
networkMaterial->normalTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.normalTexture.filename)), NORMAL_TEXTURE, material.normalTexture.content);
|
||||
networkMaterial->normalTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.normalTexture.filename)), (material.normalTexture.isBumpmap ? BUMP_TEXTURE : NORMAL_TEXTURE), material.normalTexture.content);
|
||||
networkMaterial->normalTextureName = material.normalTexture.name;
|
||||
|
||||
auto normalMap = model::TextureMapPointer(new model::TextureMap());
|
||||
normalMap->setTextureStorage(networkMaterial->normalTexture->_textureStorage);
|
||||
normalMap->setTextureSource(networkMaterial->normalTexture->_textureSource);
|
||||
|
||||
material._material->setTextureMap(model::MaterialKey::NORMAL_MAP, normalMap);
|
||||
}
|
||||
|
@ -2091,7 +2091,7 @@ static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const
|
|||
networkMaterial->specularTextureName = material.specularTexture.name;
|
||||
|
||||
auto glossMap = model::TextureMapPointer(new model::TextureMap());
|
||||
glossMap->setTextureStorage(networkMaterial->specularTexture->_textureStorage);
|
||||
glossMap->setTextureSource(networkMaterial->specularTexture->_textureSource);
|
||||
|
||||
material._material->setTextureMap(model::MaterialKey::GLOSS_MAP, glossMap);
|
||||
}
|
||||
|
@ -2102,7 +2102,7 @@ static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const
|
|||
checkForTexcoordLightmap = true;
|
||||
|
||||
auto lightmapMap = model::TextureMapPointer(new model::TextureMap());
|
||||
lightmapMap->setTextureStorage(networkMaterial->emissiveTexture->_textureStorage);
|
||||
lightmapMap->setTextureSource(networkMaterial->emissiveTexture->_textureSource);
|
||||
lightmapMap->setTextureTransform(material.emissiveTexture.transform);
|
||||
lightmapMap->setLightmapOffsetScale(material.emissiveParams.x, material.emissiveParams.y);
|
||||
|
||||
|
|
Loading…
Reference in a new issue