mirror of
https://github.com/overte-org/overte.git
synced 2025-07-24 18:23:57 +02:00
Merge pull request #4863 from samcake/orange
Using the skymap for ambient lighting
This commit is contained in:
commit
d1f52231be
11 changed files with 291 additions and 8 deletions
|
@ -3377,7 +3377,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
|
||||||
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||||
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity(), skyStage->getSunLight()->getAmbientIntensity());
|
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity(), skyStage->getSunLight()->getAmbientIntensity());
|
||||||
DependencyManager::get<DeferredLightingEffect>()->setGlobalAtmosphere(skyStage->getAtmosphere());
|
DependencyManager::get<DeferredLightingEffect>()->setGlobalAtmosphere(skyStage->getAtmosphere());
|
||||||
// NOt yet DependencyManager::get<DeferredLightingEffect>()->setGlobalSkybox(skybox);
|
DependencyManager::get<DeferredLightingEffect>()->setGlobalSkybox(skybox);
|
||||||
|
|
||||||
PROFILE_RANGE("DeferredLighting");
|
PROFILE_RANGE("DeferredLighting");
|
||||||
PerformanceTimer perfTimer("lighting");
|
PerformanceTimer perfTimer("lighting");
|
||||||
|
|
|
@ -57,7 +57,7 @@ const Texture::PixelsPointer Texture::Storage::getMipFace(uint16 level, uint8 fa
|
||||||
|
|
||||||
void Texture::Storage::notifyMipFaceGPULoaded(uint16 level, uint8 face) const {
|
void Texture::Storage::notifyMipFaceGPULoaded(uint16 level, uint8 face) const {
|
||||||
PixelsPointer mipFace = getMipFace(level, face);
|
PixelsPointer mipFace = getMipFace(level, face);
|
||||||
if (mipFace) {
|
if (mipFace && (_type != TEX_CUBE)) {
|
||||||
mipFace->_isGPULoaded = true;
|
mipFace->_isGPULoaded = true;
|
||||||
mipFace->_sysmem.resize(0);
|
mipFace->_sysmem.resize(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,7 +127,7 @@ public:
|
||||||
CUBE_FACE_LEFT_NEG_X,
|
CUBE_FACE_LEFT_NEG_X,
|
||||||
CUBE_FACE_TOP_POS_Y,
|
CUBE_FACE_TOP_POS_Y,
|
||||||
CUBE_FACE_BOTTOM_NEG_Y,
|
CUBE_FACE_BOTTOM_NEG_Y,
|
||||||
CUBE_FACE_BACK_POS_X,
|
CUBE_FACE_BACK_POS_Z,
|
||||||
CUBE_FACE_FRONT_NEG_Z,
|
CUBE_FACE_FRONT_NEG_Z,
|
||||||
|
|
||||||
NUM_CUBE_FACES, // Not a valid vace index
|
NUM_CUBE_FACES, // Not a valid vace index
|
||||||
|
|
|
@ -99,3 +99,6 @@ void Light::setShowContour(float show) {
|
||||||
}
|
}
|
||||||
editSchema()._control.w = show;
|
editSchema()._control.w = show;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -180,6 +180,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
typedef std::shared_ptr< SphericalHarmonics > SHPointer;
|
||||||
|
|
||||||
class Light {
|
class Light {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -39,6 +39,9 @@ void Skybox::setColor(const Color& color) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Skybox::setCubemap(const gpu::TexturePointer& cubemap) {
|
void Skybox::setCubemap(const gpu::TexturePointer& cubemap) {
|
||||||
|
if (_isSHValid && (cubemap != _cubemap)) {
|
||||||
|
_isSHValid = false;
|
||||||
|
}
|
||||||
_cubemap = cubemap;
|
_cubemap = cubemap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +52,9 @@ void Skybox::clearCubemap() {
|
||||||
void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Skybox& skybox) {
|
void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Skybox& skybox) {
|
||||||
|
|
||||||
if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) {
|
if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) {
|
||||||
|
|
||||||
|
skybox.getIrradianceSH();
|
||||||
|
|
||||||
static gpu::PipelinePointer thePipeline;
|
static gpu::PipelinePointer thePipeline;
|
||||||
static gpu::BufferPointer theBuffer;
|
static gpu::BufferPointer theBuffer;
|
||||||
static gpu::Stream::FormatPointer theFormat;
|
static gpu::Stream::FormatPointer theFormat;
|
||||||
|
@ -113,3 +119,223 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky
|
||||||
batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(skybox.getColor(),1.0f), 0.f, 0);
|
batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(skybox.getColor(),1.0f), 0.f, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
glm::vec3 sRGBToLinear(glm::vec3& color) {
|
||||||
|
const float GAMMA_CORRECTION = 2.2f;
|
||||||
|
return glm::pow(color, glm::vec3(GAMMA_CORRECTION));
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 linearTosRGB(glm::vec3& color) {
|
||||||
|
const float GAMMA_CORRECTION_INV = 1.0f / 2.2f;
|
||||||
|
return glm::pow(color, glm::vec3(GAMMA_CORRECTION_INV));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Originial code for the Spherical Harmonics taken from "Sun and Black Cat- Igor Dykhta (igor dykhta email) © 2007-2014 "
|
||||||
|
void sphericalHarmonicsAdd(float * result, int order, const float * inputA, const float * inputB) {
|
||||||
|
const int numCoeff = order * order;
|
||||||
|
for(int i=0; i < numCoeff; i++) {
|
||||||
|
result[i] = inputA[i] + inputB[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sphericalHarmonicsScale(float * result, int order, const float * input, float scale) {
|
||||||
|
const int numCoeff = order * order;
|
||||||
|
for(int i=0; i < numCoeff; i++) {
|
||||||
|
result[i] = input[i] * scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sphericalHarmonicsEvaluateDirection(float * result, int order, const glm::vec3 & dir) {
|
||||||
|
// calculate coefficients for first 3 bands of spherical harmonics
|
||||||
|
double P_0_0 = 0.282094791773878140;
|
||||||
|
double P_1_0 = 0.488602511902919920 * dir.z;
|
||||||
|
double P_1_1 = -0.488602511902919920;
|
||||||
|
double P_2_0 = 0.946174695757560080 * dir.z * dir.z - 0.315391565252520050;
|
||||||
|
double P_2_1 = -1.092548430592079200 * dir.z;
|
||||||
|
double P_2_2 = 0.546274215296039590;
|
||||||
|
result[0] = P_0_0;
|
||||||
|
result[1] = P_1_1 * dir.y;
|
||||||
|
result[2] = P_1_0;
|
||||||
|
result[3] = P_1_1 * dir.x;
|
||||||
|
result[4] = P_2_2 * (dir.x * dir.y + dir.y * dir.x);
|
||||||
|
result[5] = P_2_1 * dir.y;
|
||||||
|
result[6] = P_2_0;
|
||||||
|
result[7] = P_2_1 * dir.x;
|
||||||
|
result[8] = P_2_2 * (dir.x * dir.x - dir.y * dir.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<glm::vec3> & output, const uint order) {
|
||||||
|
const uint sqOrder = order*order;
|
||||||
|
|
||||||
|
// allocate memory for calculations
|
||||||
|
output.resize(sqOrder);
|
||||||
|
std::vector<float> resultR(sqOrder);
|
||||||
|
std::vector<float> resultG(sqOrder);
|
||||||
|
std::vector<float> resultB(sqOrder);
|
||||||
|
|
||||||
|
int width, height;
|
||||||
|
|
||||||
|
// initialize values
|
||||||
|
float fWt = 0.0f;
|
||||||
|
for(uint i=0; i < sqOrder; i++) {
|
||||||
|
output[i] = glm::vec3(0.0f);
|
||||||
|
resultR[i] = 0.0f;
|
||||||
|
resultG[i] = 0;
|
||||||
|
resultB[i] = 0;
|
||||||
|
}
|
||||||
|
std::vector<float> shBuff(sqOrder);
|
||||||
|
std::vector<float> shBuffB(sqOrder);
|
||||||
|
// get width and height
|
||||||
|
width = height = cubeTexture.getWidth();
|
||||||
|
if(width != height) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float UCHAR_TO_FLOAT = 1.0f / float(std::numeric_limits<unsigned char>::max());
|
||||||
|
|
||||||
|
// for each face of cube texture
|
||||||
|
for(int face=0; face < gpu::Texture::NUM_CUBE_FACES; face++) {
|
||||||
|
|
||||||
|
auto numComponents = cubeTexture.accessStoredMipFace(0,face)->_format.getDimensionCount();
|
||||||
|
auto data = cubeTexture.accessStoredMipFace(0,face)->_sysmem.readData();
|
||||||
|
if (data == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// step between two texels for range [0, 1]
|
||||||
|
float invWidth = 1.0f / float(width);
|
||||||
|
// initial negative bound for range [-1, 1]
|
||||||
|
float negativeBound = -1.0f + invWidth;
|
||||||
|
// step between two texels for range [-1, 1]
|
||||||
|
float invWidthBy2 = 2.0f / float(width);
|
||||||
|
|
||||||
|
for(int y=0; y < width; y++) {
|
||||||
|
// texture coordinate V in range [-1 to 1]
|
||||||
|
const float fV = negativeBound + float(y) * invWidthBy2;
|
||||||
|
|
||||||
|
for(int x=0; x < width; x++) {
|
||||||
|
// texture coordinate U in range [-1 to 1]
|
||||||
|
const float fU = negativeBound + float(x) * invWidthBy2;
|
||||||
|
|
||||||
|
// determine direction from center of cube texture to current texel
|
||||||
|
glm::vec3 dir;
|
||||||
|
switch(face) {
|
||||||
|
case gpu::Texture::CUBE_FACE_RIGHT_POS_X: {
|
||||||
|
dir.x = 1.0f;
|
||||||
|
dir.y = 1.0f - (invWidthBy2 * float(y) + invWidth);
|
||||||
|
dir.z = 1.0f - (invWidthBy2 * float(x) + invWidth);
|
||||||
|
dir = -dir;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::Texture::CUBE_FACE_LEFT_NEG_X: {
|
||||||
|
dir.x = -1.0f;
|
||||||
|
dir.y = 1.0f - (invWidthBy2 * float(y) + invWidth);
|
||||||
|
dir.z = -1.0f + (invWidthBy2 * float(x) + invWidth);
|
||||||
|
dir = -dir;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::Texture::CUBE_FACE_TOP_POS_Y: {
|
||||||
|
dir.x = - 1.0f + (invWidthBy2 * float(x) + invWidth);
|
||||||
|
dir.y = 1.0f;
|
||||||
|
dir.z = - 1.0f + (invWidthBy2 * float(y) + invWidth);
|
||||||
|
dir = -dir;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::Texture::CUBE_FACE_BOTTOM_NEG_Y: {
|
||||||
|
dir.x = - 1.0f + (invWidthBy2 * float(x) + invWidth);
|
||||||
|
dir.y = - 1.0f;
|
||||||
|
dir.z = 1.0f - (invWidthBy2 * float(y) + invWidth);
|
||||||
|
dir = -dir;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::Texture::CUBE_FACE_BACK_POS_Z: {
|
||||||
|
dir.x = - 1.0f + (invWidthBy2 * float(x) + invWidth);
|
||||||
|
dir.y = 1.0f - (invWidthBy2 * float(y) + invWidth);
|
||||||
|
dir.z = 1.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::Texture::CUBE_FACE_FRONT_NEG_Z: {
|
||||||
|
dir.x = 1.0f - (invWidthBy2 * float(x) + invWidth);
|
||||||
|
dir.y = 1.0f - (invWidthBy2 * float(y) + invWidth);
|
||||||
|
dir.z = - 1.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalize direction
|
||||||
|
dir = glm::normalize(dir);
|
||||||
|
|
||||||
|
// scale factor depending on distance from center of the face
|
||||||
|
const float fDiffSolid = 4.0f / ((1.0f + fU*fU + fV*fV) *
|
||||||
|
sqrtf(1.0f + fU*fU + fV*fV));
|
||||||
|
fWt += fDiffSolid;
|
||||||
|
|
||||||
|
// calculate coefficients of spherical harmonics for current direction
|
||||||
|
sphericalHarmonicsEvaluateDirection(shBuff.data(), order, dir);
|
||||||
|
|
||||||
|
// index of texel in texture
|
||||||
|
uint pixOffsetIndex = (x + y * width) * numComponents;
|
||||||
|
|
||||||
|
// get color from texture and map to range [0, 1]
|
||||||
|
glm::vec3 clr(float(data[pixOffsetIndex]) * UCHAR_TO_FLOAT,
|
||||||
|
float(data[pixOffsetIndex+1]) * UCHAR_TO_FLOAT,
|
||||||
|
float(data[pixOffsetIndex+2]) * UCHAR_TO_FLOAT);
|
||||||
|
|
||||||
|
// Gamma correct
|
||||||
|
clr = sRGBToLinear(clr);
|
||||||
|
|
||||||
|
// scale color and add to previously accumulated coefficients
|
||||||
|
sphericalHarmonicsScale(shBuffB.data(), order,
|
||||||
|
shBuff.data(), clr.r * fDiffSolid);
|
||||||
|
sphericalHarmonicsAdd(resultR.data(), order,
|
||||||
|
resultR.data(), shBuffB.data());
|
||||||
|
sphericalHarmonicsScale(shBuffB.data(), order,
|
||||||
|
shBuff.data(), clr.g * fDiffSolid);
|
||||||
|
sphericalHarmonicsAdd(resultG.data(), order,
|
||||||
|
resultG.data(), shBuffB.data());
|
||||||
|
sphericalHarmonicsScale(shBuffB.data(), order,
|
||||||
|
shBuff.data(), clr.b * fDiffSolid);
|
||||||
|
sphericalHarmonicsAdd(resultB.data(), order,
|
||||||
|
resultB.data(), shBuffB.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// final scale for coefficients
|
||||||
|
const float fNormProj = (4.0f * glm::pi<float>()) / fWt;
|
||||||
|
sphericalHarmonicsScale(resultR.data(), order, resultR.data(), fNormProj);
|
||||||
|
sphericalHarmonicsScale(resultG.data(), order, resultG.data(), fNormProj);
|
||||||
|
sphericalHarmonicsScale(resultB.data(), order, resultB.data(), fNormProj);
|
||||||
|
|
||||||
|
// save result
|
||||||
|
for(uint i=0; i < sqOrder; i++) {
|
||||||
|
// gamma Correct
|
||||||
|
// output[i] = linearTosRGB(glm::vec3(resultR[i], resultG[i], resultB[i]));
|
||||||
|
output[i] = glm::vec3(resultR[i], resultG[i], resultB[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const SphericalHarmonics& Skybox::getIrradianceSH() const {
|
||||||
|
if (!_isSHValid) {
|
||||||
|
if (_cubemap && _cubemap->isDefined()) {
|
||||||
|
std::vector< glm::vec3 > coefs;
|
||||||
|
sphericalHarmonicsFromTexture(*_cubemap, coefs, 3);
|
||||||
|
|
||||||
|
_irradianceSH.L00 = coefs[0];
|
||||||
|
_irradianceSH.L1m1 = coefs[1];
|
||||||
|
_irradianceSH.L10 = coefs[2];
|
||||||
|
_irradianceSH.L11 = coefs[3];
|
||||||
|
_irradianceSH.L2m2 = coefs[4];
|
||||||
|
_irradianceSH.L2m1 = coefs[5];
|
||||||
|
_irradianceSH.L20 = coefs[6];
|
||||||
|
_irradianceSH.L21 = coefs[7];
|
||||||
|
_irradianceSH.L22 = coefs[8];
|
||||||
|
|
||||||
|
_isSHValid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _irradianceSH;
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
|
|
||||||
#include "gpu/Texture.h"
|
#include "gpu/Texture.h"
|
||||||
|
|
||||||
|
#include "Light.h"
|
||||||
|
|
||||||
class ViewFrustum;
|
class ViewFrustum;
|
||||||
//class Transform;
|
//class Transform;
|
||||||
namespace gpu { class Batch; }
|
namespace gpu { class Batch; }
|
||||||
|
@ -34,11 +36,16 @@ public:
|
||||||
const gpu::TexturePointer& getCubemap() const { return _cubemap; }
|
const gpu::TexturePointer& getCubemap() const { return _cubemap; }
|
||||||
void clearCubemap();
|
void clearCubemap();
|
||||||
|
|
||||||
|
const SphericalHarmonics& getIrradianceSH() const;
|
||||||
|
|
||||||
static void render(gpu::Batch& batch, const ViewFrustum& frustum, const Skybox& skybox);
|
static void render(gpu::Batch& batch, const ViewFrustum& frustum, const Skybox& skybox);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
gpu::TexturePointer _cubemap;
|
gpu::TexturePointer _cubemap;
|
||||||
|
|
||||||
|
mutable SphericalHarmonics _irradianceSH;
|
||||||
|
mutable bool _isSHValid = false;
|
||||||
|
|
||||||
Color _color{1.0f, 1.0f, 1.0f};
|
Color _color{1.0f, 1.0f, 1.0f};
|
||||||
};
|
};
|
||||||
typedef std::shared_ptr< Skybox > SkyboxPointer;
|
typedef std::shared_ptr< Skybox > SkyboxPointer;
|
||||||
|
|
|
@ -20,5 +20,6 @@ varying vec3 color;
|
||||||
void main(void) {
|
void main(void) {
|
||||||
vec3 coord = normalize(normal);
|
vec3 coord = normalize(normal);
|
||||||
vec4 texel = textureCube(cubeMap, coord);
|
vec4 texel = textureCube(cubeMap, coord);
|
||||||
gl_FragData[0] = vec4(texel.xyz * color, 0.0);
|
vec3 pixel = pow(texel.xyz * color, vec3(1.0/2.2)); // manual Gamma correction
|
||||||
|
gl_FragData[0] = vec4(pixel, 0.0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,8 +111,8 @@ vec3 evalSkyboxGlobalColor(float shadowAttenuation, vec3 position, vec3 normal,
|
||||||
vec4 fragEyeVector = invViewMat * vec4(-position, 0.0);
|
vec4 fragEyeVector = invViewMat * vec4(-position, 0.0);
|
||||||
vec3 fragEyeDir = normalize(fragEyeVector.xyz);
|
vec3 fragEyeDir = normalize(fragEyeVector.xyz);
|
||||||
|
|
||||||
vec3 color = diffuse.rgb * evalSkyboxLight(fragNormal, 0.75).xyz * getLightAmbientIntensity(light);
|
vec3 color = diffuse.rgb * evalSphericalLight(ambientSphere, fragNormal).xyz * getLightAmbientIntensity(light);
|
||||||
|
|
||||||
vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss);
|
vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss);
|
||||||
|
|
||||||
color += vec3(diffuse + shading.rgb) * shading.w * shadowAttenuation * getLightColor(light) * getLightIntensity(light);
|
color += vec3(diffuse + shading.rgb) * shading.w * shadowAttenuation * getLightColor(light) * getLightIntensity(light);
|
||||||
|
|
|
@ -291,7 +291,12 @@ void DeferredLightingEffect::render() {
|
||||||
auto globalLight = _allocatedLights[_globalLights.front()];
|
auto globalLight = _allocatedLights[_globalLights.front()];
|
||||||
|
|
||||||
if (locations->ambientSphere >= 0) {
|
if (locations->ambientSphere >= 0) {
|
||||||
auto sh = globalLight->getAmbientSphere();
|
model::SphericalHarmonics sh;
|
||||||
|
if (useSkyboxCubemap) {
|
||||||
|
sh = _skybox->getIrradianceSH();
|
||||||
|
} else {
|
||||||
|
sh = globalLight->getAmbientSphere();
|
||||||
|
}
|
||||||
for (int i =0; i <model::SphericalHarmonics::NUM_COEFFICIENTS; i++) {
|
for (int i =0; i <model::SphericalHarmonics::NUM_COEFFICIENTS; i++) {
|
||||||
program->setUniformValue(locations->ambientSphere + i, *(((QVector4D*) &sh) + i));
|
program->setUniformValue(locations->ambientSphere + i, *(((QVector4D*) &sh) + i));
|
||||||
}
|
}
|
||||||
|
|
|
@ -514,7 +514,8 @@ void NetworkTexture::setImage(const QImage& image, bool translucent, const QColo
|
||||||
|
|
||||||
if ((_width > 0) && (_height > 0)) {
|
if ((_width > 0) && (_height > 0)) {
|
||||||
|
|
||||||
bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
// 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 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));
|
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||||
|
@ -602,6 +603,45 @@ void NetworkTexture::setImage(const QImage& image, bool translucent, const QColo
|
||||||
faces.push_back(image.copy(QRect(3 * faceWidth, faceWidth, faceWidth, faceWidth)).mirrored(true, false));
|
faces.push_back(image.copy(QRect(3 * faceWidth, faceWidth, faceWidth, faceWidth)).mirrored(true, false));
|
||||||
// Front = -Z
|
// Front = -Z
|
||||||
faces.push_back(image.copy(QRect(1 * faceWidth, faceWidth, faceWidth, faceWidth)).mirrored(true, false));
|
faces.push_back(image.copy(QRect(1 * faceWidth, faceWidth, faceWidth, faceWidth)).mirrored(true, false));
|
||||||
|
|
||||||
|
} else if ((_height / 4) == (_width / 3)) {
|
||||||
|
int faceWidth = _height / 4;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// Right = +X
|
||||||
|
faces.push_back(image.copy(QRect(2 * faceWidth, faceWidth, faceWidth, faceWidth)).mirrored(true, false));
|
||||||
|
// Left = -X
|
||||||
|
faces.push_back(image.copy(QRect(0 * faceWidth, faceWidth, faceWidth, faceWidth)).mirrored(true, false));
|
||||||
|
// Top = +Y
|
||||||
|
faces.push_back(image.copy(QRect(1 * faceWidth, 0, faceWidth, faceWidth)).mirrored(false, true));
|
||||||
|
// Bottom = -Y
|
||||||
|
faces.push_back(image.copy(QRect(1 * faceWidth, 2 * faceWidth, faceWidth, faceWidth)).mirrored(false, true));
|
||||||
|
// Back = +Z
|
||||||
|
faces.push_back(image.copy(QRect(1 * faceWidth, 3 * faceWidth, faceWidth, faceWidth)).mirrored(false, true));
|
||||||
|
// Front = -Z
|
||||||
|
faces.push_back(image.copy(QRect(1 * faceWidth, faceWidth, faceWidth, faceWidth)).mirrored(true, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (faces.size() == gpu::Texture::NUM_FACES_PER_TYPE[gpu::Texture::TEX_CUBE]) {
|
if (faces.size() == gpu::Texture::NUM_FACES_PER_TYPE[gpu::Texture::TEX_CUBE]) {
|
||||||
|
|
Loading…
Reference in a new issue