Announcement

Collapse
No announcement yet.

(39) Rama's Extra Blueprint Nodes for You as a Plugin, No C++ Required!

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • replied
    Ah I see, so the static meshes are converted then merged based on the mesh, and if you change the texture coordinates, it would change ALL the static meshes that you have in the level, of that particular mesh, so if you have 10 static meshes, the plugin searches and finds all meshes of a particular name, then merges those, so you could have potentially hundreds of thousands of meshes merged into the number of beginning meshes you have, 250,000 meshes with 50 basic meshes would be 50 draw calls(plus those other extra draw calls for texture, etc), but that's still way better than rendering that many meshes.

    I wonder if it is possible though? You can change the scale, location, etc in the editor, I wonder if an overlay with an atlas material could be implemented? So you could have the same static mesh, just one draw call, with thousands of texture coordinates in different positions on the atlas material.

    I'm developing a massive, game world wide modular building system, such that modular building pieces can be laid down(foundations, walls, frames, etc), and seen in the distance. The entire game world is built entirely out of modular pieces. You can build a town, city, castle, anything you want anyway you want, and see it in the distance efficiently. Even ruins and underground tunnels are built using the same system.

    I'm using a runtime static mesh merging system for most of the building pieces, they are based on provinces, there are around 30 provinces, each with a different merged static mesh. This static mesh merging works well enough, only problem is when you want to build something, you can't take any triangles away from the merged mesh, so when you enter build mode in a province, there is a simple mesh that is spawned on each control of the modular building system, and these meshes are Victory Plugin instanced meshes, that are all merged together with only as many draw calls as you have unique meshes within the province. When you want to delete a piece, the pieces are separated so that individual instances can be deleted, then merged together again after you're done. When you're finished building the static mesh is spawned again with updated pieces(the previous merged static mesh is merged with the updated pieces).

    Leave a comment:


  • replied
    Rama @Everyone Thank you so much for creating this amazing plugin, and thank you to everyone who contributed to it! Amazing!

    I've been working with these plugins a bit, but I had two questions:

    1. Is it possible to have multiple materials with the instanced static meshes all merged into one?
    2. Would it be possible to manipulate the texture coordinates on different instanced static meshes?

    What I'm going for is a single atlas texture, with one instanced static mesh, copied tens of thousands of times, with different texture coordinates on the different meshes.

    Thank you all again!

    Leave a comment:


  • replied
    Originally posted by apfelbaum View Post

    Yes, I read your posts about .wav and that is my last option. But I don't want to use it right now. The game I am creating is using a radio which loads those audio files at runtime.
    The user gets those files by extracting them elsewhere as .ogg (to overcome copyright problems) with an already existing tool. Having the user extract the files as .ogg is more than enough, not everybody knows how to convert to .wav 16-bit so I would like to keep it as simple as possible and use .ogg for imports as it is also much smaller in size (900mb vs. over 4gb in this case). So if possible I would like to know how to fix this with .ogg :-)

    greetings
    I do believe that it does not matter what FORMAT a sound byte is used as. If the sound byte is copyrighted it does not matter if you convert it to mp3, ogg or WAV or any other format. it is the actual audio that is protected by a copyright not the format. and WAV is supported in the engine for export so I doubt that would be an issue. if the sound bytes are not legal they should not be used at all if you don't have a license to use them in the first place <3

    and also just because a "TOOL" exists does not make it a legal action to use it. like the youtube downloader software. these softwares are Illegal and go against copyrights and youtube policy even though many people use them. This is not a good idea to offer to your game users. you can support WAV and other formats
    for loading sounds but you must have a disclaimer that states using copyrighted sounds is forbidden and can void your user agreement to protect yourself etc.
    I'd talk to a lawyer before releasing the game. TOS can save your butt so be cautious.
    Last edited by frostic; 01-14-2020, 02:59 PM. Reason: added more info

    Leave a comment:


  • replied
    Originally posted by apfelbaum View Post

    Yes, I read your posts about .wav and that is my last option. But I don't want to use it right now. The game I am creating is using a radio which loads those audio files at runtime.
    The user gets those files by extracting them elsewhere as .ogg (to overcome copyright problems) with an already existing tool. Having the user extract the files as .ogg is more than enough, not everybody knows how to convert to .wav 16-bit so I would like to keep it as simple as possible and use .ogg for imports as it is also much smaller in size (900mb vs. over 4gb in this case). So if possible I would like to know how to fix this with .ogg :-)

    greetings
    Apparently 4.24 needs decompressed sample data.

    apfelbaum If you really need to work with .ogg files, you can use this modified version of the Victory function:

    Code:
    USoundWave* UBP_FunctionLibrary::GetSoundWaveFromOGGFile(const FString& filePath, bool& Success)
    {
        if (filePath == "") { Success = false; return nullptr; }
    
        char* filePathChar = TCHAR_TO_ANSI(*filePath);
    
        USoundWave* sw = NewObject<USoundWave>(USoundWave::StaticClass());
        if (!sw) { Success = false; return nullptr; }
    
        TArray < uint8 > rawFile1;
    
        FFileHelper::LoadFileToArray(rawFile1, filePath.GetCharArray().GetData());
    
        FByteBulkData* bulkData = &sw->CompressedFormatData.GetFormat(TEXT("OGG"));
    
        bulkData->Lock(LOCK_READ_WRITE);
        FMemory::Memcpy(bulkData->Realloc(rawFile1.Num()), rawFile1.GetData(), rawFile1.Num());
        bulkData->Unlock();
    
        FSoundQualityInfo info;
        FVorbisAudioInfo vorbis_obj;
    
        if (!vorbis_obj.ReadCompressedInfo(rawFile1.GetData(), rawFile1.Num(), &info))
        {
            //Debug("Can't load header");
            return nullptr;
        }
        else
        {
            sw->SoundGroup = ESoundGroup::SOUNDGROUP_Default;
            sw->NumChannels = info.NumChannels;
            sw->Duration = info.Duration;
            sw->RawPCMDataSize = info.SampleDataSize;
            sw->SetSampleRate(info.SampleRate);
    
            // - Decompress and bake PCM Data from file into SoundWave
            sw->RawPCMData = (uint8*)FMemory::Malloc(sw->RawPCMDataSize);
            vorbis_obj.ExpandFile(sw->RawPCMData, &info);
    
        }
    
        if (!sw) { Success = false; return nullptr; }
    
        Success = true;
        return sw;
    }
    This part will ensure that it works in 4.24 in editor as well as in packaged game:
    Code:
            sw->RawPCMData = (uint8*)FMemory::Malloc(sw->RawPCMDataSize);
            vorbis_obj.ExpandFile(sw->RawPCMData, &info);
    It's a bit slower than original Victory function since it needs to "Expand" the file.

    Make sure to include VorbisAudioInfo.h to your BP_FunctionLibrary.cs
    Code:
    #include "Runtime/Engine/Public/VorbisAudioInfo.h"
    And add "Vorbis" to your project's .Build.cs:

    Click image for larger version  Name:	Annotation-20200113-124610.png Views:	0 Size:	14.4 KB ID:	1707889
    Last edited by Jaytheway; 01-13-2020, 08:03 AM.

    Leave a comment:


  • replied
    Originally posted by frostic View Post

    see my last few posts. JayTheWay helped me with loading WAV files. you can use that code to load wav files. tbh it is a more common format for windows users
    Yes, I read your posts about .wav and that is my last option. But I don't want to use it right now. The game I am creating is using a radio which loads those audio files at runtime.
    The user gets those files by extracting them elsewhere as .ogg (to overcome copyright problems) with an already existing tool. Having the user extract the files as .ogg is more than enough, not everybody knows how to convert to .wav 16-bit so I would like to keep it as simple as possible and use .ogg for imports as it is also much smaller in size (900mb vs. over 4gb in this case). So if possible I would like to know how to fix this with .ogg :-)

    greetings

    Leave a comment:


  • replied
    Originally posted by apfelbaum View Post
    Great plugin, has many really really useful functionalities.
    There is (at least) one problem with the 'GetSoundWaveFromFile' node. The file gets somehow loaded, I checked with 'is valid' and also printed the loaded sound wave with a 'GetDisplayName'. But as soon I try to play the sound file the following error message occurs.

    LogAudioDerivedData: Warning: Can't cook SoundWave /Script/Engine.SoundWave:SoundWave_0 because there is no source compressed or uncompressed PC sound data

    I downloaded Plugin for 4.24 and that is also the engine version I use. I also use .ogg files. I don't know wether special conditions for the.ogg files exist, I tried a few things
    (different sample rate/bitrate) and never succeeded.
    I also don't run any plugins besides Victory nor modified the engine. The engine is a clean and fresh install.

    best regards
    see my last few posts. JayTheWay helped me with loading WAV files. you can use that code to load wav files. tbh it is a more common format for windows users

    Leave a comment:


  • replied
    Great plugin, has many really really useful functionalities.
    There is (at least) one problem with the 'GetSoundWaveFromFile' node. The file gets somehow loaded, I checked with 'is valid' and also printed the loaded sound wave with a 'GetDisplayName'. But as soon I try to play the sound file the following error message occurs.

    LogAudioDerivedData: Warning: Can't cook SoundWave /Script/Engine.SoundWave:SoundWave_0 because there is no source compressed or uncompressed PC sound data

    I downloaded Plugin for 4.24 and that is also the engine version I use. I also use .ogg files. I don't know wether special conditions for the.ogg files exist, I tried a few things
    (different sample rate/bitrate) and never succeeded.
    I also don't run any plugins besides Victory nor modified the engine. The engine is a clean and fresh install.

    best regards

    Leave a comment:


  • replied
    Originally posted by saga revolver View Post
    Hi, we are trying to compile in 4.24 without success. We are getting this error:

    Code:
    Severity Code Description Project File Line Suppression State
    Error LNK2001 unresolved external symbol "__declspec(dllimport) struct FThreadSafeStaticStat<struct FStat_STAT_PhysSceneWriteLock> StatPtr_STAT_PhysSceneWriteLock" (__imp_?StatPtr_STAT_PhysSceneWriteLock@@3U?$FThreadSafeStaticStat@UFStat_STAT_PhysSceneWriteLock@@@@A) Wardens D:\Revolver\Wardens\Intermediate\ProjectFiles\Module.VictoryBPLibrary.cpp.obj 1
    If someone was able to compile, please give us help.
    Thank you.
    Modify VictoryBPLibrary.Build.cs

    Add "ApexDestruction" to PublicDependencyModuleNames
    Add "APEX" to PrivateDependencyModuleNames

    Code:
    // Some copyright should be here...
    
    using UnrealBuildTool;
    
    public class VictoryBPLibrary : ModuleRules
    {
        public VictoryBPLibrary(ReadOnlyTargetRules Target) : base(Target)
        { 
            PrivatePCHHeaderFile = "Private/VictoryBPLibraryPrivatePCH.h";
    
            //4.15 Include What You Use
            bEnforceIWYU = false;
    
            PublicIncludePaths.AddRange(
                new string[] {
                    "VictoryBPLibrary/Public"
    
                    // ... add public include paths required here ...
                }
                );
    
    
            PrivateIncludePaths.AddRange(
                new string[] {
                    "VictoryBPLibrary/Private",
    
                    // ... add other private include paths required here ...
                }
                );
    
    
            PublicDependencyModuleNames.AddRange(
                new string[]
                {
                    "Core",
                    "ApexDestruction"
    
                    // ... add other public dependencies that you statically link with here ...
                }
                );
    
    
            PrivateDependencyModuleNames.AddRange(
                new string[]
                {
                    "CoreUObject", 
                    "Engine", 
                    "InputCore",
    
                    "RHI",
                    "RenderCore",
    
                    "HTTP",
                    "UMG", "Slate", "SlateCore",
    
                    "ImageWrapper",
    
                    "PhysicsCore", 
                    "PhysX", 
    
                    "HeadMountedDisplay",
    
                    "AIModule",
    
                    "NavigationSystem",
    
                    "Vorbis",
    
                    //FPlatformApplicationMisc
                    "ApplicationCore",
                    "APEX"
                }
                );
    
            //APEX EXCLUSIONS
            /*
            if (Target.Platform != UnrealTargetPlatform.Android && Target.Platform != UnrealTargetPlatform.IOS)
            {
                PrivateDependencyModuleNames.AddRange(
                new string[]
                {
                    "APEX"
                }
                );
    
                PublicDependencyModuleNames.AddRange(
                new string[]
                {
                    "ApexDestruction"
                }
                );
    
            }
            */
    
            DynamicallyLoadedModuleNames.AddRange(
                new string[]
                {
                    // ... add any modules that your module loads dynamically here ...
                }
                );
        }
    }

    Leave a comment:


  • replied
    Originally posted by Jaytheway View Post
    frostic The issue was that SoundWave never got RawPCMData baked into it, which is apparently what it needs in packaged builds. Here's fixed GetSoundWaveFromWaveFile function:
    You are awesome thank you!

    Leave a comment:


  • replied
    frostic The issue was that SoundWave never got RawPCMData baked into it, which is apparently what it needs in packaged builds. Here's fixed GetSoundWaveFromWaveFile function:

    Code:
    class USoundWave* UMyBPFunctionLibrary::GetSoundWaveFromWaveFile(const FString& filePath, bool& Success)
    {
        if (filePath == "") { Success = false; return nullptr; }
    
        USoundWave* sw = NewObject<USoundWave>(USoundWave::StaticClass());
        if (!sw) { Success = false; return nullptr; }
    
        TArray < uint8 > rawFile;
    
        FFileHelper::LoadFileToArray(rawFile, filePath.GetCharArray().GetData());
        FWaveModInfo WaveInfo;
    
        if (WaveInfo.ReadWaveInfo(rawFile.GetData(), rawFile.Num()))
        {
    
            // - catching not supported bit depth
            if (*WaveInfo.pBitsPerSample != 16) { Success = false;  return nullptr; }
    
            sw->InvalidateCompressedData();
    
            sw->RawData.Lock(LOCK_READ_WRITE);
            void* LockedData = sw->RawData.Realloc(rawFile.Num());
            FMemory::Memcpy(LockedData, rawFile.GetData(), rawFile.Num());
            sw->RawData.Unlock();
    
            int32 DurationDiv = *WaveInfo.pChannels * *WaveInfo.pBitsPerSample * *WaveInfo.pSamplesPerSec;
            if (DurationDiv)
            {
                sw->Duration = *WaveInfo.pWaveDataSize * 8.0f / DurationDiv;
            }
            else
            {
                sw->Duration = 0.0f;
            }
            sw->SetSampleRate(*WaveInfo.pSamplesPerSec);
            sw->NumChannels = *WaveInfo.pChannels;
            sw->RawPCMDataSize = WaveInfo.SampleDataSize;
            sw->SoundGroup = ESoundGroup::SOUNDGROUP_Default;
    
        }
        else {
            Success = false;
            return nullptr;
        }
    
        // - Baking PCM Data from file into SoundWave memory
        const int32 NumSamples = sw->RawPCMDataSize / sizeof(Audio::DefaultUSoundWaveSampleType);
    
        sw->RawPCMData = (uint8*)FMemory::Malloc(sw->RawPCMDataSize);
        FMemory::Memcpy(sw->RawPCMData, WaveInfo.SampleDataStart, NumSamples * sizeof(Audio::DefaultUSoundWaveSampleType));
    
        if (!sw) { Success = false; return nullptr; }
    
        Success = true;
        return sw;
    }
    Header:
    Code:
    UFUNCTION(BlueprintCallable, Category = "JP - Nodes", meta = (DisplayName = "Get Sound Wave from Wave file", Keywords = "Get Sound Wave from Wave file"))
    static class USoundWave* GetSoundWaveFromWaveFile(const FString& filePath, bool& Success);
    "Success" bool returns false if:
    - file path is invalid
    - failed to create SoundWave
    - input wave file has unsupported bit depth (other than 16)
    Last edited by Jaytheway; 01-04-2020, 02:31 PM.

    Leave a comment:


  • replied
    Jaytheway I sent you a private message. I'm having an issue with the code not working after build/compile

    Leave a comment:


  • replied
    frostic While you're at it, you might want to expose some properties of sound wave to blueprints. Stuff that you can usually edit in details panel of the asset:

    Click image for larger version

Name:	details.png
Views:	140
Size:	76.1 KB
ID:	1703541

    You can find it all here: https://docs.unrealengine.com/en-US/...ave/index.html

    But first check if it's not already available:
    Click image for larger version

Name:	properties.png
Views:	124
Size:	24.0 KB
ID:	1703542

    Leave a comment:


  • replied
    I'm an idiot, don't mind me.......

    your code converts it from the path/filestring into a uSound and that
    can be played in "play sound at location" instead of the "play sound at location from file" accepts a PATH and yours converts the PATH to an audio file like if i import the wav into my project. Jaytheway YOU SIR ARE AWESOME!
    Last edited by frostic; 01-01-2020, 06:32 PM.

    Leave a comment:


  • replied
    frostic Have you tried compiling just GetSoundFromWaveFile function? It might be easier to just get a sound wave from this function and then do your playback at location from blueprints.
    fyi, your error picture is too small to read what's going on.

    Leave a comment:


  • replied
    Originally posted by Jaytheway View Post

    Take a look at this playlist: https://www.youtube.com/watch?v=u1JC...QEyURMThnQYKQD
    First 2-3 videos should be enough to understand what you need to do here.

    Basically you need to create a simple BP function in your C++ BP function library. In the header file you'd declare function like this:
    Code:
     UFUNCTION(BlueprintCallable, Category = "My - functions", meta = (DisplayName = "Get Sound Wave from Wave file", Keywords = "Get Sound Wave from Wave file"))
    static USoundWave* GetSoundWaveFromWaveFile(const FString& filePath);
    And in .cpp file you'd create a definition for the function - code form my previous message.
    here is what I came up with but It wont compile. I don't know what I did wrong. This is the first time I ever added any c++
    to my game and I'm failing LOL.

    In AudioFunctions.cpp i added this code:

    Code:
    #include "AudioFunctions.h"
    #include "Sound/SoundWave.h"
    #include "Misc/FileHelper.h"
    #include "Kismet/GameplayStatics.h"
    
    void UAudioFunctions::PlaySoundAtLocationFromWAV(UObject* WorldContextObject, const FString& FilePath, FVector Location, float VolumeMultiplier, float PitchMultiplier, float StartTime, class USoundAttenuation* AttenuationSettings)
    {
        USoundWave* sw = GetSoundFromWaveFile(FilePath);
    
        if (!sw)
            return;
    
        UGameplayStatics::PlaySoundAtLocation(WorldContextObject, sw, Location, VolumeMultiplier, PitchMultiplier, StartTime, AttenuationSettings);
    }
    
    class USoundWave* UAudioFunctions::GetSoundFromWaveFile(const FString& filePath)
    {
        USoundWave* sw = NewObject<USoundWave>(USoundWave::StaticClass());
    
        if (!sw)
            return nullptr;
    
        TArray < uint8 > rawFile;
    
        FFileHelper::LoadFileToArray(rawFile, filePath.GetCharArray().GetData());
        FWaveModInfo WaveInfo;
    
        if (WaveInfo.ReadWaveInfo(rawFile.GetData(), rawFile.Num()))
        {
            sw->InvalidateCompressedData();
    
            sw->RawData.Lock(LOCK_READ_WRITE);
            void* LockedData = sw->RawData.Realloc(rawFile.Num());
            FMemory::Memcpy(LockedData, rawFile.GetData(), rawFile.Num());
            sw->RawData.Unlock();
    
            int32 DurationDiv = *WaveInfo.pChannels * *WaveInfo.pBitsPerSample * *WaveInfo.pSamplesPerSec;
            if (DurationDiv)
            {
                sw->Duration = *WaveInfo.pWaveDataSize * 8.0f / DurationDiv;
            }
            else
            {
                sw->Duration = 0.0f;
            }
            sw->SetSampleRate(*WaveInfo.pSamplesPerSec);
            sw->NumChannels = *WaveInfo.pChannels;
            sw->RawPCMDataSize = WaveInfo.SampleDataSize;
            sw->SoundGroup = ESoundGroup::SOUNDGROUP_Default;
        }
        else {
            return nullptr;
        }
    
        return sw;
    }

    And in my AudioFunctions.h i put this:

    Code:
    // Fill out your copyright notice in the Description page of Project Settings.
    
    #pragma once
    
    #include "CoreMinimal.h"
    #include "Kismet/BlueprintFunctionLibrary.h"
    #include "AudioFunctions.generated.h"
    
    /**
     *
     */
    UCLASS()
    class StyxVR_API UAudioFunctions : public UBlueprintFunctionLibrary
    {
        GENERATED_BODY()
    
        //* Declare blueprint functions here?
        UFUNCTION(BlueprintCallable, Category = "AudioFunctions", meta = (DisplayName = "Get Sound from Wave file", Keywords = "Get Sound from Wave file"))
        static USoundWave* GetSoundFromWaveFile(const FString& filePath);
    
        UFUNCTION(BlueprintCallable, Category = "AudioFunctions", meta = (DisplayName = "Play Sound from Wave file", Keywords = "Play Sound from Wave file"))
        static USoundWave* PlaySoundAtLocationFromWAV(UObject* WorldContextObject, const FString& FilePath, FVector Location, float VolumeMultiplier, float PitchMultiplier, float StartTime, class USoundAttenuation* AttenuationSettings);
    
    };

    I seem to have some error



    Click image for larger version  Name:	Screenshot_1.png Views:	0 Size:	12.6 KB ID:	1703353
    Last edited by frostic; 01-01-2020, 07:26 AM.

    Leave a comment:

Working...
X