Browse Source

Added inner and outer angle parameters to SoundSource3D, which makes it possible to do cone-like directional sounds. Fixed sound attenuation if near and far distance are the same. Closes #49.

Lasse Öörni 12 years ago
parent
commit
a37ea5bb6e

+ 3 - 0
Docs/AngelScriptAPI.h

@@ -4420,6 +4420,7 @@ void Play(Sound, float, float);
 void Play(Sound, float, float, float);
 void Stop();
 void SetDistanceAttenuation(float, float, float);
+void SetAngleAttenuation(float, float);
 
 // Properties:
 /* (readonly) */
@@ -4464,6 +4465,8 @@ bool autoRemove;
 bool playing;
 float nearDistance;
 float farDistance;
+float innerAngle;
+float outerAngle;
 float rolloffFactor;
 };
 

+ 8 - 0
Docs/LuaScriptAPI.dox

@@ -126,18 +126,25 @@ Properties:
 Methods:
 
 - void SetDistanceAttenuation(float nearDistance, float farDistance, float rolloffFactor)
+- void SetAngleAttenuation(float innerAngle, float outerAngle)
 - void SetNearDistance(float distance)
 - void SetFarDistance(float distance)
+- void SetInnerAngle(float angle)
+- void SetOuterAngle(float angle)
 - void SetRolloffFactor(float factor)
 - void CalculateAttenuation()
 - float GetNearDistance() const
 - float GetFarDistance() const
+- float GetInnerAngle() const
+- float GetOuterAngle() const
 - float RollAngleoffFactor() const
 
 Properties:
 
 - float nearDistance
 - float farDistance
+- float innerAngle
+- float outerAngle
 - float rolloffFactor
 
 ### PODVector
@@ -1156,6 +1163,7 @@ Properties:
 
 Methods:
 
+- RayQueryResult()
 
 Properties:
 

+ 3 - 0
Docs/ScriptAPI.dox

@@ -3798,6 +3798,7 @@ Methods:
 - void Play(Sound@, float, float, float)
 - void Stop()
 - void SetDistanceAttenuation(float, float, float)
+- void SetAngleAttenuation(float, float)
 
 Properties:
 
@@ -3827,6 +3828,8 @@ Properties:
 - bool playing (readonly)
 - float nearDistance
 - float farDistance
+- float innerAngle
+- float outerAngle
 - float rolloffFactor
 
 

+ 59 - 7
Source/Engine/Audio/SoundSource3D.cpp

@@ -36,6 +36,7 @@ namespace Urho3D
 static const float DEFAULT_NEARDISTANCE = 0.0f;
 static const float DEFAULT_FARDISTANCE = 100.0f;
 static const float DEFAULT_ROLLOFF = 2.0f;
+static const float DEFAULT_ANGLE = 360.0f;
 static const float MIN_ROLLOFF = 0.1f;
 
 extern const char* AUDIO_CATEGORY;
@@ -44,6 +45,8 @@ SoundSource3D::SoundSource3D(Context* context) :
     SoundSource(context),
     nearDistance_(DEFAULT_NEARDISTANCE),
     farDistance_(DEFAULT_FARDISTANCE),
+    outerAngle_(DEFAULT_ANGLE),
+    innerAngle_(DEFAULT_ANGLE),
     rolloffFactor_(DEFAULT_ROLLOFF)
 {
     // Start from zero volume until attenuation properly calculated
@@ -60,6 +63,8 @@ void SoundSource3D::RegisterObject(Context* context)
     REMOVE_ATTRIBUTE(SoundSource3D, "Panning");
     ATTRIBUTE(SoundSource3D, VAR_FLOAT, "Near Distance", nearDistance_, DEFAULT_NEARDISTANCE, AM_DEFAULT);
     ATTRIBUTE(SoundSource3D, VAR_FLOAT, "Far Distance", farDistance_, DEFAULT_FARDISTANCE, AM_DEFAULT);
+    ATTRIBUTE(SoundSource3D, VAR_FLOAT, "Inner Angle", innerAngle_, DEFAULT_ANGLE, AM_DEFAULT);
+    ATTRIBUTE(SoundSource3D, VAR_FLOAT, "Outer Angle", outerAngle_, DEFAULT_ANGLE, AM_DEFAULT);
     ATTRIBUTE(SoundSource3D, VAR_FLOAT, "Rolloff Factor", rolloffFactor_, DEFAULT_ROLLOFF, AM_DEFAULT);
 }
 
@@ -77,6 +82,13 @@ void SoundSource3D::SetDistanceAttenuation(float nearDistance, float farDistance
     MarkNetworkUpdate();
 }
 
+void SoundSource3D::SetAngleAttenuation(float innerAngle, float outerAngle)
+{
+    innerAngle_ = Clamp(innerAngle, 0.0f, DEFAULT_ANGLE);
+    outerAngle_ = Clamp(outerAngle, 0.0f, DEFAULT_ANGLE);
+    MarkNetworkUpdate();
+}
+
 void SoundSource3D::SetFarDistance(float distance)
 {
     farDistance_ = Max(distance, 0.0f);
@@ -89,6 +101,18 @@ void SoundSource3D::SetNearDistance(float distance)
     MarkNetworkUpdate();
 }
 
+void SoundSource3D::SetInnerAngle(float angle)
+{
+    innerAngle_ = Clamp(angle, 0.0f, DEFAULT_ANGLE);
+    MarkNetworkUpdate();
+}
+
+void SoundSource3D::SetOuterAngle(float angle)
+{
+    outerAngle_ = Clamp(angle, 0.0f, DEFAULT_ANGLE);
+    MarkNetworkUpdate();
+}
+
 void SoundSource3D::SetRolloffFactor(float factor)
 {
     rolloffFactor_ = Max(factor, MIN_ROLLOFF);
@@ -101,7 +125,7 @@ void SoundSource3D::CalculateAttenuation()
         return;
 
     float interval = farDistance_ - nearDistance_;
-    if (interval > 0.0f && node_)
+    if (node_)
     {
         SoundListener* listener = audio_->GetListener();
 
@@ -110,12 +134,40 @@ void SoundSource3D::CalculateAttenuation()
         {
             Node* listenerNode = listener->GetNode();
             Vector3 relativePos(listenerNode->GetWorldRotation().Inverse() * (node_->GetWorldPosition() - listenerNode->GetWorldPosition()));
-            float distance = Clamp(relativePos.Length() - nearDistance_, 0.0f, interval);
-            float attenuation = powf(1.0f - distance / interval, rolloffFactor_);
-            float panning = relativePos.Normalized().x_;
-
-            attenuation_ = attenuation;
-            panning_ = panning;
+            float distance = relativePos.Length();
+            
+            // Distance attenuation
+            if (interval > 0.0f)
+                attenuation_ = powf(1.0f - Clamp(distance - nearDistance_, 0.0f, interval) / interval, rolloffFactor_);
+            else
+                attenuation_ = distance <= nearDistance_ ? 1.0f : 0.0f;
+            
+            // Panning
+            panning_ = relativePos.Normalized().x_;
+            
+            // Angle attenuation
+            if (innerAngle_ < DEFAULT_ANGLE)
+            {
+                Vector3 listenerRelativePos(node_->GetWorldRotation().Inverse() * (listenerNode->GetWorldPosition() -
+                    node_->GetWorldPosition()));
+                float listenerDot = Vector3::FORWARD.DotProduct(listenerRelativePos.Normalized());
+                float listenerAngle = acosf(listenerDot) * M_RADTODEG * 2.0f;
+                float angleInterval = Max(outerAngle_ - innerAngle_, 0.0f);
+                float angleAttenuation = 1.0f;
+                
+                if (angleInterval > 0.0f)
+                {
+                    if (listenerAngle > innerAngle_)
+                    {
+                        angleAttenuation = powf(1.0f - Clamp(listenerAngle - innerAngle_, 0.0f, angleInterval) / angleInterval,
+                            rolloffFactor_);
+                    }
+                }
+                else
+                    angleAttenuation = listenerAngle <= innerAngle_ ? 1.0f : 0.0f;
+                
+                attenuation_ *= angleAttenuation;
+            }
         }
         else
             attenuation_ = 0.0f;

+ 16 - 2
Source/Engine/Audio/SoundSource3D.h

@@ -45,10 +45,16 @@ public:
     
     /// Set attenuation parameters.
     void SetDistanceAttenuation(float nearDistance, float farDistance, float rolloffFactor);
-    /// Set near distance. Distances closer than this do not have an effect.
+    /// Set angle attenuation parameters.
+    void SetAngleAttenuation(float innerAngle, float outerAngle);
+    /// Set near distance. Inside this range sound will not be attenuated.
     void SetNearDistance(float distance);
-    /// Set far distance. Beyond this sound will be completely attenuated.
+    /// Set far distance. Outside this range sound will be completely attenuated.
     void SetFarDistance(float distance);
+    /// Set inner angle in degrees. Inside this angle sound will not be attenuated.By default 360, meaning direction never has an effect.
+    void SetInnerAngle(float angle);
+    /// Set outer angle in degrees. Outside this angle sound will be completely attenuated. By default 360, meaning direction never has an effect.
+    void SetOuterAngle(float angle);
     /// Set rolloff power factor, defines attenuation function shape.
     void SetRolloffFactor(float factor);
     /// Calculate attenuation and panning based on current position and listener position.
@@ -58,6 +64,10 @@ public:
     float GetNearDistance() const { return nearDistance_; }
     /// Return far distance.
     float GetFarDistance() const { return farDistance_; }
+    /// Return inner angle in degrees.
+    float GetInnerAngle() const { return innerAngle_; }
+    /// Return outer angle in degrees.
+    float GetOuterAngle() const { return outerAngle_; }
     /// Return rolloff power factor.
     float RollAngleoffFactor() const { return rolloffFactor_; }
     
@@ -66,6 +76,10 @@ protected:
     float nearDistance_;
     /// Far distance.
     float farDistance_;
+    /// Inner angle for directional attenuation.
+    float innerAngle_;
+    /// Outer angle for directional attenuation.
+    float outerAngle_;
     /// Rolloff power factor.
     float rolloffFactor_;
 };

+ 7 - 0
Source/Engine/LuaScript/pkgs/Audio/SoundSource3D.pkg

@@ -3,17 +3,24 @@ $#include "SoundSource3D.h"
 class SoundSource3D : public SoundSource
 {
     void SetDistanceAttenuation(float nearDistance, float farDistance, float rolloffFactor);
+    void SetAngleAttenuation(float innerAngle, float outerAngle);
     void SetNearDistance(float distance);
     void SetFarDistance(float distance);
+    void SetInnerAngle(float angle);
+    void SetOuterAngle(float angle);
     void SetRolloffFactor(float factor);
     void CalculateAttenuation();
     
     float GetNearDistance() const;
     float GetFarDistance() const;
+    float GetInnerAngle() const;
+    float GetOuterAngle() const;
     float RollAngleoffFactor() const;
     
     tolua_property__get_set float nearDistance;
     tolua_property__get_set float farDistance;
+    tolua_property__get_set float innerAngle;
+    tolua_property__get_set float outerAngle;
     tolua_property__get_set float rolloffFactor;
 };
 

+ 5 - 0
Source/Engine/Script/AudioAPI.cpp

@@ -57,10 +57,15 @@ void RegisterSoundSources(asIScriptEngine* engine)
     // Allow creation of sound sources also outside scene
     RegisterObjectConstructor<SoundSource>(engine, "SoundSource");
     engine->RegisterObjectMethod("SoundSource3D", "void SetDistanceAttenuation(float, float, float)", asMETHOD(SoundSource3D, SetDistanceAttenuation), asCALL_THISCALL);
+    engine->RegisterObjectMethod("SoundSource3D", "void SetAngleAttenuation(float, float)", asMETHOD(SoundSource3D, SetAngleAttenuation), asCALL_THISCALL);
     engine->RegisterObjectMethod("SoundSource3D", "void set_nearDistance(float)", asMETHOD(SoundSource3D, SetNearDistance), asCALL_THISCALL);
     engine->RegisterObjectMethod("SoundSource3D", "float get_nearDistance() const", asMETHOD(SoundSource3D, GetNearDistance), asCALL_THISCALL);
     engine->RegisterObjectMethod("SoundSource3D", "void set_farDistance(float)", asMETHOD(SoundSource3D, SetFarDistance), asCALL_THISCALL);
     engine->RegisterObjectMethod("SoundSource3D", "float get_farDistance() const", asMETHOD(SoundSource3D, GetFarDistance), asCALL_THISCALL);
+    engine->RegisterObjectMethod("SoundSource3D", "void set_innerAngle(float)", asMETHOD(SoundSource3D, SetInnerAngle), asCALL_THISCALL);
+    engine->RegisterObjectMethod("SoundSource3D", "float get_innerAngle() const", asMETHOD(SoundSource3D, GetInnerAngle), asCALL_THISCALL);
+    engine->RegisterObjectMethod("SoundSource3D", "void set_outerAngle(float)", asMETHOD(SoundSource3D, SetOuterAngle), asCALL_THISCALL);
+    engine->RegisterObjectMethod("SoundSource3D", "float get_outerAngle() const", asMETHOD(SoundSource3D, GetOuterAngle), asCALL_THISCALL);
     engine->RegisterObjectMethod("SoundSource3D", "void set_rolloffFactor(float)", asMETHOD(SoundSource3D, SetRolloffFactor), asCALL_THISCALL);
     engine->RegisterObjectMethod("SoundSource3D", "float get_rolloffFactor() const", asMETHOD(SoundSource3D, RollAngleoffFactor), asCALL_THISCALL);
 }