Welcome, Guest. Please login or register. Did you miss your activation email?

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Topics - SuperApe

Pages: [1]
1
The "help" I'm looking for is really a request to double-check I used SFML as it was intended to be used for my case, and then the request would be to make this clearer in the documentation in one or two places, if so.

I post this as I have just gotten all to work as expected / intended, but the route to get here was painful, so I'm hoping to see changes to documentation that help others in a similar situation.

The subject is using the static Listener and setting properties on Sound object instances to achieve spatial audio in a 2D environment, where the Listener is to match the View position, and sounds would therefore really only register as "to the left" or "to the right" in relation to the center of the view, with proper attenuation.

All audio used is mono, so spatial audio is possible. Some of the audio used in the project is not meant to be spatial (music, ui sfx) and so there are different configurations that were needed.

References used in this effort include the SoundSource doc https://www.sfml-dev.org/documentation/2.5.1/classsf_1_1SoundSource.php and static Listener doc https://www.sfml-dev.org/documentation/2.5.1/classsf_1_1Listener.php.

Additionally, the Spatialization tutorial https://www.sfml-dev.org/tutorials/2.5/audio-spatialization.php and then this forum thread https://en.sfml-dev.org/forums/index.php?topic=14566.0 helped to highlight where I was having problems understanding the API intent, so ultimately it helps to reference all these.

With all that said, and understanding that we're all careful, we (largely) read documentation before making assumptions, and we (largely) make mistakes from time to time, worthy of improvement, I humbly suggest we revisit how this kind of effort is documented. There are a couple of things to point out in terms of how the documentation presents the tools available.

The Spatialization tutorial says this:
Quote
(in General) By default, sounds and music are played at full volume in each speaker; they are not spatialized. ... (for Audio Sources) The main property is the position of the audio source. ... This position is absolute by default, but it can be relative to the listener if needed. ... This can be useful for sounds emitted by the listener itself (like a gun shot, or foot steps). It also has the interesting side-effect of disabling spatialization if you set the position of the audio source to (0, 0, 0). Non-spatialized sounds can be required in various situations: GUI sounds (clicks), ambient music, etc.
The concern here is simply that the sound results are defined in two states: absolute and relative (to listener); however if you read this carefully, you are hearing "default = absolute = full volume both speakers" and then "relative = emitted by listener itself = examples: foot steps, gui sounds, ambient music". Which, are actually describing the same results: full volume both speakers. This could be carefully cleaned up in the documentation to avoid confusion by clearly defining two states of the sound source: absolute and relative.

I suggest that without clearing it up, absolute sound by default apparently means the sound seems emitted at the listener location. But that conflicts with what the SoundSource class documentation has to say:
Quote
void sf::SoundSource::setRelativeToListener(bool relative)   
Make the sound's position relative to the listener or absolute.

Making a sound relative to the listener will ensure that it will always be played the same way regardless of the position of the listener. This can be useful for non-spatialized sounds, sounds that are produced by the listener, or sounds attached to it. The default value is false (position is absolute).

Parameters
relative   True to set the position relative, false to set it absolute
Here is where the solution to my particular setup fell into place, but only by realizing that the word "relative", as in, "this sound source position relative to the listener position", actually is used in an inverse meaning. Based on the explanation, rather than the word "relative", it was clear what was meant is the SoundSource position will seem as if it is following the Listener position, as if it is the same position as the Listener with no difference, no delta.

"Relative", I'm suggesting, actually infers a difference between two, with a delta that in this case would make sense for spatialization. In other words, if a sound is relative to the listener, the suggested meaning is that this enables spatialization between sound and listener. But in practice, the opposite is true.

So I'm suggesting a) the word "relative" was used in a misleading way (if not opposite), and b) the description of the results called for with relative = true matches what the Spatialization tutorial says is already default (absolute) behavior; in other words, this documentation again conflicts.

That was my first point, the use of the word "relative" in the method name, property name conflicts with the actual results. My suggestion is documentation can call this out more clearly, and help others in the future. (I'm not suggesting you change the API to fit the language, I know that's too much to ask at this point)

The second point has to do with the practical use for spatialization of audio in 2D, and without a clear example, the development was more painful than necessary, and a short example in the documentation would be excellent. So this calls for another sanity check: did I do this as the API expects I would, because it seemed as intuitive as I could get it.

Again, there is a brief mention in the Spatialization tutorial
Quote
If you have a 2D world you can just use the same Y value everywhere, usually 0.
So, to be honest, that threw me off for a while. Converting my moving view center position to (x, 0, y) for the 3D vector needed by the listener was not intuitive and did not yield expected results. And setting SourceSource locations to match this space was tried in many different attempts to follow this guidance. All this didn't turn out to be necessary in the end.

In fact, here is what worked:
    sf::Listener::setDirection(0.f,0.f,-1.f);
    sf::Listener::setUpVector(0.f,1.f,0.f);
    while (gameLoop) {
        sf::Listener::setPosition( myView.getCenter().x, myView.getCenter().y, 0.f );
    }
This configuration is what worked for a simple 2D view game, where the view travels with my local player in the x,y 2D space, and all sound emitting objects likewise live on the same x,y 2D space. So, when a sound object was set for spatialization the position was set as
    mySound.setRelativeToListener(false);
    mySound.setMinDistance(50.f);
    mySound.setAttenuation(0.1f);
    mySound.setPosition(sPos.x,sPos.y,0.f);
(Individual configurations for minDistance and Attenuation will vary) But, notice two things here: first, the space is simply using z=0, with x & y the same, and second, to make this spatialized, the sound is set to be absolute, not relative (opposite meaning of "relative to listener"). And, following this new understanding, the non-attenuated / non-spatialized sounds needed for this project are defined like this:
    mySound.setPosition(0.f,0.f,0.f);
    mySound.setRelativeToListener(true);
    mySound.setMinDistance(1.f);
    mySound.setAttenuation(1.f);
(while the position, minDistance and Attenuation are irrelevant if not spatialized, I set it this way for tidy-ness)

So, my second point is: This clear example, with a 1 to 1 relationship to the 2D visual space a simple project works in, would be so helpful to have in the documentation, and it would have saved a lot of time. Clearing up the "y=0" idea, as well, would be helpful, as that was not the intuitive way to go.

The results with the above example are as one would expect of a simple 2D audio space. Sounds from the left are heard on the left, etc. Note the direction of the Listener is pointing to negative Z. Up vector is positive Y. And all positions are using the 2D space with a Z of zero.

With all this, I'm hoping the two points are well taken in the spirit of making the documentation better for the next person.
  • All documentation surrounding relativity to listener ("isRelativeToListener", "setRelativeToListener", etc) needs clarification to ensure the reader understands the two states of the sound: absolute means it lives in a spatialized sound space, and the listener position will matter (even if default is origin and if you do nothing to the listener, it will play at full volume in both speakers), while relative actually means the sound will emit from the listener regardless of its position or the sound source position, and will always play at full volume in both speakers.
  • A clear example for a simple 2D spatialized audio setup would be extremely helpful. Translate sound positions to 3D sound space for listener as (x,y,0) and position listener likewise as (x,y,0). Set direction of listener to point toward negative Z. Set up vector for listener to positive Y.
I do hope that helps. And of course, if I've misunderstood any/all this, I think that also helpful to be corrected.

(love SFML btw, thanks!)

2
My experience with shaders is minimal, my experience is SFML is a little more, with C++ a little more than that. Now combining them, and stumped after trying and chasing the issues I can think of. Help / Ideas are appreciated.

This text drawn to the graphics window confirms that shaders are available.
    std::string debugText = "";
    if ( sf::Shader::isAvailable() )
        debugText = "Shaders are available on this system";
    else
        debugText = "No shaders, sorry";

This was my initial attempt, using an external GLSL file, and after drawing a base tile layer, loading subsequent layers (roots, rocks, grass) and drawing them to the render texture called terrainGrassLayer using that shader:
    sf::Shader tileBlend;
    bool shaderLoaded = tileBlend.loadFromFile( "src/TerrainTest.glsl", sf::Shader::Fragment );
        ...
                if ( sf::Shader::isAvailable() && shaderLoaded )
                {
                    // do alpha setting each tile for each terrain layer (potentially blending over texture) with GLSL
                    ...                  
                    terrainGrassLayer.draw( terrainLayer, &tileBlend );
                }
                else
                {
                    // tile blend shader not found, just draw tile with tile center alpha value
                    terrainLayer.setColor( pixelAlpha );
                    terrainGrassLayer.draw( terrainLayer );
                    // in other words, do far less interesting alpha assignment and draw to a render texture
                }
        ...
        // (then in main loop)
        ...
        // draw calls
        rWin.clear();
        rWin.setView( vw );
        rWin.draw( terrainLayerSprite );
        ...

With the above, I can confirm (again) Shaders are available, but that the shader did not load. I can confirm the shader did not load by commenting out the draw( terrainLayer ) line and seeing only a base terrain tile layer (dirt) drawn earlier on. So, only the else block works at this time, and shaderLoaded must be false.

I tried moving the filepath (project directory, cpp source directory, image asset directory in my project), tried re-writing the shader a couple times, including GLSL from SFML examples.

So, I tried loading from memory instead (figuring my GLSL, even the most basic I can make it) isn't right:
    const std::string fragmentShader = \
    "uniform sampler2D tSample;" \
    "uniform float tileAlphaCenter;" \
    "void main()" \
    "{" \
    "    vec4 pixel = texture2d( tSample, gl_TexCoord[0].xy );" \
    "    pixel.a = tileAlphaCenter;" \
    "    gl_FragColor = gl_Color * pixel;" \
    "}";
    bool shaderLoaded = tileBlend.loadFromMemory( fragmentShader, sf::Shader::Fragment );

Still, shaderLoaded is false, and frustratingly, there is no standard error output. But, there should be, if the load didn't work, right? The idea that there is no SFML output, just warnings from the compiler regarding C++11 standards leads me to wonder if I'm looking for SFML errors in the wrong place in CodeBlocks. :\ Like, I say, I'm stumped and up for any ideas. 'Much appreciated.

'Need to see the GLSL file I tried?

uniform sampler2D tSample;
uniform float tileAlphaCenter;

void main()
{
    vec4 pixel = texture2d( tSample, gl_TexCoord[0].xy );
    pixel.a = tileAlphaCenter;
    gl_FragColor = gl_Color * pixel;
}

I'll save the much fancier GLSL file I started with for another time. ;)

Pages: [1]