summaryrefslogtreecommitdiff
path: root/Runtime/Camera/Light.h
blob: c14a59c395fe72c93d93ca62e5cd171ccfe18eec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
#ifndef LIGHT_H
#define LIGHT_H

#include "Lighting.h"
#include "Flare.h"
#include "ShadowSettings.h"
#include "Runtime/GameCode/Behaviour.h"
#include "Runtime/Math/Color.h"
#include "Runtime/Math/Vector3.h"
#include "Runtime/Geometry/AABB.h"
#include "Runtime/GfxDevice/GfxDeviceObjects.h"
#include "Runtime/GfxDevice/GfxDeviceConfigure.h"
#include "Runtime/Utilities/LinkedList.h"
#if UNITY_EDITOR
#include "Editor/Src/LightmapVisualization.h"
#endif
#include "Runtime/Math/Rect.h"

class Texture;
class GfxDevice;

class Light : public Behaviour, public ListElement
{
public:

	REGISTER_DERIVED_CLASS   (Light, Behaviour)
	DECLARE_OBJECT_SERIALIZE (Light)

	Light (MemLabelId label, ObjectCreationMode mode);
	// ~Light(); declared-by-macro

	static void InitializeClass ();
	static void CleanupClass ();
	
	// Tag class as sealed, this makes QueryComponent faster.
	static bool IsSealedClass ()				{ return true; }
	
	virtual void Reset ();

	// System interaction
	virtual void AddToManager ();
	virtual void RemoveFromManager ();
	virtual void CheckConsistency ();
	virtual void AwakeFromLoad(AwakeFromLoadMode mode);
	
	void TransformChanged ();
	

	LightType GetType() const { return static_cast<LightType>( m_Type ); }
	void SetType (LightType type);


	/// How to render this light.
	enum RenderMode
	{
		kRenderAuto,			///< Automatic
		kRenderImportant,		///< This light is important
		kRenderNotImportant,	///< This light is not very important
		kRenderModeCount // keep this last!
	};
	/// Get the render mode hint for this light
	int GetRenderMode() const { return m_RenderMode; }
	void SetRenderMode (int mode) 	{ m_RenderMode = mode; SetDirty(); m_GfxLightValid = false; }

	enum Lightmapping
	{
		kLightmappingRealtimeOnly = 0, // light is not baked, realtime only
		kLightmappingAuto = 1, // light is baked in the dual lightmap style
		kLightmappingBakedOnly = 2 // light is fully baked, not rendering in realtime at all
	};

	void SetLightmapping (int mode) { m_Lightmapping = mode; SetDirty(); m_GfxLightValid = false; }
	inline Lightmapping GetLightmappingForRender() const;
	Lightmapping GetLightmappingForBake() const;

	void SetActuallyLightmapped (bool v);
	bool GetActuallyLightmapped() const { return m_ActuallyLightmapped; }

	/// Get the full range of the light.
	float GetRange() const 			{ return m_Range; }
	void SetRange (float range) { m_Range = std::max(0.0F, range); SetDirty (); m_GfxLightValid = false; Precalc (); }

	/// Get the spot angle in degrees.
	float GetSpotAngle() const { return m_SpotAngle; }
	void SetSpotAngle (float angle) { m_SpotAngle = angle; CheckConsistency(); SetDirty (); m_GfxLightValid = false; Precalc (); }
	
	float GetCookieSize() const { return m_CookieSize; }
	void SetCookieSize (float size) { m_CookieSize = size; CheckConsistency(); SetDirty (); m_GfxLightValid = false; Precalc (); }
	
	// range * this value = end side length
	float GetCotanHalfSpotAngle () const { return m_CotanHalfSpotAngle; }
	// range * this value = diagonal side length
	float GetInvCosHalfSpotAngle () const { return m_InvCosHalfSpotAngle; }

	/// Get/set the cookie used for the light
	void SetCookie (Texture *tex);
	Texture *GetCookie () const { return m_Cookie; }
	
	/// Get/set the lens flare used
	void SetFlare (Flare *flare);
	Flare *GetFlare () { return m_Flare; }
		
	const ColorRGBAf& GetColor () const { return m_Color; }
	void SetColor (const ColorRGBAf& c);
	ColorRGBAf GetConvertedFinalColor() const { return m_ConvertedFinalColor; }
	
	float GetIntensity() const { return m_Intensity; }
	void SetIntensity( float i );

	float GetShadowStrength() const { return m_Shadows.m_Strength; }
	void SetShadowStrength( float f ) { m_Shadows.m_Strength = f; SetDirty(); }
	ShadowType GetShadows() const { return static_cast<ShadowType>(m_Shadows.m_Type); }
	void SetShadows( int v );
	int GetShadowResolution() const { return m_Shadows.m_Resolution; }
	void SetShadowResolution( int v ) { m_Shadows.m_Resolution = v; SetDirty(); }
	float GetShadowBias() const { return m_Shadows.m_Bias; }
	void SetShadowBias( float v ) { m_Shadows.m_Bias = v; SetDirty(); }
	float GetShadowSoftness() const { return m_Shadows.m_Softness; }
	void SetShadowSoftness (float v) { m_Shadows.m_Softness = v; SetDirty(); }
	float GetShadowSoftnessFade() const { return m_Shadows.m_SoftnessFade; }
	void SetShadowSoftnessFade (float v) { m_Shadows.m_SoftnessFade = v; SetDirty(); }
	
	int GetFinalShadowResolution() const;

	#if UNITY_EDITOR
	int GetShadowSamples() const { return m_ShadowSamples; }
	void SetShadowSamples (int samples) { m_ShadowSamples = samples; }
	float GetShadowRadius() const { return m_ShadowRadius; }
	void SetShadowRadius (float radius) { m_ShadowRadius = radius; }
	float GetShadowAngle() const { return m_ShadowAngle; }
	void SetShadowAngle (float angle) { m_ShadowAngle = angle; }
	float GetIndirectIntensity() const { return m_IndirectIntensity; }
	void SetIndirectIntensity (float intensity) { m_IndirectIntensity = intensity; }
	Vector2f GetAreaSize() const { return m_AreaSize; }
	void SetAreaSize(const Vector2f& areaSize) { m_AreaSize = areaSize; }
	#endif

	/// Calculate the quadratic attenuation factor for a light with a specified range
	/// @param range the range of the light
	/// @return the quadratic attenuation factor
	static float CalcQuadFac (float range);

	// Attenuation function: inverse quadratic. distSqr is over 0..1 range
	static float AttenuateNormalized(float distSqr);

	// Get the result of attenuation for a squared distance from the light
	float AttenuateApprox (float sqrDist) const;

	// Set up this light as GfxDevice fixed function per-vertex light.
	// IMPORTANT: Assumes the modelview matrix has been set up to be the world2camera matrix.
	void SetupVertexLight (int lightNo, float visibilityFade);

	void SetLightKeyword();
	void SetPropsToShaderLab (float blend) const;
	

	// Set up the halo for the light.
	void SetupHalo ();
	// Set up the flare for the light.
	void SetupFlare ();
	
	void SetCullingMask (int mask) { m_CullingMask.m_Bits = mask; SetDirty(); }
	int GetCullingMask () const { return m_CullingMask.m_Bits; }

	// Precalc all non-changing shaderlab values.
	void Precalc ();

	const Vector3f& GetWorldPosition() const { return m_WorldPosition; }
	const Matrix4x4f& GetWorldToLocalMatrix() const { return m_World2Local; }

	enum AttenuationMode
	{
		kSpotCookie,		// 2D cookie projected in spot light's cone
		kPointFalloff,		// Attenuation for a point light
		kDirectionalCookie,	// Cookie projected from a directional light
		kUnused				// The attenuation texture is not used
	};
	void GetMatrix (const Matrix4x4f* __restrict object2light, Matrix4x4f* __restrict outMatrix) const;

	bool IsValidToRender() const;

private:
	void UpdateSpotAngleValues ()
	{
		float halfSpotRad = Deg2Rad(m_SpotAngle * 0.5f);
		float cs = cosf(halfSpotRad);
		float ss = sinf(halfSpotRad);
		m_CotanHalfSpotAngle = cs / ss;
		m_InvCosHalfSpotAngle = 1.0f / cs;
	}

	void ComputeGfxLight (GfxVertexLight& gfxLight) const;

private:
	Matrix4x4f		m_World2Local;
	Vector3f		m_WorldPosition;
	ShadowSettings	m_Shadows;			///< Shadow settings.
	
	ColorRGBAf m_Color;
	ColorRGBAf m_ConvertedFinalColor;
	
	PPtr<Flare> m_Flare;				///< Does the light have a flare?
	PPtr<Texture> m_Cookie;				///< Custom cookie (optional). 
	BitField  m_CullingMask;            ///< The mask used for selectively lighting objects in the scene.
	float	m_Intensity;				///< Light intensity range {0.0, 8.0}
	float	m_Range; 					///< Light range
	float	m_SpotAngle;				///< Angle of the spotlight cone.
	float	m_CookieSize;				///< Cookie size for directional lights.
	float	m_CotanHalfSpotAngle; // cotangent of half of the spot angle
	float	m_InvCosHalfSpotAngle; // 1/cos of half of the spot angle
	int		m_RenderMode;				///< enum { Auto, Important, Not Important } Rendering mode for the light.
	int		m_Lightmapping;				///< enum { RealtimeOnly, Auto, BakedOnly } Is light baked into lightmaps?
	int		m_Type;						///< enum { Spot, Directional, Point, Area (baked only) } Light type
	bool    m_DrawHalo;					///< Does the light have a halo?
	bool	m_ActuallyLightmapped; // Is it actually lightmapped already?
	#if UNITY_EDITOR
	int		m_ShadowSamples;			// number of samples for lightmapper shadow calculations
	float	m_ShadowRadius;				// radius of the light source for lightmapper shadow calculations (point and spot lights)
	float	m_ShadowAngle;				// angle of the cone for lightmapper shadow rays (directional lights)
	float	m_IndirectIntensity;		// aka bounce intensity - a multiplier for the indirect light
	Vector2f m_AreaSize;				// size of area light's rectangle
	#endif
	
	PPtr<Texture>	m_AttenuationTexture;
	AttenuationMode m_AttenuationMode;
	LightKeywordMode	m_KeywordMode; // The current keyword used by the light
		
	int m_HaloHandle, m_FlareHandle;
	
	GfxVertexLight m_CachedGfxLight;
	bool	m_GfxLightValid;
};

void SetupVertexLights(const std::vector<Light*>& lights);
void SetLightScissorRect (const Rectf& lightRect, const Rectf& viewPort, bool intoRT, GfxDevice& device);
void ClearScissorRect (bool oldScissor, const int oldRect[4], GfxDevice& device);


// Inline this; called a lot in light culling.
inline Light::Lightmapping Light::GetLightmappingForRender() const 
{
	if (m_Type == kLightArea)
		return kLightmappingBakedOnly;

	// all lights behave as realtime only if no lightmaps have been baked yet or if lightmaps are disabled
	return m_ActuallyLightmapped
		#if UNITY_EDITOR
		&& GetLightmapVisualization().GetUseLightmapsForRendering()
		#endif
		? static_cast<Lightmapping>(m_Lightmapping) : kLightmappingRealtimeOnly; 
}


#endif