265 lines
7.9 KiB
C++
265 lines
7.9 KiB
C++
|
/****************************************************************************
|
|||
|
Copyright (c) 2011-2013,WebJet Business Division,CYOU
|
|||
|
|
|||
|
http://www.genesis-3d.com.cn
|
|||
|
|
|||
|
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 "stdneb.h"
|
|||
|
#include "ActiveLight.h"
|
|||
|
#include "foundation/math/intersection.h"
|
|||
|
#include "graphicsystem/GraphicSystem.h"
|
|||
|
#include "graphicsystem/Renderable/RenderObject.h"
|
|||
|
namespace Graphic
|
|||
|
{
|
|||
|
using namespace Math;
|
|||
|
|
|||
|
ActiveLightManager::ActiveLightManager()
|
|||
|
{
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ActiveLightManager::~ActiveLightManager()
|
|||
|
{
|
|||
|
|
|||
|
}
|
|||
|
void ActiveLightManager::_reset()
|
|||
|
{
|
|||
|
mActiveLights.Clear();
|
|||
|
mAttLightBeginIndex = 0;
|
|||
|
mTempLightBlock.Clear();
|
|||
|
mTempObj = NULL;
|
|||
|
}
|
|||
|
|
|||
|
void ActiveLightManager::CameraCull(Camera* camera)
|
|||
|
{
|
|||
|
_reset();
|
|||
|
switch(camera->GetCameraOrder())
|
|||
|
{
|
|||
|
case eCO_Main:
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
default:
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
frustum view_frustum;
|
|||
|
view_frustum.setmatrix(camera->GetViewProjTransform());
|
|||
|
|
|||
|
float4 camera_pos = camera->GetTransform().get_position();
|
|||
|
float4 view_dir = -camera->GetTransform().get_zaxis();
|
|||
|
view_dir = float4::normalize(view_dir);
|
|||
|
plane camera_plane(camera_pos, view_dir);
|
|||
|
float zfar = camera->GetCameraSetting().GetZFar();
|
|||
|
|
|||
|
RenderScene* camera_scene = camera->GetRenderScene();
|
|||
|
|
|||
|
const RenderScene::Lights& lights = camera_scene->GetLights();
|
|||
|
|
|||
|
RenderScene::Lights::Iterator it = lights.Begin();
|
|||
|
RenderScene::Lights::Iterator end = lights.End();
|
|||
|
// sort the light type, the first of them is sunlight , then the directional light
|
|||
|
// others the attenuation lights
|
|||
|
for( ; it != end; ++it )
|
|||
|
{
|
|||
|
Light* light = *it;
|
|||
|
if (!light->IsEnabled()
|
|||
|
|| light->GetLightmapType() == Light::eLM_JustForBaked ) //
|
|||
|
{
|
|||
|
continue;
|
|||
|
}
|
|||
|
Light::LightType lightType = light->GetLightType();
|
|||
|
|
|||
|
// sort the light type, the first of them is sunlight , then the directional light
|
|||
|
// others the attenuation lights
|
|||
|
if (Light::eSunLight == lightType || Light::eDirectionalLight == lightType)
|
|||
|
{
|
|||
|
ActiveLightInfo& outLight = mActiveLights.PushBack();
|
|||
|
_setActiveDirectionallight(light, outLight);
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
float4 temp = light->GetTransform().get_position();
|
|||
|
point lightPos(temp.x(), temp.y(), temp.z());
|
|||
|
float lightRange = light->GetLightRange();
|
|||
|
|
|||
|
if(Intersection::Intersect(sphere(lightPos, lightRange), view_frustum))
|
|||
|
{
|
|||
|
float viewDistance = camera_plane.distance(lightPos);
|
|||
|
|
|||
|
if (Light::ePointLight == lightType)
|
|||
|
{
|
|||
|
ActiveLightInfo& outLight = mActiveLights.PushBack();
|
|||
|
outLight.light = light;
|
|||
|
vector boxSize(lightRange, lightRange, lightRange);
|
|||
|
outLight.boundingBox = bbox(lightPos, boxSize);
|
|||
|
}
|
|||
|
else if (Light::eSpotLight == lightType)
|
|||
|
{
|
|||
|
Pyramid bounds;
|
|||
|
_buildPyramid(*light, bounds);
|
|||
|
bbox box(bounds.points[0], bounds.points[0]);
|
|||
|
|
|||
|
for (int i = 1; i < Pyramid::PointCount; i++)
|
|||
|
box.extend(bounds.points[i]);
|
|||
|
|
|||
|
if (ClipStatus::Outside != view_frustum.clipstatus(box))
|
|||
|
{
|
|||
|
ActiveLightInfo& outLight = mActiveLights.PushBack();
|
|||
|
outLight.boundingBox = box;
|
|||
|
outLight.light = light;
|
|||
|
}
|
|||
|
}
|
|||
|
else //Light::eInvailidLightType
|
|||
|
{
|
|||
|
n_warning("unknown light type: %d.", (int)lightType);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
const ActiveLightInfo* ActiveLightManager::FindSunLight() const
|
|||
|
{
|
|||
|
if (mActiveLights.Count())
|
|||
|
{
|
|||
|
if (Light::eSunLight == mActiveLights[0].light->GetLightType())
|
|||
|
{
|
|||
|
return &mActiveLights[0];
|
|||
|
}
|
|||
|
}
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
const TempLightBlock& ActiveLightManager::FindActiveAttLights(const RenderObject* obj, int max_count, bool& bUsedForLightmap) const
|
|||
|
{
|
|||
|
bUsedForLightmap = false;
|
|||
|
|
|||
|
if (mTempObj == obj)
|
|||
|
{
|
|||
|
return mTempLightBlock;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
mTempObj = obj;
|
|||
|
mTempLightBlock.Clear();
|
|||
|
}
|
|||
|
|
|||
|
bUsedForLightmap = obj->IsUseLM() && obj->IsLMHandleValid();
|
|||
|
// <20><>lightmapģʽ<C4A3><CABD>,<2C><>̬<EFBFBD>ƹ<EFBFBD>ֻ֧<D6BB><D6A7>һյ
|
|||
|
max_count = bUsedForLightmap? Math::n_min(1,max_count) :max_count;
|
|||
|
|
|||
|
int a_count = mActiveLights.Count();
|
|||
|
int index = mAttLightBeginIndex;
|
|||
|
|
|||
|
if ( index < a_count )
|
|||
|
{
|
|||
|
bbox worldBox;
|
|||
|
obj->GetBoudingBoxInWorld(worldBox);
|
|||
|
while( index < a_count && mTempLightBlock.Count() < max_count)
|
|||
|
{
|
|||
|
ActiveLightInfo& alight = mActiveLights[index];
|
|||
|
bool bRealtimeLight = (alight.light->GetLightmapType() == Light::eLM_NoBaked);
|
|||
|
|
|||
|
if ( ((bUsedForLightmap && bRealtimeLight) || (!bUsedForLightmap))
|
|||
|
&& _inLight(obj, worldBox, mActiveLights[index]))
|
|||
|
{
|
|||
|
mTempLightBlock.PushBack(&alight);
|
|||
|
}
|
|||
|
++index;
|
|||
|
}
|
|||
|
}
|
|||
|
return mTempLightBlock;
|
|||
|
}
|
|||
|
|
|||
|
void ActiveLightManager::_buildPyramid (const Light& light, Pyramid& outPyramid)
|
|||
|
{
|
|||
|
//Ĭ<>Ϲ<EFBFBD><CFB9>շ<EFBFBD><D5B7><EFBFBD>Ϊz<CEAA>Ḻ<EFBFBD><E1B8BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>distZȡ<5A><C8A1><EFBFBD><EFBFBD>
|
|||
|
float negativeZ = -light.GetLightRange();
|
|||
|
float farRadius = negativeZ * n_clamp(n_tan(n_acos(light.GetCosHalfOuterAngle())), 0.0f, 1.0f);
|
|||
|
|
|||
|
outPyramid.points[0] = light.GetTransform().get_position();
|
|||
|
outPyramid.points[1] = matrix44::transform(light.GetTransform(), float4(-farRadius,-farRadius, negativeZ, 1.0f) );
|
|||
|
outPyramid.points[2] = matrix44::transform(light.GetTransform(), float4( farRadius,-farRadius, negativeZ, 1.0f) );
|
|||
|
outPyramid.points[3] = matrix44::transform(light.GetTransform(), float4( farRadius, farRadius, negativeZ, 1.0f) );
|
|||
|
outPyramid.points[4] = matrix44::transform(light.GetTransform(), float4(-farRadius, farRadius, negativeZ, 1.0f) );
|
|||
|
}
|
|||
|
|
|||
|
bool ActiveLightManager::_inLight(const RenderObject* renderObj, const Math::bbox& worldBox, const ActiveLightInfo& actLight)
|
|||
|
{
|
|||
|
bool ret = false;
|
|||
|
const Light* light = actLight.light;
|
|||
|
|
|||
|
switch(light->GetLightType())
|
|||
|
{
|
|||
|
case Light::eSunLight:
|
|||
|
case Light::eDirectionalLight:
|
|||
|
{
|
|||
|
ret = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
case Light::ePointLight:
|
|||
|
{
|
|||
|
if(worldBox.intersects(actLight.boundingBox))//ֻ<>Ǽü<F2B5A5B2>
|
|||
|
{
|
|||
|
//<2F><>ϸ<EFBFBD>ü<EFBFBD>
|
|||
|
const bbox& localBox = renderObj->GetBoundingBox();
|
|||
|
matrix44 invMat44 = matrix44::inverse(renderObj->GetTransform());
|
|||
|
|
|||
|
sphere sph(actLight.light->GetLightPos(), actLight.light->GetLightRange());
|
|||
|
sph.transform(invMat44);
|
|||
|
ret = Intersection::Intersect(localBox, sph);
|
|||
|
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
case Light::eSpotLight:
|
|||
|
{
|
|||
|
if(worldBox.intersects(actLight.boundingBox))//ֻ<>Ǽü<F2B5A5B2>
|
|||
|
{
|
|||
|
//<2F><>ϸ<EFBFBD>ü<EFBFBD>.<2E><>ʱ<EFBFBD><CAB1>Χ<EFBFBD>вü<D0B2><C3BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ü<EFBFBD><C3BC>۹<EFBFBD><DBB9>ơ<EFBFBD><C6A1><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><D7B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϸ<EFBFBD>IJü<C4B2><C3BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD>ʻ<EFBFBD><CABB>Ե͡<D4B5><CDA1>д<EFBFBD><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
const bbox& localBox = renderObj->GetBoundingBox();
|
|||
|
matrix44 invMat44 = matrix44::inverse(renderObj->GetTransform());
|
|||
|
bbox box = actLight.boundingBox;
|
|||
|
box.transform(invMat44);
|
|||
|
|
|||
|
ret = localBox.intersects(box);
|
|||
|
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
void ActiveLightManager::_setActiveDirectionallight(Light* light, ActiveLightInfo& alight)
|
|||
|
{
|
|||
|
alight.light = light;
|
|||
|
alight.boundingBox = bbox(point::origin(), vector(std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity()));
|
|||
|
//˥<><CBA5><EFBFBD><EFBFBD>Դ<EFBFBD><D4B4><EFBFBD><EFBFBD>ʼλ<CABC>á<EFBFBD><C3A1><EFBFBD><EFBFBD><EFBFBD>Ĭ<EFBFBD><C4AC><EFBFBD>ڵƹ<DAB5><C6B9>б<EFBFBD><D0B1><EFBFBD><EFA3AC>˥<EFBFBD><CBA5><EFBFBD>Ĺ<EFBFBD>Դ<EFBFBD><D4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD><D0B1><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD>ġ<EFBFBD>
|
|||
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>ƹ<EFBFBD><C6B9><EFBFBD>Ȼ<EFBFBD><C8BB>˥<EFBFBD><CBA5><EFBFBD><EFBFBD>Դ<EFBFBD><D4B4><EFBFBD><EFBFBD>ʼ
|
|||
|
mAttLightBeginIndex = mActiveLights.Count();
|
|||
|
}
|
|||
|
}
|