This page has been translated automatically.
Основы UNIGINE
1. Введение
2. Виртуальные миры и работа с ними
3. Подготовка 3D моделей
4. Материалы
5. Камеры и освещение
7. Создание кат-сцен и запись видео
8. Подготовка проекта к релизу
9. Физика
10. Основы оптимизации
11. ПРОЕКТ2: Шутер от первого лица
12. ПРОЕКТ3: Аркадная гонка по пересеченной местности от 3-го лица
13. ПРОЕКТ4: VR приложение с простым взаимодействием

Проигрывание звука

In addition to the visuals, sound is an important component of real-time solutions. It is sound that creates the feeling of immersion in the virtual world. A rumbling echo that makes you think the action is taking place in a spacious building, the soft tapping of footsteps on a stone floor or a car speeding past — all this can be simulated. UNIGINE provides a multi-channel sound system with stereo sound support based on HRTF (sound perception modeling function), various 3D effects, obstruction, and multiple sound reverberation. You can play sound in MP3, WAV, or OGA format when objects are in contact to simulate their physical properties at the sound level. For moving objects, the Doppler effect is simulated.Помимо визуальной составляющей, важным компонентом технологий реального времени является звук. Именно звук создает ощущение погружения в виртуальный мир. Раскатистое эхо, которое заставляет думать, что действие происходит в просторном здании, мягкий перестук шагов по каменному полу или промчавшийся мимо автомобиль — все это можно смоделировать. UNIGINE предоставляет систему многоканального звука с поддержкой стереозвука на основе функции HRTF (функции моделирования восприятия звука), различных 3D эффектов, преграждения и множественной реверберации звука. Можно проигрывать звук в формате MP3, WAV или OGA при контакте объектов для имитации их физических свойств на уровне звука. Для движущихся объектов моделируется эффект Допплера.

UNIGINE has two types of sound sources: В UNIGINE есть два типа источников звука:

  • Sound Source — used to create directional sound sources.Sound Source – используется для создания направленных источников звука.
  • Ambient Source — used for playing background music and sounds that can be heard throughout the scene.Ambient Source – для воспроизведения фоновых музыки и звуков, которые слышны повсюду в сцене.

A directional sound source can be added to a scene either in the Editor or via code. To add it via code, all you need to do is create an instance of the SoundSource class and specify all the necessary settings. Sound playback can be turned on and off using the play() and stop() methods.Направленный источник звука можно добавить в сцену как в Редакторе, так и через код. В последнем случае, достаточно создать экземпляр класса SoundSource и указать все необходимые настройки. Воспроизведение звука можно включать и выключать при помощи методов play() и stop().

Исходный код (C++)
// создаем новый источник звука, используя указанный аудиофайл
SoundSourcePtr sound = SoundSource::create("sound.mp3");

// отключаем заглушение звука преградами
sound->setOcclusion(0);
// устанавливаем дистанцию, начиная с которой звук становится чистым
sound->setMinDistance(10.0f);
// устанавливаем дистанцию, начиная с которой звук перестает быть слышимым
sound->setMaxDistance(100.0f);
// устанавливаем коэффициент усиления звука
sound->setGain(0.5f);
// включаем циклическое воспроизведение звука
sound->setLoop(1);
// включаем воспроизведение звука 
sound->play();

The sound played depends on the relative position of the sound sources and the listener. The sound is linearly attenuated within the specified range (MinDistance and MaxDistance). If inner and outer sound cones are set, they will also contribute to the attenuation factor (ConeInnerAngle and ConeOuterAngle). In addition, various objects in the scene can also block the propagation of sound from SoundSource (you can even set different sound absorption coefficients for different surfaces). The number of such sound sources is unlimited, as only those within hearing range are played.Проигрываемый звук зависит от взаимного расположения источников звука и слушателя. Звук линейно затухает в указанном диапазоне (MinDistance и MaxDistance). Если определены внутренний и внешний звуковые конусы, они также будут вносить свою лепту в коэффициент затухания (ConeInnerAngle и ConeOuterAngle). Кроме того, различные объекты в сцене также могут преграждать распространение звука от источников SoundSource (можно даже задавать коэффициент поглощения звука для различных поверхностей). Количество таких источников звука неограничено, поскольку проигрываются только те, что находятся в пределах слышимости.



To play background music and sounds that should be heard everywhere, you need to create an instance of the AmbientSource class (such sources can only be created via API). When creating it, the necessary parameters are also specified.Для воспроизведения фоновой музыки и звуков, которые должны быть слышны везде нужно создать экземпляр класса AmbientSource (такие источники можно создавать только через API). При создании также указываются необходимые параметры.

Примечание
For an ambient source to be played, a Player is always required. In case an ambient source needs to be played when neither a world, nor the Editor are loaded, a Player, as well as the sound source should be created in the SystemLogic::init() method; otherwise, no sound will be heard.Для воспроизведения звука от источника Ambient Source всегда требуется персонаж (Player). В случае, если необходимо воспроизвести такой звук, когда ни мир, ни Редактор не загружены, необходимо создать Player, а также сам источник звука в методе SystemLogic::init(); в противном случае звука не будет слышно.
Исходный код (C++)
// создаем персонаж (player), чтобы звук Ambient Source был слышен
PlayerSpectatorPtr player = PlayerSpectator::create();
player->setPosition(Vec3(0.0f, -3.401f, 1.5f));
player->setViewDirection(vec3(0.0f, 1.0f, -0.4f));
Game::setPlayer(player);

// создаем источник звука AmbientSource
AmbientSourcePtr sound = AmbientSource::create("sound.mp3");

// устанавливаем необходимые параметры звука
sound->setGain(0.5f);
sound->setPitch(1.0f);
sound->setLoop(1);

// включаем воспроизведение звука
sound->play();

Sound is processed in a separate thread at 30 frames per second, so changes are not applied instantly. In some cases, such as after stopping playback before changing track, it is necessary to force update the audio stream to avoid application errors.Звук обрабатывается в отдельном потоке с частотой 30 кадров в секунду, поэтому изменения не применяются мгновенно. В ряде случаев, как например после остановки воспроизведения перед сменой трека, нужно форсированно обновить звуковой поток, чтобы избежать ошибок в работе приложения.

Practice
Практика#

To create an atmosphere in our application, let's add the StereoSystem component to play music tracks using AmbientSource.В нашем приложении для создания атмосферы добавим компонент StereoSystem для проигрывания музыкальных треков при помощи источника AmbientSource.

The component controls the stereo system in the room (switches it on and off, changes tracks).Компонент управления стереосистемой в комнате (вкл,выкл, сменить трек).

StereoSystem.h
#pragma once
#include <UnigineComponentSystem.h>
#include <UnigineSounds.h>
#include <UnigineVisualizer.h>
#include "Interactable.h"
class StereoSystem :
    public Interactable
{
	// Объявляем конструктор и деструктор для нашего класса, а также задаем имя связанного с компонентом свойства (property). 
	// Файл StereoSystem.prop со всеми описанными ниже параметрами будет сгенерирован Компонентной системой в папке 'data' вашего проекта при первом запуске приложения
	COMPONENT_DEFINE(StereoSystem, Interactable);
	// список треков для воспроизведения
	PROP_ARRAY(File, sound_tracks);
	//регистрация методов, которые будут вызываться на соответствующих этапах жизненного цикла приложения (сами методы объявляются в protected-блоке ниже)
	COMPONENT_INIT(init);
	// перегрузка метода Action для дочернего компонента
	void action(int num = 0);
protected:
	// объявление методов, которые будут вызываться на соответствующих этапах жизненного цикла приложения
	void init();

private:
	// номер текущего трека
	int current_track = 0;
	// источник звука AmbientSource
	Unigine::AmbientSourcePtr track_player = nullptr;
};
StereoSystem.cpp
#include "StereoSystem.h"
// Регистрация компонента StereoSystem
REGISTER_COMPONENT(StereoSystem);
using namespace Unigine;
using namespace Math;

void StereoSystem::init()
{
	// задаем текст подсказки, которая будет отображаться при наведении курсора на объект
	tooltip = "По правому щелчку мыши циклически переключает звуковые дорожки по списку.";

	// инициализируем первый трек, если список не пуст
	if (sound_tracks.size() > 0)
		track_player = AmbientSource::create(Unigine::FileSystem::guidToPath(FileSystem::getGUID(sound_tracks[current_track].getRaw())));
	track_player->stop();
}

// перегрузка метода Action для дочернего компонента
void StereoSystem::action(int num)
{
	// индексы действий отличные от нуля для данного компонента невалидны, поэтому игнорируются
	if (num != 0)
		return;
	// если список воспроизведения пуст, ничего не делаем
	if (sound_tracks.size() < 1)
		return;

	// при необходимости отключаем воспроизведение предыдущего трека перед переключением
	if (!track_player->isStopped()) {
		track_player->stop();
	}

	// после остановки воспроизведения перед сменой трека нужно форсированно обновить звуковой поток
	Sound::renderWorld(1);

	// меняем трек на элемент списка аудиофайлов с индексом
	track_player->setSampleName(Unigine::FileSystem::guidToPath(FileSystem::getGUID(sound_tracks[current_track].getRaw())));

	// отображаем информацию о текущем треке
	Visualizer::renderMessage2D(vec3(0.0f, (float)(WindowManager::getMainWindow()->getClientSize().y - 40) / WindowManager::getMainWindow()->getClientSize().y, 0.0f),
		vec3(1.0f, 0.1f, 0.0f),
		String::format(" > Воспроизведение дорожки №%d: %s", current_track + 1, sound_tracks[current_track].get()),
		Math::vec4_red, 1, 18, 1);
	track_player->setTime(0.0f);
	track_player->play();

	// увеличиваем индекс текущего трека (если он превышает число треков, устанавливаем его в 0)
	current_track++;
	if (current_track >= sound_tracks.size())
		current_track = 0;
}

Let's save our files and then build and run our application by hitting Ctrl + F5 to make the Component System generate a property to be used to assign our component to nodes. Close the application after running it and switch to UnigineEditor.Сохраним файлы, а затем соберем и запустим приложение нажав Ctrl + F5, чтобы Компонентная система сгенерировала property для связи компонента с нодой. После запуска приложения закроем его и вернемся в UnigineEditor.

Assign the StereoSystem component to the tv1 node in the scene (interior -> tv1) and add tracks from the archviz/sounds folder to the Sound Tracks list:Назначьте компонент StereoSystem на ноду tv1 в сцене (interior -> tv1) и добавьте треки из папки archviz/sounds в список Sound Tracks:

Let's also add a few lines to the Fan component to play the fan sound. The important point here is that the Fan component is assigned to the fan_rotator node controlled by Toggle, so if the component disables the fan_rotator node, the logic of the Fan component assigned to it will not be executed and the sound will not be turned off. We need to make that part of the Fan component code (namely the updateSound() method) work even if the node is disabled and be executed every frame.Также давайте добавим несколько строк в компонент Fan для проигрывания звука вентилятора. Важный момент здесь в том, что компонент Fan назначен на ноду fan_rotator, управляемую выключателем (Toggle), при отключении компонентом ноды fan_rotator, перестанет выполняться логика назначенного на нее компонента Fan и звук просто не выключится. Нам нужно, чтобы часть кода компонента Fan (а именно метод UpdateSound) работала и тогда, когда нода отключена и выполнялась каждый кадр

So, that's how we declare the updateSound method (passing execution order and invoke_disabled flag as second and third arguments):Итак, объявляем метод updateSound следующим образом (передаем порядок выполнения и флаг invoke_disabled в качестве второго и третьего аргумента соответственно):

Исходный код (C++)
COMPONENT_UPDATE(updateSound, 0 /*execution order*/, 1 /*invoke_disabled*/)

As a result, we have the following code and everything should work out well:В итоге получаем следующий код и все должно работать как надо:

Fan.h
#pragma once
#include <UnigineComponentSystem.h>
class Fan :
	public Unigine::ComponentBase
{
public:
	// Объявляем конструктор и деструктор для нашего класса, а также задаем имя связанного с компонентом свойства (property). 
	// Файл Fan.prop со всеми описанными ниже параметрами будет сгенерирован Компонентной системой в папке 'data' вашего проекта при первом запуске приложения
	COMPONENT_DEFINE(Fan, ComponentBase);

	// объявляем параметры компонента и задаем начальные значения
	PROP_PARAM(Node, fan_node, nullptr);			// нода пропеллера, которую будем вращать
	PROP_PARAM(Float, speed, 720.0f);			// скорость вращения

	// регистрация методов, которые будут вызываться на соответствующих этапах жизненного цикла приложения (сами методы объявляются в protected-блоке ниже)
	COMPONENT_INIT(init);
	COMPONENT_UPDATE(update);
${#HL}$
	// обеспечиваем выполнение метода updateSound даже если компонент отключен вместе с нодой
	COMPONENT_UPDATE(updateSound, 0 /*order*/, 1 /*invoke_disabled*/); ${HL#}$

protected:
	// объявление методов, которые будут вызываться на соответствующих этапах жизненного цикла приложения
	void init();
	void update();
${#HL}$
	void updateSound();
private:
	// источник звука
	Unigine::SoundSourcePtr sound = nullptr;
	// звук вентилятора
	Unigine::String soundFile ="archviz/sounds/fan_sound.mp3"; ${HL#}$
};
Fan.cpp
#include "Fan.h"
#include <UnigineGame.h>
// Регистрация компонента Fan
REGISTER_COMPONENT(Fan);

// включаем нужные пространства имен
using namespace Unigine;
using namespace Math;

// метод update компонента, вызываемый каждый кадр 
void Fan::update()
{
	// если не назначена нода лопастей, ничего не делаем
	if (!fan_node)
		return;
	// поворачиваем ноду с заданной скоростью
	fan_node->rotate(0, speed * Game::getIFps() , 0);
}
${#HL}$
// метод init компонента, вызываемый на этапе инициализации
void Fan::init()
{
	// создаем новый источник звука, используя указанный аудиофайл
	sound = SoundSource::create(Unigine::FileSystem::guidToPath(FileSystem::getGUID(soundFile.get())));

	// отключаем заглушение звука преградами
	sound->setOcclusion(0);
	// устанавливаем дистанцию, начиная с которой звук становится чистым
	sound->setMinDistance(1.0f);
	// устанавливаем дистанцию, начиная с которой звук перестает быть слышимым
	sound->setMaxDistance(4.0f);
	// устанавливаем коэффициент усиления звука
	sound->setGain(0.5f);
	// включаем циклическое воспроизведение звука
	sound->setLoop(1);
	// помещаем источник звука в положение вентилятора
	sound->setWorldTransform(fan_node->getWorldTransform());
}

// метод updateSound компонента, вызываемый каждый кадр
void Fan::updateSound()
{
	// если компмонент отключен и звук воспроизводится, отключаем восмпроизведение
	if (!isEnabled() && sound->isPlaying()) {
		sound->stop();
		return;
	}
	// если компмонент включен и звук не воспроизводится, включаем восмпроизведение
	if (isEnabled() && !sound->isPlaying())
		sound->play();
}
 ${HL#}$

Let's save our files and then build and run our application by hitting Ctrl + F5 to make the Component System regenerate the Fan property. Close the application after running it, switch to SDK Browser and launch our application by clicking the Run button on our project's card.Сохраним файлы, а затем соберем и запустим приложение нажав Ctrl + F5, чтобы Компонентная система перегенерировала свойство Fan. После запуска приложения закроем его, Переключимся в SDK Browser и запустим наше приложение, нажав кнопку Run на карточке проекта.

As a result, we have created an interactive room while getting acquainted with the UNIGINE component system and the essential aspects of working with various scene components from the code. This room allows us to arrange and remove objects, interact with them, modify their appearance, and play sounds.В итоге, в ходе знакомства с компонентной системой UNIGINE и основными аспектами работы с различными составляющими сцены из кода, у нас получилась интерактивная комната, в которой можно расставлять и удалять объекты, взаимодействовать с ними, изменять их внешний вид, воспроизводить звуки.

Последнее обновление: 06.11.2024
Build: ()