mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-21 08:23:53 +00:00
Refraction can be disabled separately now
This commit is contained in:
parent
a29919d02d
commit
3772cd9257
11 changed files with 72 additions and 53 deletions
|
@ -123,6 +123,7 @@ namespace MWGui
|
|||
getWidget(mInvertYButton, "InvertYButton");
|
||||
getWidget(mUISensitivitySlider, "UISensitivitySlider");
|
||||
getWidget(mCameraSensitivitySlider, "CameraSensitivitySlider");
|
||||
getWidget(mRefractionButton, "RefractionButton");
|
||||
|
||||
mSubtitlesButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled);
|
||||
mCrosshairButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled);
|
||||
|
@ -133,6 +134,7 @@ namespace MWGui
|
|||
mShaderModeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShaderModeToggled);
|
||||
mFullscreenButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled);
|
||||
mWaterShaderButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled);
|
||||
mRefractionButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled);
|
||||
mReflectObjectsButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled);
|
||||
mReflectTerrainButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled);
|
||||
mReflectActorsButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled);
|
||||
|
@ -248,6 +250,8 @@ namespace MWGui
|
|||
mShadersButton->setCaption (Settings::Manager::getBool("shaders", "Objects") ? "on" : "off");
|
||||
mShaderModeButton->setCaption (Settings::Manager::getString("shader mode", "General"));
|
||||
|
||||
mRefractionButton->setCaption (Settings::Manager::getBool("refraction", "Water") ? "on" : "off");
|
||||
|
||||
if (!MWRender::RenderingManager::waterShaderSupported())
|
||||
{
|
||||
mWaterShaderButton->setEnabled(false);
|
||||
|
@ -376,6 +380,8 @@ namespace MWGui
|
|||
{
|
||||
if (_sender == mWaterShaderButton)
|
||||
Settings::Manager::setBool("shader", "Water", newState);
|
||||
else if (_sender == mRefractionButton)
|
||||
Settings::Manager::setBool("refraction", "Water", newState);
|
||||
else if (_sender == mUnderwaterButton)
|
||||
{
|
||||
Settings::Manager::setBool("underwater effect", "Water", newState);
|
||||
|
|
|
@ -51,6 +51,7 @@ namespace MWGui
|
|||
MyGUI::Button* mShadersButton;
|
||||
MyGUI::Button* mShaderModeButton;
|
||||
MyGUI::Button* mUnderwaterButton;
|
||||
MyGUI::Button* mRefractionButton;
|
||||
|
||||
MyGUI::Button* mShadowsEnabledButton;
|
||||
MyGUI::Button* mShadowsLargeDistance;
|
||||
|
|
|
@ -135,8 +135,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
|
|||
sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty<sh::FloatValue>(new sh::FloatValue(0)));
|
||||
sh::Factory::getInstance ().setSharedParameter ("windDir_windSpeed", sh::makeProperty<sh::Vector3>(new sh::Vector3(0.5, -0.8, 0.2)));
|
||||
sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty<sh::Vector2>(new sh::Vector2(1, 0.6)));
|
||||
sh::Factory::getInstance ().setSharedParameter ("gammaCorrection", sh::makeProperty<sh::FloatValue>(new sh::FloatValue(
|
||||
1.f)));
|
||||
sh::Factory::getInstance ().setGlobalSetting ("refraction", Settings::Manager::getBool("refraction", "Water") ? "true" : "false");
|
||||
|
||||
applyCompositors();
|
||||
|
||||
|
@ -757,6 +756,7 @@ Compositors* RenderingManager::getCompositors()
|
|||
void RenderingManager::processChangedSettings(const Settings::CategorySettingVector& settings)
|
||||
{
|
||||
bool changeRes = false;
|
||||
bool rebuild = false; // rebuild static geometry (necessary after any material changes)
|
||||
for (Settings::CategorySettingVector::const_iterator it=settings.begin();
|
||||
it != settings.end(); ++it)
|
||||
{
|
||||
|
@ -794,18 +794,23 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec
|
|||
applyCompositors();
|
||||
sh::Factory::getInstance ().setGlobalSetting ("mrt_output", useMRT() ? "true" : "false");
|
||||
sh::Factory::getInstance ().setGlobalSetting ("simple_water", Settings::Manager::getBool("shader", "Water") ? "false" : "true");
|
||||
mObjects.rebuildStaticGeometry ();
|
||||
rebuild = true;
|
||||
mRendering.getViewport ()->setClearEveryFrame (true);
|
||||
}
|
||||
else if (it->second == "refraction" && it->first == "Water")
|
||||
{
|
||||
sh::Factory::getInstance ().setGlobalSetting ("refraction", Settings::Manager::getBool("refraction", "Water") ? "true" : "false");
|
||||
rebuild = true;
|
||||
}
|
||||
else if (it->second == "underwater effect" && it->first == "Water")
|
||||
{
|
||||
sh::Factory::getInstance ().setGlobalSetting ("underwater_effects", Settings::Manager::getString("underwater effect", "Water"));
|
||||
mObjects.rebuildStaticGeometry ();
|
||||
rebuild = true;
|
||||
}
|
||||
else if (it->second == "shaders" && it->first == "Objects")
|
||||
{
|
||||
sh::Factory::getInstance ().setShadersEnabled (Settings::Manager::getBool("shaders", "Objects"));
|
||||
mObjects.rebuildStaticGeometry ();
|
||||
rebuild = true;
|
||||
}
|
||||
else if (it->second == "shader mode" && it->first == "General")
|
||||
{
|
||||
|
@ -818,13 +823,13 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec
|
|||
else
|
||||
lang = sh::Language_CG;
|
||||
sh::Factory::getInstance ().setCurrentLanguage (lang);
|
||||
mObjects.rebuildStaticGeometry ();
|
||||
rebuild = true;
|
||||
}
|
||||
else if (it->first == "Shadows")
|
||||
{
|
||||
mShadows->recreate ();
|
||||
|
||||
mObjects.rebuildStaticGeometry ();
|
||||
rebuild = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -842,6 +847,9 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec
|
|||
|
||||
if (mWater)
|
||||
mWater->processChangedSettings(settings);
|
||||
|
||||
if (rebuild)
|
||||
mObjects.rebuildStaticGeometry();
|
||||
}
|
||||
|
||||
void RenderingManager::setMenuTransparency(float val)
|
||||
|
|
|
@ -430,8 +430,11 @@ void Water::applyRTT()
|
|||
delete mRefraction;
|
||||
mRefraction = NULL;
|
||||
|
||||
if (Settings::Manager::getBool("refraction", "Water"))
|
||||
{
|
||||
mRefraction = new Refraction(mCamera);
|
||||
mRefraction->setHeight(mTop);
|
||||
}
|
||||
}
|
||||
|
||||
void Water::applyVisibilityMask()
|
||||
|
@ -456,6 +459,7 @@ void Water::processChangedSettings(const Settings::CategorySettingVector& settin
|
|||
{
|
||||
if ( it->first == "Water" && (
|
||||
it->second == "shader"
|
||||
|| it->second == "refraction"
|
||||
|| it->second == "rtt size"))
|
||||
applyRT = true;
|
||||
|
||||
|
|
|
@ -1,9 +1,3 @@
|
|||
//#define gammaCorrectRead(v) pow(max(v, 0.00001f), float3(gammaCorrection,gammaCorrection,gammaCorrection))
|
||||
//#define gammaCorrectOutput(v) pow(max(v, 0.00001f), float3(1.f/gammaCorrection,1.f/gammaCorrection,1.f/gammaCorrection))
|
||||
|
||||
#define gammaCorrectRead(v) v
|
||||
#define gammaCorrectOutput(v) v
|
||||
|
||||
#if SH_HLSL == 1 || SH_CG == 1
|
||||
|
||||
#define shTexture2D sampler2D
|
||||
|
|
|
@ -112,8 +112,6 @@
|
|||
shUniform(float, far) @shAutoConstant(far, far_clip_distance)
|
||||
#endif
|
||||
|
||||
//shUniform(float, gammaCorrection) @shSharedParameter(gammaCorrection, gammaCorrection)
|
||||
|
||||
#if LIGHTING
|
||||
shInput(float3, normalPassthrough)
|
||||
shInput(float3, objSpacePositionPassthrough)
|
||||
|
@ -180,7 +178,6 @@
|
|||
SH_START_PROGRAM
|
||||
{
|
||||
shOutputColour(0) = shSample(diffuseMap, UV);
|
||||
shOutputColour(0).xyz = gammaCorrectRead(shOutputColour(0).xyz);
|
||||
|
||||
#if LIGHTING
|
||||
float3 normal = normalize(normalPassthrough);
|
||||
|
@ -271,7 +268,7 @@
|
|||
// regular fog only if fragment is above water
|
||||
if (worldPos.y > waterLevel || waterEnabled != 1.f)
|
||||
#endif
|
||||
shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, gammaCorrectRead(fogColour), fogValue);
|
||||
shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue);
|
||||
#endif
|
||||
|
||||
// prevent negative colour output (for example with negative lights)
|
||||
|
@ -286,11 +283,11 @@
|
|||
|
||||
float waterSunGradient = dot(eyeVec, -normalize(lightDirectionWS0.xyz));
|
||||
waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0));
|
||||
float3 waterSunColour = gammaCorrectRead(float3(0.0,1.0,0.85)) *waterSunGradient * 0.5;
|
||||
float3 waterSunColour = float3(0.0,1.0,0.85) *waterSunGradient * 0.5;
|
||||
|
||||
float waterGradient = dot(eyeVec, float3(0.0,-1.0,0.0));
|
||||
waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0);
|
||||
float3 watercolour = ( gammaCorrectRead(float3(0.0078, 0.5176, 0.700))+waterSunColour)*waterGradient*2.0;
|
||||
float3 watercolour = ( float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0;
|
||||
watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT)));
|
||||
watercolour = (cameraPos.y <= waterLevel) ? watercolour : watercolour*0.3;
|
||||
|
||||
|
@ -303,8 +300,6 @@
|
|||
shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater * waterEnabled);
|
||||
#endif
|
||||
|
||||
shOutputColour(0).xyz = gammaCorrectOutput(shOutputColour(0).xyz);
|
||||
|
||||
#if MRT
|
||||
shOutputColour(1) = float4(depthPassthrough / far,1,1,1);
|
||||
#endif
|
||||
|
|
|
@ -137,8 +137,6 @@
|
|||
|
||||
shSampler2D(normalMap) // global normal map
|
||||
|
||||
//shUniform(float, gammaCorrection) @shSharedParameter(gammaCorrection, gammaCorrection)
|
||||
|
||||
|
||||
@shForeach(@shPropertyString(num_blendmaps))
|
||||
shSampler2D(blendMap@shIterator)
|
||||
|
@ -254,9 +252,9 @@
|
|||
|
||||
#if IS_FIRST_PASS == 1 && @shIterator == 0
|
||||
// first layer of first pass doesn't need a blend map
|
||||
albedo = gammaCorrectRead(shSample(diffuseMap0, UV * 10).rgb);
|
||||
albedo = shSample(diffuseMap0, UV * 10).rgb;
|
||||
#else
|
||||
albedo = shLerp(albedo, gammaCorrectRead(shSample(diffuseMap@shIterator, UV * 10).rgb), blendValues@shPropertyString(blendmap_component_@shIterator));
|
||||
albedo = shLerp(albedo, shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator));
|
||||
|
||||
#endif
|
||||
@shEndForeach
|
||||
|
@ -343,7 +341,7 @@
|
|||
// regular fog only if fragment is above water
|
||||
if (worldPos.y > waterLevel)
|
||||
#endif
|
||||
shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, gammaCorrectRead(fogColour), fogValue);
|
||||
shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue);
|
||||
#endif
|
||||
|
||||
// prevent negative colour output (for example with negative lights)
|
||||
|
@ -358,12 +356,12 @@
|
|||
|
||||
float waterSunGradient = dot(eyeVec, -normalize(lightDirectionWS0.xyz));
|
||||
waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0));
|
||||
float3 waterSunColour = gammaCorrectRead(float3(0.0,1.0,0.85))*waterSunGradient * 0.5;
|
||||
float3 waterSunColour = float3(0.0,1.0,0.85)*waterSunGradient * 0.5;
|
||||
|
||||
float waterGradient = dot(eyeVec, float3(0.0,-1.0,0.0));
|
||||
waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0);
|
||||
float3 watercolour = (gammaCorrectRead(float3(0.0078, 0.5176, 0.700))+waterSunColour)*waterGradient*2.0;
|
||||
float3 waterext = gammaCorrectRead(float3(0.6, 0.9, 1.0));//water extinction
|
||||
float3 watercolour = (float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0;
|
||||
float3 waterext = float3(0.6, 0.9, 1.0);//water extinction
|
||||
watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT)));
|
||||
watercolour = (cameraPos.y <= waterLevel) ? watercolour : watercolour*0.3;
|
||||
|
||||
|
@ -376,8 +374,6 @@
|
|||
shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater);
|
||||
#endif
|
||||
|
||||
shOutputColour(0).xyz = gammaCorrectOutput(shOutputColour(0).xyz);
|
||||
|
||||
#if MRT
|
||||
shOutputColour(1) = float4(depth / far,1,1,1);
|
||||
#endif
|
||||
|
|
|
@ -12,6 +12,9 @@ material Water
|
|||
|
||||
cull_hardware none
|
||||
|
||||
scene_blend alpha_blend
|
||||
depth_write off
|
||||
|
||||
texture_unit reflectionMap
|
||||
{
|
||||
texture_alias WaterReflection
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
// Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html )
|
||||
|
||||
#define RIPPLES 1
|
||||
#define REFRACTION @shGlobalSettingBool(refraction)
|
||||
|
||||
#ifdef SH_VERTEX_SHADER
|
||||
|
||||
|
@ -123,9 +124,9 @@
|
|||
#define REFR_BUMP 0.12 // refraction distortion amount
|
||||
|
||||
#define SCATTER_AMOUNT 3.0 // amount of sunlight scattering
|
||||
#define SCATTER_COLOUR gammaCorrectRead(float3(0.0,1.0,0.95)) // colour of sunlight scattering
|
||||
#define SCATTER_COLOUR float3(0.0,1.0,0.95) // colour of sunlight scattering
|
||||
|
||||
#define SUN_EXT gammaCorrectRead(float3(0.45, 0.55, 0.68)) //sunlight extinction
|
||||
#define SUN_EXT float3(0.45, 0.55, 0.68) //sunlight extinction
|
||||
|
||||
#define SPEC_HARDNESS 256 // specular highlights hardness
|
||||
|
||||
|
@ -168,7 +169,9 @@
|
|||
shUniform(float, far) @shAutoConstant(far, far_clip_distance)
|
||||
|
||||
shSampler2D(reflectionMap)
|
||||
#if REFRACTION
|
||||
shSampler2D(refractionMap)
|
||||
#endif
|
||||
shSampler2D(depthMap)
|
||||
shSampler2D(normalMap)
|
||||
|
||||
|
@ -187,9 +190,6 @@
|
|||
shUniform(float4, sunPosition) @shAutoConstant(sunPosition, light_position, 0)
|
||||
shUniform(float4, sunSpecular) @shAutoConstant(sunSpecular, light_specular_colour, 0)
|
||||
|
||||
shUniform(float, gammaCorrection) @shSharedParameter(gammaCorrection, gammaCorrection)
|
||||
|
||||
|
||||
shUniform(float, renderTargetFlipping) @shAutoConstant(renderTargetFlipping, render_target_flipping)
|
||||
|
||||
|
||||
|
@ -255,7 +255,7 @@
|
|||
|
||||
float s = shSaturate(dot(lR, vVec)*2.0-1.2);
|
||||
float lightScatter = shSaturate(dot(-lVec,lNormal)*0.7+0.3) * s * SCATTER_AMOUNT * waterSunFade_sunHeight.x * shSaturate(1.0-exp(-waterSunFade_sunHeight.y));
|
||||
float3 scatterColour = shLerp(float3(SCATTER_COLOUR)*gammaCorrectRead(float3(1.0,0.4,0.0)), SCATTER_COLOUR, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT)));
|
||||
float3 scatterColour = shLerp(float3(SCATTER_COLOUR)*float3(1.0,0.4,0.0), SCATTER_COLOUR, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT)));
|
||||
|
||||
// fresnel
|
||||
float ior = (cameraPos.y>0)?(1.333/1.0):(1.0/1.333); //air to water; water to air
|
||||
|
@ -264,32 +264,36 @@
|
|||
fresnel = shSaturate(fresnel);
|
||||
|
||||
// reflection
|
||||
float3 reflection = gammaCorrectRead(shSample(reflectionMap, screenCoords+(normal.xz*REFL_BUMP)).rgb);
|
||||
float3 reflection = shSample(reflectionMap, screenCoords+(normal.xz*REFL_BUMP)).rgb;
|
||||
|
||||
// refraction
|
||||
float3 R = reflect(vVec, normal);
|
||||
|
||||
float3 refraction = gammaCorrectRead(shSample(refractionMap, (screenCoords-(normal.xz*REFR_BUMP))*1.0).rgb);
|
||||
#if REFRACTION
|
||||
float3 refraction = shSample(refractionMap, (screenCoords-(normal.xz*REFR_BUMP))*1.0).rgb;
|
||||
|
||||
// brighten up the refraction underwater
|
||||
refraction = (cameraPos.y < 0) ? shSaturate(refraction * 1.5) : refraction;
|
||||
|
||||
#endif
|
||||
// specular
|
||||
float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS);
|
||||
|
||||
#if REFRACTION
|
||||
shOutputColour(0).xyz = shLerp( shLerp(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * sunSpecular.xyz;
|
||||
|
||||
#else
|
||||
shOutputColour(0).xyz = reflection + specular * sunSpecular.xyz;
|
||||
#endif
|
||||
// fog
|
||||
if (isUnderwater == 1)
|
||||
{
|
||||
float waterSunGradient = dot(-vVec, -lVec);
|
||||
waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0));
|
||||
float3 waterSunColour = gammaCorrectRead(float3(0.0,1.0,0.85))*waterSunGradient * 0.5;
|
||||
float3 waterSunColour = float3(0.0,1.0,0.85)*waterSunGradient * 0.5;
|
||||
|
||||
float waterGradient = dot(-vVec, float3(0.0,-1.0,0.0));
|
||||
waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0);
|
||||
float3 watercolour = (gammaCorrectRead(float3(0.0078, 0.5176, 0.700))+waterSunColour)*waterGradient*2.0;
|
||||
float3 waterext = gammaCorrectRead(float3(0.6, 0.9, 1.0));//water extinction
|
||||
float3 watercolour = (float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0;
|
||||
float3 waterext = float3(0.6, 0.9, 1.0);//water extinction
|
||||
watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT)));
|
||||
|
||||
float darkness = VISIBILITY*2.0;
|
||||
|
@ -302,11 +306,14 @@
|
|||
else
|
||||
{
|
||||
float fogValue = shSaturate((length(cameraPos.xyz-position.xyz) - fogParams.y) * fogParams.w);
|
||||
shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, gammaCorrectRead(fogColor), fogValue);
|
||||
shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColor, fogValue);
|
||||
}
|
||||
|
||||
shOutputColour(0).xyz = gammaCorrectOutput(shOutputColour(0).xyz);
|
||||
#if REFRACTION
|
||||
shOutputColour(0).w = 1;
|
||||
#else
|
||||
shOutputColour(0).w = shSaturate(fresnel + specular);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -285,6 +285,13 @@
|
|||
<Property key="Caption" value="Underwater effects (caustics, fog)"/>
|
||||
</Widget>
|
||||
</Widget>
|
||||
|
||||
<Widget type="HBox" position="4 182 350 24">
|
||||
<Widget type="AutoSizedButton" skin="MW_Button" align="Left Top" name="RefractionButton"/>
|
||||
<Widget type="AutoSizedTextBox" skin="SandText" align="Left Top">
|
||||
<Property key="Caption" value="Refraction"/>
|
||||
</Widget>
|
||||
</Widget>
|
||||
</Widget>
|
||||
|
||||
<Widget type="TabItem" skin="" position="4 28 344 272">
|
||||
|
|
|
@ -127,11 +127,10 @@ fog end factor = 1.0
|
|||
num lights = 8
|
||||
|
||||
[Water]
|
||||
# Enable this to get fancy-looking water with reflections and refractions
|
||||
# Only available if object shaders are on
|
||||
# All the settings below have no effect if this is false
|
||||
shader = false
|
||||
|
||||
refraction = false
|
||||
|
||||
rtt size = 512
|
||||
reflect terrain = true
|
||||
reflect statics = false
|
||||
|
@ -139,7 +138,6 @@ reflect small statics = false
|
|||
reflect actors = false
|
||||
reflect misc = false
|
||||
|
||||
# Enable underwater effect. It is not resource intensive, so only disable it if you have problems.
|
||||
underwater effect = false
|
||||
|
||||
[Sound]
|
||||
|
|
Loading…
Reference in a new issue