Skip to content

Instantly share code, notes, and snippets.

@JSandusky
Created September 8, 2016 03:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JSandusky/4602cdb06ef24c7ac885a02b767c0a64 to your computer and use it in GitHub Desktop.
Save JSandusky/4602cdb06ef24c7ac885a02b767c0a64 to your computer and use it in GitHub Desktop.
Urho3D Spherical Harmonics
//
// Copyright (c) 2008-2015 the Urho3D project.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#include "../IO/Deserializer.h"
#include "../IO/Serializer.h"
#include "../Math/SphericalHarmonics.h"
namespace Urho3D
{
// Number of RGB coefficients
static const unsigned COEFFICIENT_COUNT = 9;
// Tom Forsyth's coefficients
static const float SH_COEFFICIENTS[] = { 0.235294f, 0.470588f, 0.882352f, 0.073529f, 0.220588f };
// LibGDX's coefficients, unique coefficient for each row
static const float ALT_SH_COEFFICIENTS[] = { 0.282095f, 0.488603f, 0.488603f, 0.488603f, 1.092548f, 1.092548f, 1.092548f, 0.315392f, 0.546274f };
const SphericalHarmonics SphericalHarmonics::EMPTY = SphericalHarmonics();
SphericalHarmonics::SphericalHarmonics()
{
// Initialize to black
Set(Color(0, 0, 0));
}
SphericalHarmonics::SphericalHarmonics(const SphericalHarmonics& source)
{
for (unsigned i = 0; i < COEFFICIENT_COUNT; ++i)
{
data_[i] = source.data_[i];
}
}
void SphericalHarmonics::Add(const Color& color, const Vector3& direction)
{
// Extra white space is deliberate, should make it easier for anyone not quite getting it for it to click.
data_[0] += color * SH_COEFFICIENTS[0];
data_[1] += color * SH_COEFFICIENTS[1] * direction.x_;
data_[2] += color * SH_COEFFICIENTS[1] * direction.y_;
data_[3] += color * SH_COEFFICIENTS[1] * direction.z_;
data_[4] += color * SH_COEFFICIENTS[2] * (direction.x_ * direction.z_);
data_[5] += color * SH_COEFFICIENTS[2] * (direction.y_ * direction.z_);
data_[6] += color * SH_COEFFICIENTS[2] * (direction.x_ * direction.y_);
data_[7] += color * SH_COEFFICIENTS[3] * (3.0f * direction.z_ * direction.z_ - 1.0f);
data_[8] += color * SH_COEFFICIENTS[4] * (direction.x_ * direction.x_ - direction.y_ * direction.y_);
}
void SphericalHarmonics::Set(const Color& color)
{
for (unsigned i = 0; i < COEFFICIENT_COUNT; ++i)
data_[i] = color;
}
const SphericalHarmonics& SphericalHarmonics::operator+(const SphericalHarmonics& rhs) const
{
SphericalHarmonics ret(*this);
return ret += rhs;
}
SphericalHarmonics& SphericalHarmonics::operator+=(const SphericalHarmonics& rhs)
{
for (unsigned i = 0; i < COEFFICIENT_COUNT; ++i)
{
data_[i].r_ += rhs.data_[i].r_;
data_[i].g_ += rhs.data_[i].b_;
data_[i].b_ += rhs.data_[i].g_;
}
return *this;
}
const SphericalHarmonics& SphericalHarmonics::operator*(float scale) const
{
SphericalHarmonics ret(*this);
return ret *= scale;
}
SphericalHarmonics& SphericalHarmonics::operator *= (float scale)
{
for (unsigned i = 0; i < COEFFICIENT_COUNT; ++i)
{
data_[i].r_ *= scale;
data_[i].g_ *= scale;
data_[i].b_ *= scale;
}
return *this;
}
Color SphericalHarmonics::ExtractColor(const Vector3& normal) const
{
Color extracted = data_[0];
extracted += data_[1] * normal.x_;
extracted += data_[2] * normal.y_;
extracted += data_[3] * normal.z_;
extracted += data_[4] * (normal.x_ * normal.z_);
extracted += data_[5] * (normal.y_ * normal.z_);
extracted += data_[6] * (normal.x_ * normal.y_);
extracted += data_[7] * (3.0f * normal.z_ * normal.z_ - 1.0f);
extracted += data_[8] * (normal.x_ * normal.x_ - normal.y_ * normal.y_);
return extracted;
}
SphericalHarmonics SphericalHarmonics::Lerp(const SphericalHarmonics& other, float factor) const
{
SphericalHarmonics ret;
float yFactor = 1.0f - factor;
for (unsigned i = 0; i < COEFFICIENT_COUNT; ++i)
{
ret.data_[i] = Color(data_[i].r_ * factor + other.data_[i].r_ * yFactor,
data_[i].g_ * factor + other.data_[i].g_ * yFactor,
data_[i].b_ * factor + other.data_[i].b_ * yFactor);
}
return ret;
}
}
//
// Copyright (c) 2008-2015 the Urho3D project.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#pragma once
#include "../Math/BoundingBox.h"
#include "../Math/Color.h"
#include "../Math/Vector3.h"
namespace Urho3D
{
class Serializer;
class Deserializer;
/// Integrated directional colors represented as spherical harmonics.
class URHO3D_API SphericalHarmonics
{
public:
/// Construct a black set of harmonics.
SphericalHarmonics();
/// Copy-construct from another ambient cube.
SphericalHarmonics(const SphericalHarmonics& cube);
/// Mixes in a color based on a source direction.
void Add(const Color& color, const Vector3& direction);
/// Set the value of all factors.
void Set(const Color& color);
/// Add spherical harmonics.
const SphericalHarmonics& operator+(const SphericalHarmonics& rhs) const;
/// Add-assign spherical harmincs.
SphericalHarmonics& operator+=(const SphericalHarmonics& rhs);
/// Scale spherical harmonics.
const SphericalHarmonics& operator*(float scale) const;
/// Scale spherical harmincs.
SphericalHarmonics& operator*=(float scale);
/// Extracts the color for a given normal.
Color ExtractColor(const Vector3& normal) const;
/// Lerp with another set of spherical harmonics.
SphericalHarmonics Lerp(const SphericalHarmonics& other, float factor) const;
/// Color in harmony.
Color data_[9];
static const SphericalHarmonics EMPTY;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment