kicad/3d-viewer/3d_rendering/3d_render_raytracing/light.h

203 lines
5.5 KiB
C++

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 2015-2020 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file light.h
* @brief Declare and implement light sources.
*/
#ifndef _LIGHT_H_
#define _LIGHT_H_
#include "ray.h"
#include "hitinfo.h"
/**
* A base light class to derive to implement other light classes.
*/
class LIGHT
{
public:
LIGHT() { m_castShadow = true; }
virtual ~LIGHT() {}
/**
* Get parameters from this light.
*
* @param aHitPoint: input hit position
* @param aOutVectorToLight a vector that points from the hit
* position in direction to the light
* @param aOutLightColor the color of this light
* @param aOutDistance the distance from the point to the light
*/
virtual void GetLightParameters( const SFVEC3F& aHitPoint, SFVEC3F& aOutVectorToLight,
SFVEC3F& aOutLightColor, float& aOutDistance ) const = 0;
void SetCastShadows( bool aCastShadow ) { m_castShadow = aCastShadow; }
bool GetCastShadows() const { return m_castShadow; }
protected:
bool m_castShadow;
};
/**
* Point light source based on http://ogldev.atspace.co.uk/www/tutorial20/tutorial20.html.
*/
class POINT_LIGHT : public LIGHT
{
public:
POINT_LIGHT( const SFVEC3F& aPos, const SFVEC3F& aColor )
{
m_position = aPos;
m_color = aColor;
m_att_constant = 0.9f;
m_att_linear = 0.0005f;
m_att_exp = 0.001f;
m_castShadow = true;
}
// Imported functions from LIGHT
void GetLightParameters( const SFVEC3F& aHitPoint, SFVEC3F& aOutVectorToLight,
SFVEC3F& aOutLightColor, float& aOutDistance ) const override
{
const SFVEC3F vectorLight = m_position - aHitPoint;
aOutDistance = glm::length( vectorLight );
aOutVectorToLight = vectorLight / aOutDistance; // normalize
const float att = 1.0f / ( m_att_constant +
m_att_linear * aOutDistance +
m_att_exp * aOutDistance * aOutDistance );
if( att <= 0.0f )
aOutLightColor = SFVEC3F( 0.0f, 0.0f, 0.0f );
else
aOutLightColor = m_color * att;
}
private:
SFVEC3F m_position;
SFVEC3F m_color;
float m_att_constant;
float m_att_linear;
float m_att_exp;
};
/**
* A light source based only on a directional vector.
*/
class DIRECTIONAL_LIGHT : public LIGHT
{
public:
DIRECTIONAL_LIGHT( const SFVEC3F& aDir, const SFVEC3F& aColor )
{
// Invert light direction and make sure it is normalized
m_inv_direction = glm::normalize( -aDir );
m_color = aColor;
m_castShadow = true; // Set as default to cast shadows
}
/**
* Set directional light orientation.
*
* @param aDir is the vector defining the direction of the light source.
*/
void SetDirection( const SFVEC3F& aDir ) { m_inv_direction = -aDir; }
// Imported functions from LIGHT
void GetLightParameters( const SFVEC3F& aHitPoint, SFVEC3F& aOutVectorToLight,
SFVEC3F& aOutLightColor, float& aOutDistance ) const override
{
(void)aHitPoint; // unused
aOutVectorToLight = m_inv_direction;
aOutDistance = std::numeric_limits<float>::infinity();
aOutLightColor = m_color;
}
private:
SFVEC3F m_inv_direction; ///< opposite direction of the light
SFVEC3F m_color; ///< light color
};
typedef std::list<LIGHT*> LIST_LIGHT;
/**
* A container for light sources.
*
* @todo Do we really need this object? Wouldn't it be cleaner to just use std::list directly?
*/
class LIGHT_SOURCES
{
public:
LIGHT_SOURCES() {}
~LIGHT_SOURCES() { Clear(); }
/**
* Remove all lights from the container.
*/
void Clear()
{
if( !m_lights.empty() )
{
for( LIST_LIGHT::iterator ii = m_lights.begin(); ii != m_lights.end(); ++ii )
{
delete *ii;
*ii = nullptr;
}
m_lights.clear();
}
}
/**
* Add a light source to the container.
*/
void Add( LIGHT* aLight )
{
if( aLight )
m_lights.push_back( aLight );
}
/**
* Get light list of this container.
*
* @return a list of lights
*/
const LIST_LIGHT& GetList() const { return m_lights; }
private:
LIST_LIGHT m_lights; ///< list of lights
};
#endif // _LIGHT_H_