Creating a Script to make 3D Extrusion in a Text

editeiro wrote on 7/24/2024, 10:41 AM

Hello Everyone,
Following the advances in working with 3D layer PSDs in Vegas, which @zzzzzz9125 helped create here: https://www.vegascreativesoftware.info/us/forum/psd-layer-splitter-script--145259/

I was wondering if it would be possible to create a 1-click script to make a 3D text extrusion.

I often do this in my work, but it really takes a lot of time and is a mechanical and predictable process, with exact values regardless of the aspect ratio or project resolution.

Here is an example of how I do it:

Steps to create 3D text extrusion in Vegas Pro:

1. Create a text.
2. Duplicate the track.
3. Make this duplicate a subclip.
4. Add the Sepia effect to the Media FX of the subclip, choose the color and bring the "Blending Strength" to the maximum.
5. Change the composite modes to "3D Source Alpha".
6. Change the Parent Comp Mode to "3D Source Alpha".
7. In track 2, add +10 to the Z-position in Track Motion.
8. Duplicate the track and add +10 (=20) to the Z-position in Track Motion.
9. Continue duplicating the tracks and adding +10 to the Z-position until you reach 100.

By doing this, I create a 3D text extrusion, and with the Sepia effect in the Media FX of the subclip, I can change the border color.

to organize the timeline:
10. Group the events.
11. Select all the tracks, group them.
12. DragOff the Parent Track of the group.
13. Collapse only the group with the extrusion tracks.

Finally, the timeline stays clean, I have better visibility, and I can change the Parent Motion and access the main text event to alter the font, size, and color.

This works great for 3D Flat Design, Fake3D, Isometric Design, and others.

Question:
Is it possible to automate this process in a 1-click script?

I don't know enough programming to develop this, but I would greatly appreciate it if anyone could help.

Comments

m3lquixd wrote on 7/24/2024, 11:56 AM

UP!

About me:
Hi! Melqui Calheiros Here. I've been using Vegas as my only video editor for over 10 years. I edit professionally for various influencers, public bodies and small businesses. My goal is to squeeze Vegas to the fullest! And end the prejudice that software has here in Brazil.

⬇️ Some of my jobs. ⬇️
https://www.vegascreativesoftware.info/us/forum/post-your-vegas-creations--109464/?page=37#ca872169

PC Specs:
Operating System:
    Windows 11 Pro 64-bit
CPU:
    AMD Ryzen 7 5700G 3.80 GHz
RAM:
    32,0GB Dual-Channel DDR4 3200MHz
Motherboard:
    ASRock B450M Steel Legend (AM4)
Graphics:
    MSI RTX 4060 Ventus 2X Black OC 8GB
Storage:
    476GB ADATA SU650 (SATA (SSD))
    931GB KINGSTON SNV2S1000G (SATA-2 (SSD))

zzzzzz9125 wrote on 7/24/2024, 8:48 PM

A possible version that works, but may not what op wants:

using System.Collections.Generic;

using ScriptPortal.Vegas;  // "ScriptPortal.Vegas" for Magix Vegas Pro 14 or above, "Sony.Vegas" for Sony Vegas Pro 13 or below

namespace Test_Script
{

    public class Class
    {
        public Vegas myVegas;
        public const string TEXTPLUGINGUID = "{0FE8789D-0C47-442A-AFB0-0DAF97669317}";
        // Optional Choices:  Titles & Text: "{Svfx:com.vegascreativesoftware:titlesandtext}" // for VP 17 and later
        //                    Titles & Text: "{Svfx:com.sonycreativesoftware:titlesandtext}"  // for VP 16 and earlier
        //                    (Legacy) Text: "{0FE8789D-0C47-442A-AFB0-0DAF97669317}"
        //                   ProType Titler: "{53FC0B44-BD58-4716-A90F-3EB43168DE81}"

        public const int LAYERSCOUNT = 10;

        public void Main(Vegas vegas)
        {
            myVegas = vegas;
            myVegas.ResumePlaybackOnScriptExit = true;
            Project project = myVegas.Project;
            PlugInNode pluginText = myVegas.Generators.GetChildByUniqueID(TEXTPLUGINGUID);
            PlugInNode pluginColor = myVegas.VideoFX.GetChildByUniqueID("{Svfx:com.vegascreativesoftware:sepia}") ?? myVegas.VideoFX.GetChildByUniqueID("{Svfx:com.sonycreativesoftware:sepia}");
            if (pluginText == null || pluginColor == null)
            {
                myVegas.ShowError("Plugin Not Found!");
                return;
            }

            List<VideoTrack> vTracks = new List<VideoTrack>();
            foreach (Track myTrack in project.Tracks)
            {
                if (myTrack.IsVideo() && myTrack.Selected)
                {
                   vTracks.Add((VideoTrack)myTrack);
                   myTrack.Selected = false;
                }
            }
            if (vTracks.Count == 0)
            {
                VideoTrack newTrack = new VideoTrack(project, 0, null);
                project.Tracks.Add(newTrack);
                vTracks.Add(newTrack);
                newTrack.Selected = false;
            }

            Timecode startTimecode = myVegas.Transport.CursorPosition;
            foreach (VideoTrack vTrack in vTracks)
            {
                Media pluginMedia = Media.CreateInstance(project, pluginText);
                VideoEvent vEvent = (VideoEvent) AddNewEvent(myVegas, vTrack, pluginMedia);
                TrackEventGroup grp = vEvent.Group;
                if (grp == null)
                {
                    grp = new TrackEventGroup(project);
                    project.Groups.Add(grp);
                    grp.Add(vEvent);
                }
                vTrack.SetCompositeMode(CompositeMode.SrcAlpha3D, false);

                Take takeSave = vEvent.ActiveTake;
                Media sc = new Subclip(project, pluginMedia.FilePath, vEvent.ActiveTake.Offset, vEvent.Length, false, null);
                sc = Media.CreateInstance(project, pluginText);
                vEvent.AddTake(sc.Streams[takeSave.StreamIndex], true);
                Effect effectColor = new Effect(pluginColor);
                sc.Effects.Insert(0, effectColor);
                if (pluginColor.IsOFX)
                {
                    OFXEffect ofxColor = effectColor.OFXEffect;
                    OFXDoubleParameter strength = (OFXDoubleParameter)ofxColor["BlendingStrength"];
                    strength.Value = 1;
                }

                for (int i = LAYERSCOUNT; i > 0; i--)
                {
                    VideoTrack newTrack = new VideoTrack(project, vTrack.Index + 1, null);
                    vegas.Project.Tracks.Add(newTrack);
                    if (i == 2)
                    {
                        newTrack.CompositeNestingLevel = vTrack.CompositeNestingLevel;
                        newTrack.Selected = true;
                        project.GroupSelectedTracks().CollapseTrackGroup();
                        newTrack.Selected = false;
                    }
                    newTrack.CompositeNestingLevel = vTrack.CompositeNestingLevel + 1;

                    newTrack.SetCompositeMode(vTrack.CompositeMode, false);
                    newTrack.Name = vTrack.Name;
                    newTrack.Solo = vTrack.Solo;
                    newTrack.Mute = vTrack.Mute;

                    foreach (TrackMotionKeyframe kf in newTrack.TrackMotion.MotionKeyframes)
                    {
                        kf.PositionZ += i * 10;
                    }

                    VideoEvent newEvent = (VideoEvent) vEvent.Copy(newTrack, vEvent.Start);
                    grp.Add(newEvent);
                }
                
                if (vTrack.IsCompositingParent)
                {
                    vTrack.SetParentCompositeMode(vTrack.CompositeMode, false);
                }

                vEvent.ActiveTake = takeSave;
            }
        }

        public static TrackEvent AddNewEvent(Vegas vegas, Track track, Media media, int i = 0, Timecode start = null, Timecode length = null)
        {
            if (vegas == null || track == null || media == null || i >= media.StreamCount(track.MediaType))
            {
                return null;
            }

            MediaStream ms = track.MediaType == MediaType.Video ? (MediaStream) media.GetVideoStreamByIndex(i) : (MediaStream) media.GetAudioStreamByIndex(i);

            if (start == null)
            {
                start = vegas.Transport.CursorPosition;
            }

            if (length == null)
            {
                length = ms.Length;
            }

            TrackEvent evnt = null;
            if (track.MediaType == MediaType.Video)
            {
                evnt = new VideoEvent(vegas.Project, start, length, null);
            }
            else
            {
                evnt = new AudioEvent(vegas.Project, start, length, null);
            }
            track.Events.Add(evnt);
            evnt.AddTake(ms);

            return evnt;
        }
    }
}


public class EntryPoint
{
    public void FromVegas(Vegas vegas)
    {
        Test_Script.Class test = new Test_Script.Class();
        test.Main(vegas);
    }
}

This script will create two different media instead of one media and one subclip because I found that I can't seem to create subclips of media generators. See the bolded part of the code, once I comment out the second line, the script will throw an error saying that the media is invalid.

@jetdv Is it possible to create a subclip of generators? If not, things are going to get a little tricky...

 

Plus: If you use Titles & Text instead of (Legacy) Text or other text plugins, we'll be able to change its parameters via script, so I recommend using it.

Last changed by zzzzzz9125 on 7/24/2024, 9:14 PM, changed a total of 3 times.

Using VEGAS Pro 22 build 248 & VEGAS Pro 21 build 208.

Information about my PC:
Brand Name: HP VICTUS Laptop
System: Windows 11.0 (64-bit) 10.00.22631
CPU: 12th Gen Intel(R) Core(TM) i7-12700H
GPU: NVIDIA GeForce RTX 3050 Laptop GPU
GPU Driver: NVIDIA Studio Driver 560.70

editeiro wrote on 7/24/2024, 11:41 PM

Ho @zzzzzz9125 Thanks for Thinking about this idea.

I use Subclip to be able to place VideoFX that affect several events at the same time without affecting the original media (it's the only way to color the edge of the 3D text without affecting the original media, for example) And using Sublip as a resource, this extrusion can be done in other media, such as .PNG, Nested Projects, Alpha .MOV and other Generated Media.

We can think about a script that can be triggered when the event is already created and selected on the timeline, and then the script just automates this sequence of actions that I described.

@jetdv I hoje wich something can be done about put the subclip step on the Script ^^

jetdv wrote on 7/25/2024, 8:46 AM

Is it possible to create a subclip of generators? If not, things are going to get a little tricky...

You might try following this (ignoring the "reverse" part):

zzzzzz9125 wrote on 7/25/2024, 9:24 AM

Is it possible to create a subclip of generators? If not, things are going to get a little tricky...

You might try following this (ignoring the "reverse" part):

@jetdv I've tried, using the following code:

Media sc = new Subclip(project, pluginMedia.FilePath, vEvent.ActiveTake.Offset, vEvent.Length, false, null);

pluginMedia is a generator media, whose FilePath only has its name and doesn't contain any possible real path. Subclip, on the other hand, seems to only look for the media in the true path when created, and cannot find the generator media. When I used the above code, it assumed that the Subclip media was invalid. If I change pluginMedia to any real media, it works. So I don't think I can create subclips on generator media.

Using VEGAS Pro 22 build 248 & VEGAS Pro 21 build 208.

Information about my PC:
Brand Name: HP VICTUS Laptop
System: Windows 11.0 (64-bit) 10.00.22631
CPU: 12th Gen Intel(R) Core(TM) i7-12700H
GPU: NVIDIA GeForce RTX 3050 Laptop GPU
GPU Driver: NVIDIA Studio Driver 560.70

jetdv wrote on 7/25/2024, 9:58 AM

@zzzzzz9125 It appears you are correct as there is no "file path" for a media generator. I tested a couple of options here but the sub-clip was not created. There was no error - but there was no sub-clip either.

In every event from track 2 down, I see there are TWO takes which means you've still got the original Titles and Text copied on each one as well the sub-clip copied. Why do you need the second take? Tracks 2 down only need to be the subclip.

zzzzzz9125 wrote on 7/25/2024, 9:59 AM

We can think about a script that can be triggered when the event is already created and selected on the timeline, and then the script just automates this sequence of actions that I described.

@editeiro How about this?

using System.Collections.Generic;
using System.Windows.Forms;

using ScriptPortal.Vegas;  // "ScriptPortal.Vegas" for Magix Vegas Pro 14 or above, "Sony.Vegas" for Sony Vegas Pro 13 or below

namespace Test_Script
{

    public class Class
    {
        public Vegas myVegas;
        public const int LAYERSCOUNT = 10;
        public const int COLOR_DEFAULT_R = 255;
        public const int COLOR_DEFAULT_G = 0;
        public const int COLOR_DEFAULT_B = 0;

        public void Main(Vegas vegas)
        {
            myVegas = vegas;
            myVegas.ResumePlaybackOnScriptExit = true;
            Project project = myVegas.Project;
            PlugInNode pluginColor = myVegas.VideoFX.GetChildByUniqueID("{Svfx:com.vegascreativesoftware:sepia}") ?? myVegas.VideoFX.GetChildByUniqueID("{Svfx:com.sonycreativesoftware:sepia}");
            if (pluginColor == null)
            {
                myVegas.ShowError("Sepia Plugin Not Found!");
                return;
            }

            // to avoid problems later when creating track groups
            foreach (Track myTrack in project.Tracks)
            {
                myTrack.Selected = false;
            }

            Timecode startTimecode = myVegas.Transport.CursorPosition;
            foreach (VideoEvent vEvent in GetSelectedVideoEvents(project, true))
            {
                VideoTrack vTrack = (VideoTrack)vEvent.Track;
                TrackEventGroup grp = vEvent.Group;
                if (grp == null)
                {
                    grp = new TrackEventGroup(project);
                    project.Groups.Add(grp);
                    grp.Add(vEvent);
                }
                vTrack.SetCompositeMode(CompositeMode.SrcAlpha3D, false);

                Take takeOriSave = null, takeSubSave = null;
                Media sc = null;
                foreach (Take t in vEvent.Takes)
                {
                    Media m = t.Media;
                    if (m != null && m.IsSubclip())
                    {
                        sc = m;
                        takeSubSave = t;
                        foreach (Take tk in vEvent.Takes)
                        {
                            if (tk.Media == ((Subclip)sc).ParentMedia)
                            {
                                takeOriSave = tk;
                                break;
                            }
                        }
                        break;
                    }
                }
                if (takeOriSave == null)
                {
                    takeOriSave = vEvent.ActiveTake;
                }
                if (sc == null)
                {
                    sc = new Subclip(project, vEvent.ActiveTake.Media.FilePath, vEvent.ActiveTake.Offset, vEvent.Length, false, null);
                }

                if (!sc.IsValid())
                {
                    if (DialogResult.Yes == MessageBox.Show("Failed to Create Subclip! The script cannot create subclips on media generators! It's recommended that you create a subclip of it manually before running the script!\n\nWant to copy the generator? Copying the generators will result in being out of sync with the original ones. Click \"Yes\" to Copy, \"No\" to Cancel.", "Subclip Warning", MessageBoxButtons.YesNo))
                    {
                        if (vEvent.ActiveTake.Media.IsGenerated())
                        {
                            sc = CopyGenerator(vEvent.ActiveTake.Media);
                        }
                    }
                    else
                    {
                        continue;
                    }
                }

                if (takeSubSave != null)
                {
                    vEvent.ActiveTake = takeSubSave;
                }
                else
                {
                    vEvent.AddTake(sc.Streams[takeOriSave.StreamIndex], true);
                }

                Effect effectColor = new Effect(pluginColor);
                sc.Effects.Insert(0, effectColor);
                if (pluginColor.IsOFX)
                {
                    OFXEffect ofxColor = effectColor.OFXEffect;
                    ((OFXDoubleParameter)ofxColor["BlendingStrength"]).Value = 1;
                    ((OFXRGBParameter)ofxColor["Color"]).Value = new OFXColor(COLOR_DEFAULT_R, COLOR_DEFAULT_G, COLOR_DEFAULT_B);
                }

                for (int i = LAYERSCOUNT; i > 0; i--)
                {
                    VideoTrack newTrack = new VideoTrack(project, vTrack.Index + 1, null);
                    vegas.Project.Tracks.Add(newTrack);
                    if (i == 2)
                    {
                        newTrack.CompositeNestingLevel = vTrack.CompositeNestingLevel;
                        newTrack.Selected = true;
                        project.GroupSelectedTracks().CollapseTrackGroup();
                        newTrack.Selected = false;
                        
                    }
                    newTrack.CompositeNestingLevel = vTrack.CompositeNestingLevel + 1;

                    newTrack.SetCompositeMode(vTrack.CompositeMode, false);
                    newTrack.Name = vTrack.Name;
                    newTrack.Solo = vTrack.Solo;
                    newTrack.Mute = vTrack.Mute;

                    foreach (TrackMotionKeyframe kf in newTrack.TrackMotion.MotionKeyframes)
                    {
                        kf.PositionZ += i * 10;
                    }

                    VideoEvent newEvent = (VideoEvent) vEvent.Copy(newTrack, vEvent.Start);
                    grp.Add(newEvent);
                }
                
                if (vTrack.IsCompositingParent)
                {
                    vTrack.SetParentCompositeMode(vTrack.CompositeMode, false);
                }

                vEvent.ActiveTake = takeOriSave;
            }
        }

        public static List<VideoEvent> GetSelectedVideoEvents(Project project, bool reverse = false)
        {
            List<VideoEvent> vEvents = new List<VideoEvent>();
            foreach (Track myTrack in project.Tracks)
            {
                if (myTrack.IsVideo())
                {
                    foreach (TrackEvent evnt in myTrack.Events)
                    {
                        if (evnt.Selected)
                        {
                            if (evnt.ActiveTake == null || evnt.ActiveTake.Media == null || evnt.ActiveTake.MediaStream == null)
                            {
                                continue;
                            }

                            vEvents.Add((VideoEvent)evnt);
                        }
                    }
                }
            }
            if (reverse)
            {
                vEvents.Reverse();
            }

            return vEvents;
        }

        public static Media CopyGenerator(Media sourceMedia)
        {
            if (sourceMedia == null || !sourceMedia.IsGenerated())
            {
                return null;
            }
            Media newMedia = new Media(sourceMedia.Generator.PlugIn);
            CopyEffect(sourceMedia.Generator, newMedia.Generator);
            newMedia.Length = sourceMedia.Length;
            VideoStream sourceStream = (VideoStream) sourceMedia.Streams[0];
            VideoStream newStream = (VideoStream) newMedia.Streams[0];
            newStream.Size = sourceStream.Size;
            newStream.FieldOrder = sourceStream.FieldOrder;
            newStream.PixelAspectRatio = sourceStream.PixelAspectRatio;
            newStream.AlphaChannel = sourceStream.AlphaChannel;
            newStream.BackgroundColor = sourceStream.BackgroundColor;
            return newMedia;
        }

        public static void CopyEffect(Effect sourceEffect, Effect targetEffect)
        {
            if (sourceEffect == null)
            {
                return;
            }

            if (targetEffect.PlugIn != sourceEffect.PlugIn)
            {
                targetEffect = new Effect(sourceEffect.PlugIn);
            }
            
            targetEffect.Preset = sourceEffect.CurrentPreset.Name;

            if (sourceEffect.PlugIn.UniqueID.Contains("{Svfx:")) // when the plugin is a DXT plugin, sourceEffect.IsOFX will throw an error, so I judge it by GUID strings
            {
                CopyOFX(sourceEffect.OFXEffect, targetEffect.OFXEffect);
            }
        }

        public static void CopyOFX(OFXEffect sourceOFX, OFXEffect targetOFX)
        {
            if (sourceOFX == null || targetOFX == null)
            {
                return;
            }

            foreach (OFXParameter targetPara in targetOFX.Parameters)
            {
                OFXParameter para = sourceOFX.FindParameterByName(targetPara.Name);
                if (para == null || targetPara.ParameterType != para.ParameterType)
                {
                    continue;
                }

                switch (targetPara.ParameterType)
                {
                    case OFXParameterType.Boolean:
                        ((OFXBooleanParameter)targetPara).Value = ((OFXBooleanParameter)para).Value;
                        break;

                    case OFXParameterType.Choice:
                        ((OFXChoiceParameter)targetPara).Value = ((OFXChoiceParameter)para).Value;
                        break;

                    case OFXParameterType.Custom:
                        ((OFXCustomParameter)targetPara).Value = ((OFXCustomParameter)para).Value;
                        break;

                    case OFXParameterType.Double2D:
                        ((OFXDouble2DParameter)targetPara).Value = ((OFXDouble2DParameter)para).Value;
                        break;

                    case OFXParameterType.Double3D:
                        ((OFXDouble3DParameter)targetPara).Value = ((OFXDouble3DParameter)para).Value;
                        break;

                    case OFXParameterType.Double:
                        ((OFXDoubleParameter)targetPara).Value = ((OFXDoubleParameter)para).Value;
                        break;

                    case OFXParameterType.Integer2D:
                        ((OFXInteger2DParameter)targetPara).Value = ((OFXInteger2DParameter)para).Value;
                        break;

                    case OFXParameterType.Integer3D:
                        ((OFXInteger3DParameter)targetPara).Value = ((OFXInteger3DParameter)para).Value;
                        break;

                    case OFXParameterType.Integer:
                        ((OFXIntegerParameter)targetPara).Value = ((OFXIntegerParameter)para).Value;
                        break;

                    case OFXParameterType.RGBA:
                        ((OFXRGBAParameter)targetPara).Value = ((OFXRGBAParameter)para).Value;
                        break;

                    case OFXParameterType.RGB:
                        ((OFXRGBParameter)targetPara).Value = ((OFXRGBParameter)para).Value;
                        break;

                    case OFXParameterType.String:
                        ((OFXStringParameter)targetPara).Value = ((OFXStringParameter)para).Value;
                        break;

                    default:
                        continue;
                }
            }
        }
    }
}

public class EntryPoint
{
    public void FromVegas(Vegas vegas)
    {
        Test_Script.Class test = new Test_Script.Class();
        test.Main(vegas);
    }
}

I can't really solve the generator's subclip problem. For general media files, it can accomplish the task directly without manually creating subclips. For generator media, it requires you to create subclips before running the script.

The script also has a built-in method to copy the media generator, as a test only, not recommended for use in projects.

However, the limitations of copying are too great. For OFX plugins, it can copy all plugin parameters; For DXT plugins, it requires you to save a preset in advance, otherwise you can only use the default default. Also, the copied won't change synchronously with the original ones. So it's still recommended that you manually create subclips in advance.

Last changed by zzzzzz9125 on 7/25/2024, 10:01 AM, changed a total of 1 times.

Using VEGAS Pro 22 build 248 & VEGAS Pro 21 build 208.

Information about my PC:
Brand Name: HP VICTUS Laptop
System: Windows 11.0 (64-bit) 10.00.22631
CPU: 12th Gen Intel(R) Core(TM) i7-12700H
GPU: NVIDIA GeForce RTX 3050 Laptop GPU
GPU Driver: NVIDIA Studio Driver 560.70

zzzzzz9125 wrote on 7/25/2024, 10:17 AM

In every event from track 2 down, I see there are TWO takes which means you've still got the original Titles and Text copied on each one as well the sub-clip copied. Why do you need the second take? Tracks 2 down only need to be the subclip.

@jetdv I added the subclip take to the selected event, then copied this event to another track, and finally switched the take of the selected event back. I think it's convenient in the code, and I didn't remove the extra takes. After all, the final goal was just to show the required takes.

When the user collapses the track group and leave one event at the top, they can choose not to expand the track group, but directly switch the event's take to the subclip, so they can access the subclip's Media FX too.

Last changed by zzzzzz9125 on 7/25/2024, 10:21 AM, changed a total of 4 times.

Using VEGAS Pro 22 build 248 & VEGAS Pro 21 build 208.

Information about my PC:
Brand Name: HP VICTUS Laptop
System: Windows 11.0 (64-bit) 10.00.22631
CPU: 12th Gen Intel(R) Core(TM) i7-12700H
GPU: NVIDIA GeForce RTX 3050 Laptop GPU
GPU Driver: NVIDIA Studio Driver 560.70

editeiro wrote on 7/25/2024, 1:44 PM

@zzzzzz9125
It worked perfectly here, and the warning to manually generate a subclip for Generated Media is great; it makes everything very clear.

I tested it to the limit here, and it worked with different media.

Thank you very much for your efforts and for bringing this idea to life.

It turned out excellent for a 1-Click Script tool.

I believe that for an evolution of this script, having more control over the extrusion would involve having a version of the script with a window to define values.

- A Rate value to choose the spacing between the tracks in the Z-position, to controlling the "density" of the extrusion.
(Will help to extrusion fits in Thiny Fonts)

- A value for the number of tracks to control the depth size of the extrusion.
And, if it's possible, I've never seen anything like it, can you guys tell me...
- A way in this same window, choose the Border color

Of course, this might make the project quite heavy and slow to render the preview, but it would be a great option to have more control over the appearance of our "3D object".

snibchi1 wrote on 7/26/2024, 5:10 AM

@zzzzzz9125

The script works wonderfully. Thank you very much! A color picker would not be bad.

Audiovisuelle Geräte

  • Canon EOS 6D
  • Canon EOS 450D
  • Nicon Coolpix S7000
  • AC800 Actioncam
  • Sony HDR-SR5

Hardware-Ausstattung

  • Monitor: LG Ultrawide 34UC79G
  • Tastatur: MSI GK 50 Elite
  • Maus: Corsair M65 PRO RGB
  • Gehäuse: CooMas HAF X 942-KKN1 ATX
  • PSU: be quiet! Staight P11 850W
  • Board: MSI MEG X570 ACE (Bios 7C35 v 1.P0, 04.07.2024)
  • CPU: AMD Ryzen 9 3900x
  • Cooler: Noctua NH-D14 SE2011 (AMD Adapter)
  • RAM: 2x 16GB D432GB 3600-17 Predator K2 KHX
  • M_2.1: 1x 2TB Gigabyte GP-ASM2NE6200
  • M_2.2: 1x 1TB Gigabyte GP-ASM2NE6100
  • M_2.3: 1x 1TB Samsung SSD Pro 980
  • SSD: 1x 4TB SanDisk Ultra 3D
  • SSD: 1x 512GB Samsung 850 Pro
  • GPU: 1x 12GB MSI Radeon RX 6750 XT
  • NAS: Synology DS 218+ 2x 6TB

Software

  • Windows 11 64 Pro (24H2 Build 26100.3775)
  • MAGIX Vegas Suite 365 (Build 22.248)
  • MAGIX Photostory deluxe 2025 (V 24.0.1.204 (UDP3))
  • Sound Forge Pro 18
  • ACID Pro 11.0 (x64)
  • Music Maker 2025
  • ADOBE Master Suite CS6, CC
zzzzzz9125 wrote on 7/26/2024, 7:09 AM

@editeiro @snibchi1 Updated script. Now it has a pop-up window where you can enter values and choose colors.

The Fade value gradually reduces the opacity of the generated events linearly.

Some other things have also been improved, such as track groups can always collapse (the old one failed to). Now you can use the script again for events that have already been generated once, which will clean up the old events and tracks.

Here's the code:

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;

using ScriptPortal.Vegas;  // "ScriptPortal.Vegas" for Magix Vegas Pro 14 or above, "Sony.Vegas" for Sony Vegas Pro 13 or below

namespace Test_Script
{

    public class Class
    {
        public Vegas myVegas;
        public const int RATE_DEFAULT = 10;
        public const int COUNT_DEFAULT = 10;
        public const int COLOR_R_DEFAULT = 255;
        public const int COLOR_G_DEFAULT = 0;
        public const int COLOR_B_DEFAULT = 0;
        public const int FADE_DEFAULT = 0;

        public void Main(Vegas vegas)
        {
            myVegas = vegas;
            myVegas.ResumePlaybackOnScriptExit = true;
            Project project = myVegas.Project;
            PlugInNode pluginColor = myVegas.VideoFX.GetChildByUniqueID("{Svfx:com.vegascreativesoftware:sepia}") ?? myVegas.VideoFX.GetChildByUniqueID("{Svfx:com.sonycreativesoftware:sepia}");
            if (pluginColor == null)
            {
                myVegas.ShowError("Sepia Plugin Not Found!");
                return;
            }

            double rate = RATE_DEFAULT;
            int count = COUNT_DEFAULT, color_R = COLOR_R_DEFAULT, color_G = COLOR_G_DEFAULT, color_B = COLOR_B_DEFAULT, fade = FADE_DEFAULT;
            DialogResult result = PopUpWindow(out rate, out count, out color_R, out color_G, out color_B, out fade);
            if (result != DialogResult.OK )
            {
                return;
            }

            Timecode startTimecode = myVegas.Transport.CursorPosition;
            foreach (VideoEvent vEvent in GetSelectedVideoEvents(project, true))
            {
                // to avoid problems later when creating track groups
                foreach (Track myTrack in project.Tracks)
                {
                    myTrack.Selected = false;
                }

                VideoTrack vTrack = (VideoTrack)vEvent.Track;
                TrackEventGroup grp = vEvent.Group;

                if (grp == null)
                {
                    grp = new TrackEventGroup(project);
                    project.Groups.Add(grp);
                    grp.Add(vEvent);
                }

                else
                {
                    List<TrackEvent> evs = new List<TrackEvent>();
                    foreach (TrackEvent ev in grp)
                    {
                        if (ev.Track != vTrack && ev.Track.IsVideo())
                        {
                            if (((VideoTrack)ev.Track).CompositeNestingLevel > vTrack.CompositeNestingLevel)
                            {
                                evs.Add(ev);
                            }
                        }
                    }
                    foreach (TrackEvent ev in evs)
                    {
                        if (ev.Track.Events.Count == 1)
                        {
                            project.Tracks.Remove(ev.Track);
                        }
                        else
                        {
                            ev.Track.Events.Remove(ev);
                        }
                    }
                }

                Take takeOriSave = null, takeSubSave = null;
                Media sc = null;
                foreach (Take t in vEvent.Takes)
                {
                    Media m = t.Media;
                    if (m != null && m.IsSubclip())
                    {
                        foreach (Take tk in vEvent.Takes)
                        {
                            if (tk.Media == ((Subclip)m).ParentMedia)
                            {
                                sc = m;
                                takeSubSave = t;
                                takeOriSave = tk;
                                break;
                            }
                        }
                        break;
                    }
                }
                if (takeOriSave == null)
                {
                    takeOriSave = vEvent.ActiveTake;
                }
                if (sc == null)
                {
                    sc = new Subclip(project, vEvent.ActiveTake.Media.FilePath, vEvent.ActiveTake.Offset, vEvent.Length, false, null);
                }

                if (!sc.IsValid())
                {
                    if (DialogResult.Yes == MessageBox.Show("Failed to Create Subclip! The script cannot create subclips on media generators! It's recommended that you create a subclip of it manually before running the script!\n\nWant to copy the generator? Copying the generators will result in being out of sync with the original ones. Click \"Yes\" to Copy, \"No\" to Cancel.", "Subclip Warning", MessageBoxButtons.YesNo))
                    {
                        if (vEvent.ActiveTake.Media.IsGenerated())
                        {
                            sc = CopyGenerator(vEvent.ActiveTake.Media);
                        }
                    }
                    else
                    {
                        continue;
                    }
                }

                if (takeSubSave != null)
                {
                    vEvent.ActiveTake = takeSubSave;
                }
                else
                {
                    vEvent.AddTake(sc.Streams[takeOriSave.StreamIndex], true);
                }

                Effect effectColor = null;
                foreach (Effect ef in sc.Effects)
                {
                    if (ef.PlugIn == pluginColor)
                    {
                        effectColor = ef;
                        break;
                    }
                }
                
                if (effectColor == null)
                {
                    effectColor = new Effect(pluginColor);
                    sc.Effects.Insert(0, effectColor);
                }

                if (pluginColor.IsOFX)
                {
                    OFXEffect ofxColor = effectColor.OFXEffect;
                    ((OFXDoubleParameter)ofxColor["BlendingStrength"]).Value = 1;
                    ((OFXRGBParameter)ofxColor["Color"]).Value = new OFXColor(color_R / 255.0, color_G / 255.0, color_B / 255.0);
                }

                vTrack.SetCompositeMode(CompositeMode.SrcAlpha3D, false);

                List<VideoTrack> vTrkList = new List<VideoTrack>();
                for (int i = vTrack.Index + 1; i < project.Tracks.Count; i++)
                {
                    if (!project.Tracks[i].IsVideo())
                    {
                        break;
                    }

                    VideoTrack trk = (VideoTrack)project.Tracks[i];
                    if (trk.CompositeNestingLevel > vTrack.CompositeNestingLevel)
                    {
                        vTrkList.Add(trk);
                    }
                    else
                    {
                        break;
                    }
                }

                for (int i = count; i > 0; i--)
                {
                    VideoTrack newTrack = null;
                    if (i > vTrkList.Count)
                    {
                        newTrack = new VideoTrack(project, vTrack.Index + vTrkList.Count + 1, null);
                        project.Tracks.Add(newTrack);
                        
                    }
                    else
                    {
                        newTrack = vTrkList[i - 1];
                    }
                    
                    if (i == 1 && i != count)
                    {
                        newTrack.CompositeNestingLevel = 0;
                        newTrack.Selected = true;
                        project.GroupSelectedTracks().CollapseTrackGroup();
                        newTrack.Selected = false;
                    }
                    newTrack.CompositeNestingLevel = 1;

                    newTrack.SetCompositeMode(vTrack.CompositeMode, false);
                    newTrack.Name = vTrack.Name;
                    newTrack.Solo = vTrack.Solo;
                    newTrack.Mute = vTrack.Mute;

                    foreach (TrackMotionKeyframe kf in newTrack.TrackMotion.MotionKeyframes)
                    {
                        kf.PositionZ += i * rate;
                    }

                    VideoEvent newEvent = (VideoEvent) vEvent.Copy(newTrack, vEvent.Start);
                    newEvent.Selected = false;
                    newEvent.FadeIn.Gain *= (float)(1 - (i - 1) * (fade / 100.0 / count));
                    grp.Add(newEvent);
                }
                
                for (int i = 0; i < count; i++)
                {
                    VideoTrack trk = (VideoTrack)project.Tracks[vTrack.Index + i + 1];
                    trk.Selected = true;
                    trk.CompositeNestingLevel += vTrack.CompositeNestingLevel;
                }

                if (vTrack.IsCompositingParent)
                {
                    vTrack.SetParentCompositeMode(vTrack.CompositeMode, false);
                }

                vEvent.ActiveTake = takeOriSave;
            }
        }

        static DialogResult PopUpWindow(out double rate, out int count, out int r, out int g, out int b, out int fade)
        {
            rate = RATE_DEFAULT;
            count = COUNT_DEFAULT;
            r = COLOR_R_DEFAULT;
            g = COLOR_G_DEFAULT;
            b = COLOR_B_DEFAULT;
            fade = FADE_DEFAULT;
            Form form = new Form();
            form.SuspendLayout();
            form.ShowInTaskbar = false;
            form.AutoSize = true;
            form.BackColor = Color.FromArgb(45,45,45);
            form.ForeColor = Color.FromArgb(200,200,200);
            if (System.Diagnostics.FileVersionInfo.GetVersionInfo(Application.ExecutablePath).FileMajorPart < 15)
            {
                form.BackColor = Color.FromArgb(153,153,153);
                form.ForeColor = Color.FromArgb(0,0,0);
            }
            form.Font = new Font("Arial", 9);
            form.Text = "3D Extrusion";
            form.FormBorderStyle = FormBorderStyle.FixedToolWindow;
            form.StartPosition = FormStartPosition.CenterScreen;
            form.AutoSizeMode = AutoSizeMode.GrowAndShrink;

            Panel p = new Panel();
            p.AutoSize = true;
            p.AutoSizeMode = AutoSizeMode.GrowAndShrink;
            form.Controls.Add(p);

            TableLayoutPanel l = new TableLayoutPanel();
            l.AutoSize = true;
            l.AutoSizeMode = AutoSizeMode.GrowAndShrink;
            l.GrowStyle = TableLayoutPanelGrowStyle.AddRows;
            l.ColumnCount = 4;
            l.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 60));
            l.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 60));
            l.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 60));
            l.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 90));
            p.Controls.Add(l);

            Label label = new Label();
            label.Margin = new Padding(6, 10, 0, 6);
            label.Text = "Rate";
            label.AutoSize = true;
            l.Controls.Add(label);

            TextBox rateBox = new TextBox();
            rateBox.AutoSize = true;
            rateBox.Margin = new Padding(6, 6, 18, 6);
            rateBox.Text = rate.ToString();
            l.Controls.Add(rateBox);

            label = new Label();
            label.Margin = new Padding(6, 10, 0, 6);
            label.Text = "Color";
            label.AutoSize = true;
            l.Controls.Add(label);

            Button colorButton = new Button();
            colorButton.Margin = new Padding(6, 6, 4, 6);
            colorButton.Tag = "Color";
            colorButton.BackColor = Color.FromArgb(r, g, b);
            colorButton.AutoSize = true;
            l.Controls.Add(colorButton);
            colorButton.MouseDown += new MouseEventHandler(colorButton_MouseDown);

            label = new Label();
            label.Margin = new Padding(6, 10, 0, 6);
            label.Text = "Count";
            label.AutoSize = true;
            l.Controls.Add(label);

            TextBox countBox = new TextBox();
            countBox.AutoSize = true;
            countBox.Margin = new Padding(6, 6, 18, 6);
            countBox.Text = count.ToString();
            l.Controls.Add(countBox);

            label = new Label();
            label.Margin = new Padding(6, 10, 0, 6);
            label.Text = "Fade";
            label.AutoSize = true;
            l.Controls.Add(label);

            TrackBar fadeBar = new TrackBar();
            fadeBar.AutoSize = false;
            fadeBar.Height = label.Height;
            fadeBar.Margin = new Padding(0, 6, 0, 6);
            fadeBar.Dock = DockStyle.Fill;
            fadeBar.Minimum = 0;
            fadeBar.Maximum = 100;
            fadeBar.LargeChange = 20;
            fadeBar.SmallChange = 10;
            fadeBar.TickStyle = TickStyle.None;
            fadeBar.Value = fade;
            l.Controls.Add(fadeBar);

            FlowLayoutPanel panel = new FlowLayoutPanel();
            panel.FlowDirection = FlowDirection.RightToLeft;
            panel.AutoSize = true;
            panel.AutoSizeMode = AutoSizeMode.GrowAndShrink;
            panel.Anchor = AnchorStyles.None;
            l.Controls.Add(panel);
            l.SetColumnSpan(panel, 4);
            panel.Font = new Font("Arial", 8);

            Button cancel = new Button();
            cancel.Text = "Cancel";
            cancel.DialogResult = DialogResult.Cancel;
            panel.Controls.Add(cancel);
            form.CancelButton = cancel;

            Button ok = new Button();
            ok.Text = "OK";
            ok.DialogResult = DialogResult.OK;
            panel.Controls.Add(ok);
            form.AcceptButton = ok;

            form.ResumeLayout();

            DialogResult result = form.ShowDialog();
            double.TryParse(rateBox.Text, out rate);
            int.TryParse(countBox.Text, out count);
            r = colorButton.BackColor.R;
            g = colorButton.BackColor.G;
            b = colorButton.BackColor.B;
            fade = fadeBar.Value;
            return result;
        }

        private static void colorButton_MouseDown(object sender, MouseEventArgs e)
        {
            Button bt = (Button)sender;
            ColorDialog colorDia = new ColorDialog();
            colorDia.Color = bt.BackColor;
            if (colorDia.ShowDialog() == DialogResult.OK)
            {
                bt.BackColor = colorDia.Color;
            }
        }

        public static List<VideoEvent> GetSelectedVideoEvents(Project project, bool reverse = false)
        {
            List<VideoEvent> vEvents = new List<VideoEvent>();
            foreach (Track myTrack in project.Tracks)
            {
                if (myTrack.IsVideo())
                {
                    foreach (TrackEvent evnt in myTrack.Events)
                    {
                        if (evnt.Selected)
                        {
                            if (evnt.ActiveTake == null || evnt.ActiveTake.Media == null || evnt.ActiveTake.MediaStream == null)
                            {
                                continue;
                            }

                            vEvents.Add((VideoEvent)evnt);
                        }
                    }
                }
            }
            if (reverse)
            {
                vEvents.Reverse();
            }

            return vEvents;
        }

        public static Media CopyGenerator(Media sourceMedia)
        {
            if (sourceMedia == null || !sourceMedia.IsGenerated())
            {
                return null;
            }
            Media newMedia = new Media(sourceMedia.Generator.PlugIn);
            CopyEffect(sourceMedia.Generator, newMedia.Generator);
            newMedia.Length = sourceMedia.Length;
            VideoStream sourceStream = (VideoStream) sourceMedia.Streams[0];
            VideoStream newStream = (VideoStream) newMedia.Streams[0];
            newStream.Size = sourceStream.Size;
            newStream.FieldOrder = sourceStream.FieldOrder;
            newStream.PixelAspectRatio = sourceStream.PixelAspectRatio;
            newStream.AlphaChannel = sourceStream.AlphaChannel;
            newStream.BackgroundColor = sourceStream.BackgroundColor;
            return newMedia;
        }

        public static void CopyEffect(Effect sourceEffect, Effect targetEffect)
        {
            if (sourceEffect == null)
            {
                return;
            }

            if (targetEffect.PlugIn != sourceEffect.PlugIn)
            {
                targetEffect = new Effect(sourceEffect.PlugIn);
            }
            
            targetEffect.Preset = sourceEffect.CurrentPreset.Name;

            if (sourceEffect.PlugIn.UniqueID.Contains("{Svfx:")) // when the plugin is a DXT plugin, sourceEffect.IsOFX will throw an error, so I judge it by GUID strings
            {
                CopyOFX(sourceEffect.OFXEffect, targetEffect.OFXEffect);
            }
        }

        public static void CopyOFX(OFXEffect sourceOFX, OFXEffect targetOFX)
        {
            if (sourceOFX == null || targetOFX == null)
            {
                return;
            }

            foreach (OFXParameter targetPara in targetOFX.Parameters)
            {
                OFXParameter para = sourceOFX.FindParameterByName(targetPara.Name);
                if (para == null || targetPara.ParameterType != para.ParameterType)
                {
                    continue;
                }

                switch (targetPara.ParameterType)
                {
                    case OFXParameterType.Boolean:
                        ((OFXBooleanParameter)targetPara).Value = ((OFXBooleanParameter)para).Value;
                        break;

                    case OFXParameterType.Choice:
                        ((OFXChoiceParameter)targetPara).Value = ((OFXChoiceParameter)para).Value;
                        break;

                    case OFXParameterType.Custom:
                        ((OFXCustomParameter)targetPara).Value = ((OFXCustomParameter)para).Value;
                        break;

                    case OFXParameterType.Double2D:
                        ((OFXDouble2DParameter)targetPara).Value = ((OFXDouble2DParameter)para).Value;
                        break;

                    case OFXParameterType.Double3D:
                        ((OFXDouble3DParameter)targetPara).Value = ((OFXDouble3DParameter)para).Value;
                        break;

                    case OFXParameterType.Double:
                        ((OFXDoubleParameter)targetPara).Value = ((OFXDoubleParameter)para).Value;
                        break;

                    case OFXParameterType.Integer2D:
                        ((OFXInteger2DParameter)targetPara).Value = ((OFXInteger2DParameter)para).Value;
                        break;

                    case OFXParameterType.Integer3D:
                        ((OFXInteger3DParameter)targetPara).Value = ((OFXInteger3DParameter)para).Value;
                        break;

                    case OFXParameterType.Integer:
                        ((OFXIntegerParameter)targetPara).Value = ((OFXIntegerParameter)para).Value;
                        break;

                    case OFXParameterType.RGBA:
                        ((OFXRGBAParameter)targetPara).Value = ((OFXRGBAParameter)para).Value;
                        break;

                    case OFXParameterType.RGB:
                        ((OFXRGBParameter)targetPara).Value = ((OFXRGBParameter)para).Value;
                        break;

                    case OFXParameterType.String:
                        ((OFXStringParameter)targetPara).Value = ((OFXStringParameter)para).Value;
                        break;

                    default:
                        continue;
                }
            }
        }
    }
}

public class EntryPoint
{
    public void FromVegas(Vegas vegas)
    {
        Test_Script.Class test = new Test_Script.Class();
        test.Main(vegas);
    }
}

 

Last changed by zzzzzz9125 on 7/26/2024, 7:39 AM, changed a total of 7 times.

Using VEGAS Pro 22 build 248 & VEGAS Pro 21 build 208.

Information about my PC:
Brand Name: HP VICTUS Laptop
System: Windows 11.0 (64-bit) 10.00.22631
CPU: 12th Gen Intel(R) Core(TM) i7-12700H
GPU: NVIDIA GeForce RTX 3050 Laptop GPU
GPU Driver: NVIDIA Studio Driver 560.70

snibchi1 wrote on 7/26/2024, 10:16 AM

@zzzzzz9125

Great work! Thank you very much. 👏

Audiovisuelle Geräte

  • Canon EOS 6D
  • Canon EOS 450D
  • Nicon Coolpix S7000
  • AC800 Actioncam
  • Sony HDR-SR5

Hardware-Ausstattung

  • Monitor: LG Ultrawide 34UC79G
  • Tastatur: MSI GK 50 Elite
  • Maus: Corsair M65 PRO RGB
  • Gehäuse: CooMas HAF X 942-KKN1 ATX
  • PSU: be quiet! Staight P11 850W
  • Board: MSI MEG X570 ACE (Bios 7C35 v 1.P0, 04.07.2024)
  • CPU: AMD Ryzen 9 3900x
  • Cooler: Noctua NH-D14 SE2011 (AMD Adapter)
  • RAM: 2x 16GB D432GB 3600-17 Predator K2 KHX
  • M_2.1: 1x 2TB Gigabyte GP-ASM2NE6200
  • M_2.2: 1x 1TB Gigabyte GP-ASM2NE6100
  • M_2.3: 1x 1TB Samsung SSD Pro 980
  • SSD: 1x 4TB SanDisk Ultra 3D
  • SSD: 1x 512GB Samsung 850 Pro
  • GPU: 1x 12GB MSI Radeon RX 6750 XT
  • NAS: Synology DS 218+ 2x 6TB

Software

  • Windows 11 64 Pro (24H2 Build 26100.3775)
  • MAGIX Vegas Suite 365 (Build 22.248)
  • MAGIX Photostory deluxe 2025 (V 24.0.1.204 (UDP3))
  • Sound Forge Pro 18
  • ACID Pro 11.0 (x64)
  • Music Maker 2025
  • ADOBE Master Suite CS6, CC
m3lquixd wrote on 7/26/2024, 10:19 AM

Too nice bro!!

About me:
Hi! Melqui Calheiros Here. I've been using Vegas as my only video editor for over 10 years. I edit professionally for various influencers, public bodies and small businesses. My goal is to squeeze Vegas to the fullest! And end the prejudice that software has here in Brazil.

⬇️ Some of my jobs. ⬇️
https://www.vegascreativesoftware.info/us/forum/post-your-vegas-creations--109464/?page=37#ca872169

PC Specs:
Operating System:
    Windows 11 Pro 64-bit
CPU:
    AMD Ryzen 7 5700G 3.80 GHz
RAM:
    32,0GB Dual-Channel DDR4 3200MHz
Motherboard:
    ASRock B450M Steel Legend (AM4)
Graphics:
    MSI RTX 4060 Ventus 2X Black OC 8GB
Storage:
    476GB ADATA SU650 (SATA (SSD))
    931GB KINGSTON SNV2S1000G (SATA-2 (SSD))

editeiro wrote on 7/26/2024, 1:40 PM

@zzzzzz9125 Work perfectly! Thanks for that!
I'll make Icons to personalize my buttons here, I share with you guys here when is ready.