Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- void sphericalHarmonicsEvaluateDirection(float * result, int order,
- const Math::Vector3 & dir)
- {
- result[0] = 0.282095;
- result[1] = 0.488603 * dir.y;
- result[2] = 0.488603 * dir.z;
- result[3] = 0.488603 * dir.x;
- result[4] = 1.092548 * dir.x*dir.y;
- result[5] = 1.092548 * dir.y*dir.z;
- result[6] = 0.315392 * (3.f*dir.z*dir.z - 1.f);
- result[7] = 1.092548 * dir.x * dir.z;
- result[8] = 0.546274 * (dir.x*dir.x - dir.y*dir.y);
- }
- 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 sphericalHarmonicsFromTexture(GLuint cubeTexture,
- std::vector<Math::Vector3> & 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);
- // variables that describe current face of cube texture
- GLubyte* data;
- GLint width, height;
- GLint internalFormat;
- GLint numComponents;
- // initialize values
- float fWt = 0.0f;
- for (uint i = 0; i < sqOrder; i++)
- {
- output[i].x = 0;
- output[i].y = 0;
- output[i].z = 0;
- resultR[i] = 0;
- resultG[i] = 0;
- resultB[i] = 0;
- }
- std::vector<float> shBuff(sqOrder);
- std::vector<float> shBuffB(sqOrder);
- const GLenum cubeSides[6] = {
- GL_TEXTURE_CUBE_MAP_POSITIVE_Y, // Top
- GL_TEXTURE_CUBE_MAP_NEGATIVE_X, // Left
- GL_TEXTURE_CUBE_MAP_POSITIVE_Z, // Front
- GL_TEXTURE_CUBE_MAP_POSITIVE_X, // Right
- GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, // Back
- GL_TEXTURE_CUBE_MAP_NEGATIVE_Y // Bottom
- };
- // bind current texture
- glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTexture);
- int level = 0;
- // for each face of cube texture
- for (int face = 0; face < 6; face++)
- {
- // get width and height
- glGetTexLevelParameteriv(cubeSides[face], level, GL_TEXTURE_WIDTH, &width);
- glGetTexLevelParameteriv(cubeSides[face], level, GL_TEXTURE_HEIGHT, &height);
- if (width != height)
- {
- return;
- }
- // get format of data in texture
- glGetTexLevelParameteriv(cubeSides[face], level,
- GL_TEXTURE_INTERNAL_FORMAT, &internalFormat);
- // get data from texture
- if (internalFormat == GL_RGBA)
- {
- numComponents = 4;
- data = new GLubyte[numComponents * width * width];
- }
- else if (internalFormat == GL_RGB)
- {
- numComponents = 3;
- data = new GLubyte[numComponents * width * width];
- }
- else
- {
- return;
- }
- glGetTexImage(cubeSides[face], level, internalFormat, GL_UNSIGNED_BYTE, data);
- // 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
- Math::Vector3 dir;
- switch (cubeSides[face])
- {
- case GL_TEXTURE_CUBE_MAP_POSITIVE_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 GL_TEXTURE_CUBE_MAP_NEGATIVE_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 GL_TEXTURE_CUBE_MAP_POSITIVE_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 GL_TEXTURE_CUBE_MAP_NEGATIVE_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 GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
- dir.x = -1.0f + (invWidthBy2 * float(x) + invWidth);
- dir.y = 1.0f - (invWidthBy2 * float(y) + invWidth);
- dir.z = 1.0f;
- break;
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_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 = Math::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]
- Math::Vector3 clr(
- float(data[pixOffsetIndex]) / 255,
- float(data[pixOffsetIndex + 1]) / 255,
- float(data[pixOffsetIndex + 2]) / 255
- );
- //clr.x = pow(clr.x, 1.1f);
- //clr.y = pow(clr.y, 1.1f);
- //clr.z = pow(clr.z, 1.1f);
- clr.x = clr.x*0.5f;
- clr.y = clr.y*0.5f;
- clr.z = clr.z*0.5f;
- // scale color and add to previously accumulated coefficients
- sphericalHarmonicsScale(shBuffB.data(), order,
- shBuff.data(), clr.x * fDiffSolid);
- sphericalHarmonicsAdd(resultR.data(), order,
- resultR.data(), shBuffB.data());
- sphericalHarmonicsScale(shBuffB.data(), order,
- shBuff.data(), clr.y * fDiffSolid);
- sphericalHarmonicsAdd(resultG.data(), order,
- resultG.data(), shBuffB.data());
- sphericalHarmonicsScale(shBuffB.data(), order,
- shBuff.data(), clr.z * fDiffSolid);
- sphericalHarmonicsAdd(resultB.data(), order,
- resultB.data(), shBuffB.data());
- }
- }
- delete[] data;
- }
- // final scale for coefficients
- const float fNormProj = (4.0f * Math::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++)
- {
- output[i].x = resultR[i];
- output[i].y = resultG[i];
- output[i].z = resultB[i];
- }
- //glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement