| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801 |
- //
- // Urho3D Engine
- // Copyright (c) 2008-2011 Lasse Öörni
- //
- // 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 "Precompiled.h"
- #include "DebugRenderer.h"
- #include "Light.h"
- #include "ReplicationUtils.h"
- #include "ResourceCache.h"
- #include "StringUtils.h"
- #include "Texture2D.h"
- #include "TextureCube.h"
- #include "XMLElement.h"
- #include "DebugNew.h"
- static LightType DEFAULT_LIGHTTYPE = LIGHT_POINT;
- static const Vector3 DEFAULT_DIRECTION = Vector3::sDown;
- static const float DEFAULT_FOV = 30.0f;
- static const float DEFAULT_CONSTANTBIAS = 0.0001f;
- static const float DEFAULT_SLOPESCALEDBIAS = 0.0001f;
- static const float DEFAULT_LAMBDA = 0.5f;
- static const float DEFAULT_SHADOWFADERANGE = 0.2f;
- static const float DEFAULT_SHADOWQUANTIZE = 0.5f;
- static const float DEFAULT_SHADOWMINVIEW = 3.0f;
- static const float DEFAULT_SHADOWNEARFARRATIO = 0.002f;
- static const std::string typeNames[] =
- {
- "directional",
- "point",
- "spot",
- "splitpoint"
- };
- void BiasParameters::validate()
- {
- mConstantBias = clamp(mConstantBias, 0.0f, 1.0f);
- mSlopeScaledBias = clamp(mSlopeScaledBias, 0.0f, 1.0f);
- }
- void CascadeParameters::validate()
- {
- mSplits = max(mSplits, 1);
- mLambda = clamp(mLambda, 0.0f, 1.0f);
- mSplitFadeRange = clamp(mSplitFadeRange, M_EPSILON, 0.5f);
- mShadowRange = max(mShadowRange, M_EPSILON);
- }
- void FocusParameters::validate()
- {
- mQuantize = max(mQuantize, SHADOW_MIN_QUANTIZE);
- mMinView = max(mMinView, SHADOW_MIN_VIEW);
- }
- Light::Light(Octant* octant, const std::string& name) :
- VolumeNode(NODE_LIGHT, octant, name),
- mLightType(DEFAULT_LIGHTTYPE),
- mDirection(DEFAULT_DIRECTION),
- mSpecularIntensity(0.0f),
- mRange(0.0f),
- mFov(DEFAULT_FOV),
- mAspectRatio(1.0f),
- mFadeDistance(0.0f),
- mDetailLevel(0),
- mShadowDetailLevel(0),
- mShadowBias(BiasParameters(DEFAULT_CONSTANTBIAS, DEFAULT_SLOPESCALEDBIAS)),
- mShadowCascade(CascadeParameters(1, DEFAULT_LAMBDA, DEFAULT_SHADOWFADERANGE, M_LARGE_VALUE)),
- mShadowFocus(FocusParameters(true, true, true, DEFAULT_SHADOWQUANTIZE, DEFAULT_SHADOWMINVIEW)),
- mShadowFadeDistance(0.0f),
- mShadowIntensity(0.0f),
- mShadowResolution(1.0f),
- mShadowNearFarRatio(DEFAULT_SHADOWNEARFARRATIO),
- mNearSplit(0.0f),
- mFarSplit(M_LARGE_VALUE),
- mNearFadeRange(M_EPSILON),
- mFarFadeRange(M_EPSILON),
- mFrustumDirty(true),
- mShadowMap(0)
- {
- }
- Light::~Light()
- {
- }
- void Light::save(Serializer& dest)
- {
- // Write VolumeNode properties
- VolumeNode::save(dest);
-
- // Write Light properties
- dest.writeUByte((unsigned char)mLightType);
- dest.writeVector3(mDirection);
- dest.writeColor(mColor);
- dest.writeFloat(mSpecularIntensity);
- dest.writeFloat(mRange);
- dest.writeFloat(mFov);
- dest.writeFloat(mAspectRatio);
- dest.writeFloat(mFadeDistance);
- dest.writeUByte(mDetailLevel);
- dest.writeUByte(mShadowDetailLevel);
- dest.writeFloat(mShadowBias.mConstantBias);
- dest.writeFloat(mShadowBias.mSlopeScaledBias);
- dest.writeFloat(mShadowCascade.mLambda);
- dest.writeFloat(mShadowCascade.mShadowRange);
- dest.writeFloat(mShadowCascade.mSplitFadeRange);
- dest.writeVLE(mShadowCascade.mSplits);
- dest.writeBool(mShadowFocus.mFocus);
- dest.writeBool(mShadowFocus.mNonUniform);
- dest.writeBool(mShadowFocus.mZoomOut);
- dest.writeFloat(mShadowFocus.mQuantize);
- dest.writeFloat(mShadowFocus.mMinView);
- dest.writeFloat(mShadowFadeDistance);
- dest.writeFloat(mShadowIntensity);
- dest.writeFloat(mShadowResolution);
- dest.writeFloat(mShadowNearFarRatio);
-
- dest.writeStringHash(getResourceHash(mRampTexture));
- if (mRampTexture)
- dest.writeBool(mRampTexture->getType() == TextureCube::getTypeStatic());
- dest.writeStringHash(getResourceHash(mSpotTexture));
- if (mSpotTexture)
- dest.writeBool(mSpotTexture->getType() == TextureCube::getTypeStatic());
- }
- void Light::load(Deserializer& source, ResourceCache* cache)
- {
- // Read VolumeNode properties
- VolumeNode::load(source, cache);
-
- // Read Light properties
- mLightType = (LightType)source.readUByte();
- mDirection = source.readVector3();
- mColor = source.readColor();
- mSpecularIntensity = source.readFloat();
- mRange = source.readFloat();
- mFov = source.readFloat();
- mAspectRatio = source.readFloat();
- mFadeDistance = source.readFloat();
- mDetailLevel = source.readUByte();
- mShadowDetailLevel = source.readUByte();
- mShadowBias.mConstantBias = source.readFloat();
- mShadowBias.mSlopeScaledBias = source.readFloat();
- mShadowCascade.mLambda = source.readFloat();
- mShadowCascade.mShadowRange = source.readFloat();
- mShadowCascade.mSplitFadeRange = source.readFloat();
- mShadowCascade.mSplits = source.readVLE();
- mShadowFocus.mFocus = source.readBool();
- mShadowFocus.mNonUniform = source.readBool();
- mShadowFocus.mZoomOut = source.readBool();
- mShadowFocus.mQuantize = source.readFloat();
- mShadowFocus.mMinView = source.readFloat();
- mShadowFadeDistance = source.readFloat();
- mShadowIntensity = source.readFloat();
- mShadowResolution = source.readFloat();
- mShadowNearFarRatio = source.readFloat();
-
- StringHash rampTexture = source.readStringHash();
- if (rampTexture)
- {
- if (!source.readBool())
- mRampTexture = cache->getResource<Texture2D>(rampTexture);
- else
- mRampTexture = cache->getResource<TextureCube>(rampTexture);
- }
- StringHash spotTexture = source.readStringHash();
- if (spotTexture)
- {
- if (!source.readBool())
- mSpotTexture = cache->getResource<Texture2D>(spotTexture);
- else
- mSpotTexture = cache->getResource<TextureCube>(spotTexture);
- }
-
- mShadowBias.validate();
- mShadowCascade.validate();
- mShadowFocus.validate();
- }
- void Light::saveXML(XMLElement& dest)
- {
- // Write VolumeNode properties
- VolumeNode::saveXML(dest);
-
- // Write Light properties
- XMLElement lightElem = dest.createChildElement("light");
- lightElem.setString("type", typeNames[mLightType]);
- lightElem.setVector3("direction", mDirection);
- lightElem.setColor("color", mColor);
- lightElem.setFloat("specular", mSpecularIntensity);
- lightElem.setFloat("range", mRange);
- lightElem.setFloat("fov", mFov);
- lightElem.setFloat("aspectratio", mAspectRatio);
-
- XMLElement lodElem = dest.getChildElement("lod");
- lodElem.setFloat("fadedistance", mFadeDistance);
- lodElem.setInt("detail", mDetailLevel);
- lodElem.setInt("shadowdetail", mShadowDetailLevel);
-
- XMLElement shadowElem = dest.createChildElement("shadows");
- shadowElem.setFloat("fadedistance", mShadowFadeDistance);
- shadowElem.setFloat("intensity", mShadowIntensity);
- shadowElem.setFloat("resolution", mShadowResolution);
- shadowElem.setFloat("nearfarratio", mShadowNearFarRatio);
-
- XMLElement biasElem = dest.createChildElement("shadowbias");
- biasElem.setFloat("constant", mShadowBias.mConstantBias);
- biasElem.setFloat("slopescaled", mShadowBias.mSlopeScaledBias);
-
- XMLElement cascadeElem = dest.createChildElement("shadowcascade");
- cascadeElem.setFloat("lambda", mShadowCascade.mLambda);
- cascadeElem.setFloat("maxrange", mShadowCascade.mShadowRange);
- cascadeElem.setFloat("faderange", mShadowCascade.mSplitFadeRange);
- cascadeElem.setInt("splits", mShadowCascade.mSplits);
-
- XMLElement focusElem = dest.createChildElement("shadowfocus");
- focusElem.setBool("enable", mShadowFocus.mFocus);
- focusElem.setBool("nonuniform", mShadowFocus.mNonUniform);
- focusElem.setBool("zoomout", mShadowFocus.mZoomOut);
- focusElem.setFloat("quantize", mShadowFocus.mQuantize);
- focusElem.setFloat("minview", mShadowFocus.mMinView);
-
- XMLElement rampElem = dest.createChildElement("ramptexture");
- rampElem.setString("name", getResourceName(mRampTexture));
-
- XMLElement spotElem = dest.createChildElement("spottexture");
- spotElem.setString("name", getResourceName(mSpotTexture));
- }
- void Light::loadXML(const XMLElement& source, ResourceCache* cache)
- {
- // Read VolumeNode properties
- VolumeNode::loadXML(source, cache);
-
- // Read Light properties
- XMLElement lightElem = source.getChildElement("light");
- mLightType = (LightType)getIndexFromStringList(lightElem.getStringLower("type"), typeNames, 3, 0);
- mDirection = lightElem.getVector3("direction");
- mColor = lightElem.getColor("color");
- mSpecularIntensity = lightElem.getFloat("specular");
- mRange = lightElem.getFloat("range");
- mFov = lightElem.getFloat("fov");
- mAspectRatio = lightElem.getFloat("aspectratio");
-
- XMLElement lodElem = source.getChildElement("lod");
- mFadeDistance = lodElem.getFloat("fadedistance");
- mDetailLevel = lodElem.getInt("detail");
- mShadowDetailLevel = lodElem.getInt("shadowdetail");
-
- XMLElement shadowElem = source.getChildElement("shadows");
- mShadowFadeDistance = shadowElem.getFloat("fadedistance");
- mShadowIntensity = shadowElem.getFloat("intensity");
- mShadowResolution = shadowElem.getFloat("resolution");
- mShadowNearFarRatio = shadowElem.getFloat("nearfarratio");
-
- XMLElement biasElem = source.getChildElement("shadowbias");
- mShadowBias.mConstantBias = biasElem.getFloat("constant");
- mShadowBias.mSlopeScaledBias = biasElem.getFloat("slopescaled");
-
- XMLElement cascadeElem = source.getChildElement("shadowcascade");
- mShadowCascade.mLambda = cascadeElem.getFloat("lambda");
- mShadowCascade.mShadowRange = cascadeElem.getFloat("maxrange");
- mShadowCascade.mSplitFadeRange = cascadeElem.getFloat("faderange");
- mShadowCascade.mSplits = cascadeElem.getInt("splits");
-
- XMLElement focusElem = source.getChildElement("shadowfocus");
- mShadowFocus.mFocus = focusElem.getBool("enable");
- mShadowFocus.mNonUniform = focusElem.getBool("nonuniform");
- mShadowFocus.mZoomOut = focusElem.getBool("zoomout");
- mShadowFocus.mQuantize = focusElem.getFloat("quantize");
- mShadowFocus.mMinView = focusElem.getFloat("minview");
-
- XMLElement rampElem = source.getChildElement("ramptexture");
- std::string name = rampElem.getString("name");
- if (getExtension(name) == ".xml")
- mRampTexture = cache->getResource<TextureCube>(name);
- else
- mRampTexture = cache->getResource<Texture2D>(name);
-
- XMLElement spotElem = source.getChildElement("spottexture");
- name = spotElem.getString("name");
- if (getExtension(name) == ".xml")
- mSpotTexture = cache->getResource<TextureCube>(name);
- else
- mSpotTexture = cache->getResource<Texture2D>(name);
-
- mShadowBias.validate();
- mShadowCascade.validate();
- mShadowFocus.validate();
- }
- bool Light::writeNetUpdate(Serializer& dest, Serializer& destRevision, Deserializer& baseRevision, const NetUpdateInfo& info)
- {
- // Write VolumeNode properties and see if there were any changes
- bool prevBits = VolumeNode::writeNetUpdate(dest, destRevision, baseRevision, info);
-
- // Build bitmask of changed properties
- unsigned char bits = 0;
- unsigned char bits2 = 0;
- unsigned char detailLevels = mDetailLevel | (mShadowDetailLevel << 4);
- checkUByte((unsigned char)mLightType, DEFAULT_LIGHTTYPE, baseRevision, bits, 1);
- checkUByte(detailLevels, 0, baseRevision, bits, 1);
- checkVector3(mDirection, DEFAULT_DIRECTION, baseRevision, bits, 2);
- checkColor(mColor, Color(), baseRevision, bits, 4);
- checkFloat(mSpecularIntensity, 0.0f, baseRevision, bits, 4);
- checkFloat(mRange, 0.0f, baseRevision, bits, 8);
- checkFloat(mFov, DEFAULT_FOV, baseRevision, bits, 16);
- checkFloat(mAspectRatio, 1.0f, baseRevision, bits, 16);
- checkFloat(mFadeDistance, 0.0f, baseRevision, bits, 32);
- checkStringHash(getResourceHash(mRampTexture), StringHash(), baseRevision, bits, 64);
- checkStringHash(getResourceHash(mSpotTexture), StringHash(), baseRevision, bits, 128);
- checkFloat(mShadowBias.mConstantBias, DEFAULT_CONSTANTBIAS, baseRevision, bits2, 1);
- checkFloat(mShadowBias.mSlopeScaledBias, DEFAULT_SLOPESCALEDBIAS, baseRevision, bits2, 1);
- checkFloat(mShadowCascade.mLambda, DEFAULT_LAMBDA, baseRevision, bits2, 2);
- checkFloat(mShadowCascade.mShadowRange, M_LARGE_VALUE, baseRevision, bits2, 2);
- checkFloat(mShadowCascade.mSplitFadeRange, DEFAULT_SHADOWFADERANGE, baseRevision, bits2, 2);
- checkVLE(mShadowCascade.mSplits, 1, baseRevision, bits2, 2);
- checkBool(mShadowFocus.mFocus, true, baseRevision, bits2, 4);
- checkBool(mShadowFocus.mNonUniform, true, baseRevision, bits2, 4);
- checkBool(mShadowFocus.mZoomOut, true, baseRevision, bits2, 4);
- checkFloat(mShadowFocus.mQuantize, DEFAULT_SHADOWQUANTIZE, baseRevision, bits2, 4);
- checkFloat(mShadowFocus.mMinView, DEFAULT_SHADOWMINVIEW, baseRevision, bits2, 4);
- checkFloat(mShadowFadeDistance, 0.0f, baseRevision, bits2, 8);
- checkUByte((unsigned char)(mShadowIntensity * 255), 0, baseRevision, bits2, 16);
- checkUByte((unsigned char)(mShadowResolution * 100), 100, baseRevision, bits2, 32);
- checkFloat(mShadowNearFarRatio, DEFAULT_SHADOWNEARFARRATIO, baseRevision, bits2, 64);
-
- // Send only information necessary for the light type, and shadow data only for shadowed lights
- if (mLightType == LIGHT_POINT)
- bits &= ~2;
- if (mLightType == LIGHT_DIRECTIONAL)
- bits &= ~(8 | 32);
- if (mLightType != LIGHT_SPOT)
- bits &= ~16;
- if (!mCastShadows)
- bits2 = 0;
-
- dest.writeUByte(bits);
- dest.writeUByte(bits2);
- writeUByteDelta((unsigned char)mLightType, dest, destRevision, bits & 1);
- writeUByteDelta(detailLevels, dest, destRevision, bits & 1);
- writeVector3Delta(mDirection, dest, destRevision, bits & 2);
- writeColorDelta(mColor, dest, destRevision, bits & 4);
- writeFloatDelta(mSpecularIntensity, dest, destRevision, bits & 4);
- writeFloatDelta(mRange, dest, destRevision, bits & 8);
- writeFloatDelta(mFov, dest, destRevision, bits & 16);
- writeFloatDelta(mAspectRatio, dest, destRevision, bits & 16);
- writeFloatDelta(mFadeDistance, dest, destRevision, bits & 32);
- writeStringHashDelta(getResourceHash(mRampTexture), dest, destRevision, bits & 64);
- if ((bits & 64) && (mRampTexture))
- dest.writeBool(mRampTexture->getType() == TextureCube::getTypeStatic());
- writeStringHashDelta(getResourceHash(mSpotTexture), dest, destRevision, bits & 128);
- if ((bits & 128) && (mSpotTexture))
- dest.writeBool(mSpotTexture->getType() == TextureCube::getTypeStatic());
- writeFloatDelta(mShadowBias.mConstantBias, dest, destRevision, bits2 & 1);
- writeFloatDelta(mShadowBias.mSlopeScaledBias, dest, destRevision, bits2 & 1);
- writeFloatDelta(mShadowCascade.mLambda, dest, destRevision, bits2 & 2);
- writeFloatDelta(mShadowCascade.mShadowRange, dest, destRevision, bits2 & 2);
- writeFloatDelta(mShadowCascade.mSplitFadeRange, dest, destRevision, bits2 & 2);
- writeVLEDelta(mShadowCascade.mSplits, dest, destRevision, bits2 & 2);
- writeBoolDelta(mShadowFocus.mFocus, dest, destRevision, bits2 & 4);
- writeBoolDelta(mShadowFocus.mNonUniform, dest, destRevision, bits2 & 4);
- writeBoolDelta(mShadowFocus.mZoomOut, dest, destRevision, bits2 & 4);
- writeFloatDelta(mShadowFocus.mQuantize, dest, destRevision, bits2 & 4);
- writeFloatDelta(mShadowFocus.mMinView, dest, destRevision, bits2 & 4);
- writeFloatDelta(mShadowFadeDistance, dest, destRevision, bits2 & 8);
- writeUByteDelta((unsigned char)(mShadowIntensity * 255), dest, destRevision, bits2 & 16);
- writeUByteDelta((unsigned char)(mShadowResolution * 100), dest, destRevision, bits2 & 32);
- writeFloatDelta(mShadowNearFarRatio, dest, destRevision, bits2 & 64);
-
- return prevBits || (bits != 0) || (bits2 != 0);
- }
- void Light::readNetUpdate(Deserializer& source, ResourceCache* cache, const NetUpdateInfo& info)
- {
- // Read VolumeNode properties
- VolumeNode::readNetUpdate(source, cache, info);
-
- unsigned char bits = source.readUByte();
- unsigned char bits2 = source.readUByte();
- if (bits & 1)
- {
- mLightType = (LightType)source.readUByte();
- unsigned char detailLevels = source.readUByte();
- mDetailLevel = detailLevels & 15;
- mShadowDetailLevel = detailLevels >> 4;
- }
- readVector3Delta(mDirection, source, bits & 2);
- readColorDelta(mColor, source, bits & 4);
- readFloatDelta(mSpecularIntensity, source, bits & 4);
- readFloatDelta(mRange, source, bits & 8);
- readFloatDelta(mFov, source, bits & 16);
- readFloatDelta(mAspectRatio, source, bits & 16);
- readFloatDelta(mFadeDistance, source, bits & 32);
- if (bits & 64)
- {
- StringHash rampTexture = source.readStringHash();
- if (rampTexture)
- {
- if (!source.readBool())
- mRampTexture = cache->getResource<Texture2D>(rampTexture);
- else
- mRampTexture = cache->getResource<TextureCube>(rampTexture);
- }
- }
- if (bits & 128)
- {
- StringHash spotTexture = source.readStringHash();
- if (spotTexture)
- {
- if (!source.readBool())
- mSpotTexture = cache->getResource<Texture2D>(spotTexture);
- else
- mSpotTexture = cache->getResource<TextureCube>(spotTexture);
- }
- }
- readFloatDelta(mShadowBias.mConstantBias, source, bits2 & 1);
- readFloatDelta(mShadowBias.mSlopeScaledBias, source, bits2 & 1);
- readFloatDelta(mShadowCascade.mLambda, source, bits2 & 2);
- readFloatDelta(mShadowCascade.mShadowRange, source, bits2 & 2);
- readFloatDelta(mShadowCascade.mSplitFadeRange, source, bits2 & 2);
- readVLEDelta(mShadowCascade.mSplits, source, bits2 & 2);
- readBoolDelta(mShadowFocus.mFocus, source, bits2 & 4);
- readBoolDelta(mShadowFocus.mNonUniform, source, bits2 & 4);
- readBoolDelta(mShadowFocus.mZoomOut, source, bits2 & 4);
- readFloatDelta(mShadowFocus.mQuantize, source, bits2 & 4);
- readFloatDelta(mShadowFocus.mMinView, source, bits2 & 4);
- readFloatDelta(mShadowFadeDistance, source, bits2 & 8);
- if (bits2 & 16)
- {
- int shadowIntensity = source.readUByte();
- mShadowIntensity = shadowIntensity / 255.0f;
- }
- if (bits2 & 32)
- {
- int shadowResolution = source.readUByte();
- mShadowResolution = shadowResolution / 100.0f;
- }
- readFloatDelta(mShadowNearFarRatio, source, bits2 & 64);
-
- if (bits)
- markDirty();
- }
- void Light::getResourceRefs(std::vector<Resource*>& dest)
- {
- if (mRampTexture)
- dest.push_back(mRampTexture);
- if (mSpotTexture)
- dest.push_back(mSpotTexture);
- }
- void Light::updateDistance(const FrameInfo& frame)
- {
- switch (mLightType)
- {
- case LIGHT_DIRECTIONAL:
- // Directional light affects the whole scene, so it is always "closest"
- mDistance = 0.0f;
- break;
-
- default:
- mDistance = frame.mCamera->getDistance(getWorldPosition());
- break;
- }
- }
- void Light::overrideTransforms(unsigned batchIndex, Camera& camera, const Matrix4x3** model, const Matrix4x3** view)
- {
- // Can use a static matrix because these are asked for one node at a time
- static Matrix4x3 lightModel;
-
- *model = &lightModel;
-
- switch (mLightType)
- {
- case LIGHT_DIRECTIONAL:
- lightModel = getDirLightTransform(camera, false);
- // Because of precision issues, set view to identity instead of adjusting model transform to match
- *view = &Matrix4x3::sIdentity;
- break;
-
- case LIGHT_POINT:
- lightModel.define(getWorldPosition(), Quaternion::sIdentity, mRange);
- break;
-
- case LIGHT_SPOT:
- {
- float yScale = tan(mFov * M_DEGTORAD * 0.5f) * mRange;
- float xScale = mAspectRatio * yScale;
- Quaternion rotation(Vector3(0.0f, 0.0f, 1.0f), mDirection);
- lightModel.define(getWorldPosition(), getWorldRotation() * rotation, Vector3(xScale, yScale, mRange));
- }
- break;
-
- case LIGHT_SPLITPOINT:
- {
- Quaternion rotation(Vector3(0.0f, 0.0f, 1.0f), mDirection);
- lightModel.define(getWorldPosition(), getWorldRotation() * rotation, mRange);
- }
- break;
- }
- }
- void Light::drawDebugGeometry(DebugRenderer* debug)
- {
- switch (mLightType)
- {
- case LIGHT_SPOT:
- debug->addFrustum(getFrustum(), mColor, false);
- break;
-
- case LIGHT_POINT:
- debug->addBoundingBox(getWorldBoundingBox(), getColor(), false);
- break;
- }
- }
- void Light::setLightType(LightType type)
- {
- mLightType = type;
-
- if (!isDirty())
- markDirty();
- }
- void Light::setDirection(const Vector3& direction)
- {
- mDirection = direction.getNormalized();
-
- if (!isDirty())
- markDirty();
- }
- void Light::setColor(const Color& color)
- {
- mColor = color;
- }
- void Light::setRange(float range)
- {
- mRange = max(range, 0.0f);
-
- if (!isDirty())
- markDirty();
- }
- void Light::setFov(float fov)
- {
- mFov = clamp(fov, 0.0f, M_MAX_FOV);
-
- if (!isDirty())
- markDirty();
- }
- void Light::setAspectRatio(float aspectRatio)
- {
- mAspectRatio = max(aspectRatio, M_EPSILON);
-
- if (!isDirty())
- markDirty();
- }
- void Light::setShadowNearFarRatio(float nearFarRatio)
- {
- mShadowNearFarRatio = clamp(nearFarRatio, 0.0f, 0.5f);
- }
- void Light::setSpecularIntensity(float intensity)
- {
- mSpecularIntensity = max(intensity, 0.0f);
- }
- void Light::setFadeDistance(float distance)
- {
- mFadeDistance = max(distance, 0.0f);
- }
- void Light::setDetailLevel(int detailLevel, int shadowDetailLevel)
- {
- mDetailLevel = clamp(detailLevel, 0, QUALITY_MAX);
- mShadowDetailLevel = clamp(shadowDetailLevel, 0, QUALITY_MAX);
- }
- void Light::setShadowBias(const BiasParameters& parameters)
- {
- mShadowBias = parameters;
- mShadowBias.validate();
- }
- void Light::setShadowCascade(const CascadeParameters& parameters)
- {
- mShadowCascade = parameters;
- mShadowCascade.validate();
- }
- void Light::setShadowFocus(const FocusParameters& parameters)
- {
- mShadowFocus = parameters;
- mShadowFocus.validate();
- }
- void Light::setShadowFadeDistance(float distance)
- {
- mShadowFadeDistance = max(distance, 0.0f);
- }
- void Light::setShadowIntensity(float intensity)
- {
- mShadowIntensity = clamp(intensity, 0.0f, 1.0f);
- }
- void Light::setShadowResolution(float resolution)
- {
- mShadowResolution = clamp(resolution, 0.25f, 1.0f);
- }
- void Light::setRampTexture(Texture* texture)
- {
- mRampTexture = texture;
- }
- void Light::setSpotTexture(Texture* texture)
- {
- mSpotTexture = texture;
- }
- void Light::copyFrom(Light* original)
- {
- setPosition(original->getWorldPosition());
- setRotation(original->getWorldRotation());
- setScale(original->getWorldScale());
- mCastShadows = original->mCastShadows;
- mDrawDistance = original->mDrawDistance;
- mShadowDistance = original->mShadowDistance;
- mViewMask = original->mViewMask;
- mLightMask = original->mLightMask;
- mDistance = original->mDistance;
- mDirection = original->mDirection;
- mLightType = original->mLightType;
- mRange = original->mRange;
- mFov = original->mFov;
- mAspectRatio = original->mAspectRatio;
- mColor = original->mColor;
- mSpecularIntensity = original->mSpecularIntensity;
- mFadeDistance = original->mFadeDistance;
- mShadowBias = original->mShadowBias;
- mShadowCascade = original->mShadowCascade;
- mShadowFocus = original->mShadowFocus;
- mShadowFadeDistance = original->mShadowFadeDistance;
- mShadowIntensity = original->mShadowIntensity;
- mShadowResolution = original->mShadowResolution;
- mRampTexture = original->mRampTexture;
- mSpotTexture = original->mSpotTexture;
- }
- bool Light::isNegative() const
- {
- return (mColor.mR < 0.0f) || (mColor.mG < 0.0f) || (mColor.mB < 0.0f);
- }
- const Frustum& Light::getFrustum()
- {
- // Note: frustum is also used for the point light when it is split for shadow rendering
- if (mFrustumDirty)
- {
- Matrix4x3 transform;
- Quaternion rotation(Vector3(0.0f, 0.0f, 1.0f), mDirection);
- transform.define(getWorldPosition(), getWorldRotation() * rotation, 1.0f);
- // Set a small near clip distance, so that the near plane can be calculated
- // Note: this is not necessarily the same near clip as on the actual shadow camera
- mFrustum.define(mFov, mAspectRatio, 1.0f, M_MIN_NEARCLIP, mRange, transform);
- }
-
- return mFrustum;
- }
- float Light::getVolumeExtent() const
- {
- switch (mLightType)
- {
- case LIGHT_POINT:
- return mRange * 1.36f;
-
- case LIGHT_SPOT:
- {
- float safeRange = mRange * 1.001f;
- float yScale = tan(mFov * M_DEGTORAD * 0.5f) * safeRange;
- float xScale = mAspectRatio * yScale;
- return sqrtf(xScale * xScale + yScale * yScale + safeRange * safeRange);
- }
-
- case LIGHT_SPLITPOINT:
- {
- float safeRange = mRange * 1.001f;
- return sqrtf(3.0f * safeRange * safeRange);
- }
-
- default:
- return M_LARGE_VALUE;
- }
- }
- Matrix4x3 Light::getDirLightTransform(Camera& camera, bool getNearQuad) const
- {
- Vector3 farVector = camera.getFrustumFarSize();
- float nearClip = camera.getNearClip();
- float farClip = camera.getFarClip();
-
- float distance;
-
- if (getNearQuad)
- distance = max(mNearSplit - mNearFadeRange, nearClip);
- else
- distance = min(mFarSplit, farClip);
- if (!camera.isOrthographic())
- farVector *= (distance / farClip);
- else
- farVector.mZ *= (distance / farClip);
-
- Matrix4x3 transform;
- transform.define(Vector3(0.0f, 0.0f, farVector.mZ), Quaternion::sIdentity, Vector3(farVector.mX, farVector.mY, 1.0f));
- return transform;
- }
- void Light::onMarkedDirty()
- {
- VolumeNode::onMarkedDirty();
-
- mFrustumDirty = true;
- }
- void Light::onWorldBoundingBoxUpdate(BoundingBox& worldBoundingBox)
- {
- switch (mLightType)
- {
- case LIGHT_DIRECTIONAL:
- // Directional light always sets humongous bounding box not affected by transform
- worldBoundingBox.define(-M_LARGE_VALUE, M_LARGE_VALUE);
- break;
-
- case LIGHT_POINT:
- {
- const Vector3& center = getWorldPosition();
- Vector3 edge(mRange, mRange, mRange);
- worldBoundingBox.define(center - edge, center + edge);
- }
- break;
-
- case LIGHT_SPOT:
- case LIGHT_SPLITPOINT:
- // Frustum is already transformed into world space
- worldBoundingBox.define(getFrustum());
- break;
- }
- }
- void Light::setNearSplit(float nearSplit)
- {
- mNearSplit = max(nearSplit, 0.0f);
- }
- void Light::setFarSplit(float farSplit)
- {
- mFarSplit = max(farSplit, 0.0f);
- }
- void Light::setNearFadeRange(float range)
- {
- mNearFadeRange = max(range, M_EPSILON);
- }
- void Light::setFarFadeRange(float range)
- {
- mFarFadeRange = max(range, M_EPSILON);
- }
- void Light::setShadowMap(Texture2D* shadowMap)
- {
- mShadowMap = shadowMap;
- }
|