mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-20 12:44:46 +00:00
Also disables the Paraboloid shadowmap type, as it is non-functional. Disabled light animations by default so as to not waste processing time if not needed Sets point lights' shadow types to be cubemap by default, and lowers the overdark factor to make them look cleaner and not exacerbate aliasing.
229 lines
7.3 KiB
C++
229 lines
7.3 KiB
C++
//-----------------------------------------------------------------------------
|
|
// Copyright (c) 2012 GarageGames, LLC
|
|
//
|
|
// 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 "platform/platform.h"
|
|
#include "T3D/spotLight.h"
|
|
|
|
#include "console/consoleTypes.h"
|
|
#include "core/stream/bitStream.h"
|
|
#include "gfx/gfxDrawUtil.h"
|
|
|
|
|
|
IMPLEMENT_CO_NETOBJECT_V1( SpotLight );
|
|
|
|
ConsoleDocClass( SpotLight,
|
|
"@brief Lighting object which emits conical light in a direction.\n\n"
|
|
|
|
"SpotLight is one of the two types of lighting objects that can be added "
|
|
"to a Torque 3D level, the other being PointLight. Unlike directional or "
|
|
"point lights, the SpotLights emits lighting in a specific direction "
|
|
"within a cone. The distance of the cone is controlled by the SpotLight::range "
|
|
"variable.\n\n"
|
|
|
|
"@tsexample\n"
|
|
"// Declaration of a point light in script, or created by World Editor\n"
|
|
"new SpotLight(SampleSpotLight)\n"
|
|
"{\n"
|
|
" range = \"10\";\n"
|
|
" innerAngle = \"40\";\n"
|
|
" outerAngle = \"45\";\n"
|
|
" isEnabled = \"1\";\n"
|
|
" color = \"1 1 1 1\";\n"
|
|
" brightness = \"1\";\n"
|
|
" castShadows = \"0\";\n"
|
|
" priority = \"1\";\n"
|
|
" animate = \"1\";\n"
|
|
" animationPeriod = \"1\";\n"
|
|
" animationPhase = \"1\";\n"
|
|
" flareType = \"LightFlareExample0\";\n"
|
|
" flareScale = \"1\";\n"
|
|
" attenuationRatio = \"0 1 1\";\n"
|
|
" shadowType = \"Spot\";\n"
|
|
" texSize = \"512\";\n"
|
|
" overDarkFactor = \"2000 1000 500 100\";\n"
|
|
" shadowDistance = \"400\";\n"
|
|
" shadowSoftness = \"0.15\";\n"
|
|
" numSplits = \"1\";\n"
|
|
" logWeight = \"0.91\";\n"
|
|
" fadeStartDistance = \"0\";\n"
|
|
" lastSplitTerrainOnly = \"0\";\n"
|
|
" representedInLightmap = \"0\";\n"
|
|
" shadowDarkenColor = \"0 0 0 -1\";\n"
|
|
" includeLightmappedGeometryInShadow = \"0\";\n"
|
|
" position = \"-29.4362 -5.86289 5.58602\";\n"
|
|
" rotation = \"1 0 0 0\";\n"
|
|
"};\n"
|
|
"@endtsexample\n\n"
|
|
|
|
"@see LightBase\n\n"
|
|
"@see PointLight\n\n"
|
|
"@ingroup Lighting\n"
|
|
);
|
|
|
|
SpotLight::SpotLight()
|
|
: mRange( 10.0f ),
|
|
mInnerConeAngle( 40.0f ),
|
|
mOuterConeAngle( 45.0f )
|
|
{
|
|
// We set the type here to ensure the extended
|
|
// parameter validation works when setting fields.
|
|
mLight->setType( LightInfo::Spot );
|
|
}
|
|
|
|
SpotLight::~SpotLight()
|
|
{
|
|
}
|
|
|
|
void SpotLight::initPersistFields()
|
|
{
|
|
addGroup( "Light" );
|
|
|
|
addField( "range", TypeF32, Offset( mRange, SpotLight ) );
|
|
addField( "innerAngle", TypeF32, Offset( mInnerConeAngle, SpotLight ) );
|
|
addField( "outerAngle", TypeF32, Offset( mOuterConeAngle, SpotLight ) );
|
|
|
|
endGroup( "Light" );
|
|
|
|
// We do the parent fields at the end so that
|
|
// they show up that way in the inspector.
|
|
Parent::initPersistFields();
|
|
|
|
// Remove the scale field... it's already
|
|
// defined by the range and angle.
|
|
removeField( "scale" );
|
|
|
|
//These are particular fields for PSSM, so useless for point lights
|
|
removeField("numSplits");
|
|
removeField("logWeight");
|
|
removeField("lastSplitTerrainOnly");
|
|
}
|
|
|
|
void SpotLight::_conformLights()
|
|
{
|
|
mLight->setTransform( getTransform() );
|
|
|
|
mRange = getMax( mRange, 0.05f );
|
|
mLight->setRange( mRange );
|
|
|
|
mLight->setColor( mColor );
|
|
mLight->setBrightness( mBrightness );
|
|
mLight->setCastShadows( mCastShadows );
|
|
mLight->setStaticRefreshFreq(mStaticRefreshFreq);
|
|
mLight->setDynamicRefreshFreq(mDynamicRefreshFreq);
|
|
mLight->setPriority( mPriority );
|
|
|
|
mOuterConeAngle = getMax( 0.01f, mOuterConeAngle );
|
|
mInnerConeAngle = getMin( mInnerConeAngle, mOuterConeAngle );
|
|
|
|
mLight->setInnerConeAngle( mInnerConeAngle );
|
|
mLight->setOuterConeAngle( mOuterConeAngle );
|
|
|
|
// Update the bounds and scale to fit our spotlight.
|
|
F32 radius = mRange * mSin( mDegToRad( mOuterConeAngle ) * 0.5f );
|
|
Point3F objectScale(radius, mRange, radius);
|
|
Point3F objectBoxMin(-1, 0, -1);
|
|
|
|
if (mAnimationData && mAnimationData->mRot.keyLen[0] > 0)
|
|
{
|
|
objectBoxMin.set(-1, -1, -1);
|
|
objectScale.set(mRange, mRange, mRange);
|
|
}
|
|
|
|
mObjBox.minExtents.set(objectBoxMin);
|
|
mObjBox.maxExtents.set(1, 1, 1);
|
|
mObjScale.set(objectScale);
|
|
|
|
// Skip our transform... it just dirties mask bits.
|
|
Parent::setTransform( mObjToWorld );
|
|
}
|
|
|
|
U32 SpotLight::packUpdate(NetConnection *conn, U32 mask, BitStream *stream )
|
|
{
|
|
if ( stream->writeFlag( mask & UpdateMask ) )
|
|
{
|
|
stream->write( mRange );
|
|
stream->write( mInnerConeAngle );
|
|
stream->write( mOuterConeAngle );
|
|
}
|
|
|
|
return Parent::packUpdate( conn, mask, stream );
|
|
}
|
|
|
|
void SpotLight::unpackUpdate( NetConnection *conn, BitStream *stream )
|
|
{
|
|
if ( stream->readFlag() ) // UpdateMask
|
|
{
|
|
stream->read( &mRange );
|
|
stream->read( &mInnerConeAngle );
|
|
stream->read( &mOuterConeAngle );
|
|
}
|
|
|
|
Parent::unpackUpdate( conn, stream );
|
|
}
|
|
|
|
void SpotLight::setScale( const VectorF &scale )
|
|
{
|
|
// The y coord is the spotlight range.
|
|
mRange = getMax( scale.y, 0.05f );
|
|
|
|
// Use the average of the x and z to get a radius. This
|
|
// is the best method i've found to make the manipulation
|
|
// from the WorldEditor gizmo to feel right.
|
|
F32 radius = mClampF( ( scale.x + scale.z ) * 0.5f, 0.05f, mRange );
|
|
mOuterConeAngle = mRadToDeg( mAsin( radius / mRange ) ) * 2.0f;
|
|
|
|
// Make sure the inner angle is less than the outer.
|
|
//
|
|
// TODO: Maybe we should make the inner angle a scale
|
|
// and not an absolute angle?
|
|
//
|
|
mInnerConeAngle = getMin( mInnerConeAngle, mOuterConeAngle );
|
|
|
|
// We changed a bunch of our settings
|
|
// so notify the client.
|
|
setMaskBits( UpdateMask );
|
|
|
|
// Let the parent do the final scale.
|
|
Parent::setScale( VectorF( radius, mRange, radius ) );
|
|
}
|
|
|
|
void SpotLight::_renderViz( SceneRenderState *state )
|
|
{
|
|
GFXDrawUtil *draw = GFX->getDrawUtil();
|
|
|
|
GFXStateBlockDesc desc;
|
|
desc.setZReadWrite( true, false );
|
|
desc.setCullMode( GFXCullNone );
|
|
desc.setBlend( true );
|
|
|
|
// Base the color on the light color.
|
|
ColorI color = mColor.toColorI();
|
|
color.alpha = 16;
|
|
|
|
F32 radius = mRange * mSin( mDegToRad( mOuterConeAngle * 0.5f ) );
|
|
draw->drawCone( desc,
|
|
getPosition() + ( getTransform().getForwardVector() * mRange ),
|
|
getPosition(),
|
|
radius,
|
|
color );
|
|
}
|