Jump to content

Slideshow fade to black script


Tattooshop
 Share

You are about to reply to a thread that has been inactive for 1612 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

Hey. I have a simple slideshow script and I decided to make a smooth transition when the texture gradually turns black and then the frame changes and the texture gradually turns white again.

How to make the color from white turn to black and then from black to white gradually?

Thank you!

Link to comment
Share on other sites

This basic script illustrates one way of doing that:

integer steps = 25;
float delay = 0.01;
integer texture;

default
{
    state_entry ()
    {
        llSetTimerEvent (5.0);
    }

    timer ()
    {
        integer fade_step = steps;
        while (fade_step--)
        {
            float fade = (float) fade_step / (float) steps;
            llSetColor (<fade, fade, fade>, ALL_SIDES);
            llSleep (delay);
        }
        llSetTexture (llList2Key (["e417f443-a199-bac1-86b0-0530e177fb54", "3ccd6876-dce0-4974-aede-22aa15ad38af"], texture = !texture), ALL_SIDES);
        while (++fade_step <= steps)
        {
            float fade = (float) fade_step / (float) steps;
            llSetColor (<fade, fade, fade>, ALL_SIDES);
            llSleep (delay);
        }
    }
}

 

  • Thanks 1
Link to comment
Share on other sites

Declare two integer variables iBlacker and iBlackness.  Then do something like this ....

timer()
{
    if (iBlacker)
    {
        ++iBlackness;
        float fBlackPct = (float) iBlackness * 0.1;
        llSetColor(< fBlackPct, fBlackPct, fBlackPct>, iFace);
    }
    else
    {
       --iBlackness;
        float fBlackPct = (float) iBlackness * 0.1;
        llSetColor(< fBlackPct, fBlackPct, fBlackPct>, iFace);
    }
    if (iBlackness == 10)
    {
       iBlacker = FALSE;
       //And change the slide here, while the face is black
    }
    else if (iBlackness == 0 )
    {
        iBlacker = TRUE;
        llSetTimerEvent(0.0);
    }
}

Then you trigger the timer event whenever you want the face (iFace) to start fading to black.  If that's all you want to do with the timer -- as in the case of a viewer that changes slides when you click on it -- then this is a standalone fade-unfade routine.  If you need the timer for other things (like changing slides automatically), then you'll have to multiplex the timer to handle both slide automation and the fading routine.

BTW, you can write a routine like this more compactly, but I wrote it in expanded form to make the logic easier to follow.  I hope.

Edited by Rolig Loon
  • Thanks 1
Link to comment
Share on other sites

is an interesting question this as it raises the general problem case

how to plot points on a line between two vectors ?

a way this can be done for the  general problem case

vector VecLinePlot(vector a, vector b, float s)
{  
    // 's' is a step between 0.0 and 1.0  
    // where s = 0.5 is halfway between the vectors
    
    // normalise the difference between vectors a and b
    vector normal = llVecNorm(b - a);
    
    // scale s by the square root of 3
    float step = s * llSqrt(3.0);
    
    // return the vector at step on the line between vectors a and b
    return a + step * normal;
}


// example usage

default
{
    state_entry()
    {
        vector start = <0.3, 0.5, 0.9>;
        vector end =   <0.7, 0.2, 1.0>;
        
        float step = 0.5;
        
        vector v = VecLinePlot(start, end, step);
                 
        llSetColor(v, ALL_SIDES);
    }
}

 

 

  • Thanks 1
Link to comment
Share on other sites

adding more to the conversation

suppose we wanted to not use llSetTimerEvent(). A reason might be that we want something to happen quicker than the timer event can fire, but slower than a loop would execute on the CPU

a way to do this is in a infinite loop punctuated in constant time. Example:

state_entry()
{
    float PERIOD = 0.01;   // some period to wait in seconds or fraction of a second

    while (TRUE)  // infinite loop
    {
       if (llGetTime() >= PERIOD)  // punctuate in constant time
        {
            llResetTime();           

            ... at this period in time ... do our thing             
       }
    }
}

 

combining this with the VecLinePlot method to shift from a color to another color

this example shifts back and forward between blue and red
 

default
{
    state_entry()
    {
        float PERIOD = 0.01;  // some period to wait in seconds or fraction of a second
    
        float STEP = 0.002;  // step to take at period
    
        vector a = <1.0, 0.0, 0.0>;
        vector b = <0.0, 0.0, 1.0>;   

        llSetColor(b, ALL_SIDES);

        float s = STEP;

        while (TRUE)  // infinite loop
        {
            if (llGetTime() >= PERIOD)  // punctuate in constant time
            {  
                llResetTime();
                
                // inline vec line plot
                vector c = a + s * 1.73205080757 * llVecNorm(b - a);
          
                llSetColor(c, ALL_SIDES);
             
                s += STEP;
                if (s >= 1.0) 
                {
                    // swap a b
                    c = a; a = b; b = c;
                    s = STEP;
                }
            }                        
        }
    }
}

 

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

when we look at the code I posted then can see that I made an attempt to optimise the code by inlining the VecLinePlot method

when look closely at this then we can realise that function llVecNorm() need only be called when s <= STEP,. Looking even closer we further realise that scaling s by sqrt(3) need only be done when llVecNorm() is called

as wrote the code is doing an unnecessary multiplication and function call at every step in the loop

which is significant when STEP is tiny. Which as wrote is set to 0.002

's' is in the range: 0.0 to 1.0.  When divide 1.0 by 0.002 (STEP) then result is 500. Which means that as wrote, the code is making 499 unnecessary functions calls to llVecNorm() and doing 499 unnecessary multiplications every (0.01 * 500) 5 seconds

which is not good. And probably make Oz, Rider and EverybodyElse Linden cry from my code abusing the server CPU, 998 times every 5 seconds 😸

so I better post a fix just in case
 

default
{
    state_entry()
    {
        float PERIOD = 0.01;  // some period to wait in seconds or fraction of a second
    
        float STEP = 0.002;  // step to take at period
    
        vector a = <1.0, 0.0, 0.0>;
        vector b = <0.0, 0.0, 1.0>;   

        llSetColor(a, ALL_SIDES);

        float s = STEP;
        // 1.73205080757 is sqrt(3)
        vector n = 1.73205080757 * llVecNorm(b - a);  

        while (TRUE)  // infinite loop
        {
            if (llGetTime() >= PERIOD)  // punctuate in constant time
            {  
                llResetTime();
                
                // inline vec line plot
                vector c = a + s * n;
          
                llSetColor(c, ALL_SIDES);
             
                s += STEP;
                if (s >= 1.0)
                {
                    // swap a b
                    c = a; a = b; b = c;
                    s = STEP;
                    n = 1.73205080757 * llVecNorm(b - a);
                }
            }                        
        }
    }
}

 

  • Thanks 1
Link to comment
Share on other sites

Hello! Thank you all very much! Everything works!

17 hours ago, KT Kingsley said:

This basic script illustrates one way of doing that

That's what I did. The only thing, at the bottom I have changed event and I had to remove it, as it was resetting the loop for some reason. Is it possible to keep it somehow?

integer steps = 25;
float delay = 0.01;

float TIMER = 5; // Timer in second 
integer FACE_NUMBER = 0; // Face number 
list slides = [];

getSlides()
{
    integer ii;
    integer iiMax = llGetInventoryNumber(INVENTORY_TEXTURE);
    string name;

    for (ii = 0; ii < iiMax; ii++)
    {
        name = llGetInventoryName(INVENTORY_TEXTURE, ii);
        slides += [name];
    }
}

integer index;

newSlide()
{
    string texture = llList2String(slides, index);
    llSetTexture(texture, FACE_NUMBER);
    index++;
    if (index >= llGetListLength(slides))
        index = 0;
}

default

{
    state_entry()
    {
        getSlides();
        
        if (llGetListLength(slides) > 0)
        {
        llSetTimerEvent(TIMER);
        index = 0;
        newSlide();
        }
    }

    timer()
    {
        integer fade_step = steps;
        while (fade_step--)
        {
            float fade = (float) fade_step / (float) steps;
            llSetColor (<fade, fade, fade>, FACE_NUMBER);
            llSleep (delay);
        }
        
        newSlide();
        
         while (++fade_step <= steps)
        {
            float fade = (float) fade_step / (float) steps;
            llSetColor (<fade, fade, fade>, FACE_NUMBER);
            llSleep (delay);
        }
    }
    
/*    changed(integer change)
    {
        llResetScript();
    }*/
}

 

17 hours ago, Rolig Loon said:

Declare two integer variables iBlacker and iBlackness.  Then do something like this ....

If you need the timer for other things (like changing slides automatically), then you'll have to multiplex the timer to handle both slide automation and the fading routine.

Yes, the slideshow uses automatic frame change. I tried to use your way, but failed as it is for touch. How in this case to multiplex the timer?

36 minutes ago, Mollymews said:

 And probably make Oz, Rider and EverybodyElse Linden cry from my code abusing the server CPU, 998 times every 5 seconds 😸

so I better post a fix just in case
 

 

And I used your method, everything works, but I could not match the transition cicle and timer. Is it possible to synchronize them somehow?

float TIMER = 5; // Timer in second 
integer FACE_NUMBER = 0; // Face number 
list slides = [];

getSlides()
{
    integer ii;
    integer iiMax = llGetInventoryNumber(INVENTORY_TEXTURE);
    string name;

    for (ii = 0; ii < iiMax; ii++)
    {
        name = llGetInventoryName(INVENTORY_TEXTURE, ii);
        slides += [name];
    }
}

integer index;

newSlide()
{
    string texture = llList2String(slides, index);
    llSetTexture(texture, FACE_NUMBER);
    index++;
    if (index >= llGetListLength(slides))
        index = 0;
}

default

{
    state_entry()
    {
        getSlides();
        
        if (llGetListLength(slides) > 0)
        {
        llSetTimerEvent(TIMER);
        index = 0;
        newSlide();
        }
        
        float PERIOD = 0.01;  // some period to wait in seconds or fraction of a second
    
        float STEP = 0.002;  // step to take at period
    
        vector a = <1.0, 1.0, 1.0>;
        vector b = <0.0, 0.0, 0.0>;   

        llSetColor(a, ALL_SIDES);

        float s = STEP;
        // 1.73205080757 is sqrt(3)
        vector n = 1.73205080757 * llVecNorm(b - a);  

        while (TRUE)  // infinite loop
        {
            if (llGetTime() >= PERIOD)  // punctuate in constant time
            {  
                llResetTime();
                
                // inline vec line plot
                vector c = a + s * n;
          
                llSetColor(c, ALL_SIDES);
             
                s += STEP;
                if (s >= 1.0)
                {
                    // swap a b
                    c = a; a = b; b = c;
                    s = STEP;
                    n = 1.73205080757 * llVecNorm(b - a);
                }
            }                        
        }
    }

    timer()
    {        
        newSlide();
    }
    
/*    changed(integer change)
    {
        llResetScript();
    }*/
}

Thank you all very much again!

Link to comment
Share on other sites

Why not use a mesh "cover" layer that is uv "fixed" and use an animated texture protocol to "slide" a alpha gradient across the uv fixed point resulting in a fade that you could time as slow or fast as you want and color it black or white or pink, heh.

This would result in only two updates being sent to viewers in range per cycle and not a spam of alpha values, which could be many depending on how slow/smooth you want the fading.

  • Like 2
  • Thanks 1
Link to comment
Share on other sites

The changed event is being triggered by the changed textures and changed colours. You can be more selective about which changes you want to have trigger the script reset. For example:

changed (integer changes)
{
    if (changes & CHANGED_INVENTORY) llResetScript ();
}

See the wiki for a description of all the changes the changed event is triggered by: http://wiki.secondlife.com/wiki/Changed.

Edited by KT Kingsley
  • Thanks 1
Link to comment
Share on other sites

10 minutes ago, Tattooshop said:

And I used your method, everything works, but I could not match the transition cicle and timer. Is it possible to synchronize them somehow?

the code I posted would go at the end of your NewSlide function

altho I would suggest that you seriously look at what Lucia is recommending

what I have posted is more a example of how to plot a line between two vectors

  • Thanks 1
Link to comment
Share on other sites

Here is what I was talking about with a UV fixed cover that does all the work with the fewest updates sent to viewers(notice when the update indicators show):

https://gyazo.com/930b4c3aff6729591e06dfabef2ca027

Here is what it looks like in Blender, where a single face(material) with all uv's "fixed" at 0.001953125(1 / 512) for x and 0.5 for y.

https://gyazo.com/02b15f89f09d1e487e7402f8e63f70f6

I made an alpha gradient in paint.net on a 256x256 canvas, then saved as targa.

https://gyazo.com/9877c2b2569ee5a1896da6d9abff1a93

I use a legacy prim root, link the mesh as link #2 and saved this script (with non-mesh attempts intact, but commented out):

integer image_index = -1;
default
{
    state_entry()
    {
        llSetObjectDesc("83,2.0");
    }
    on_rez(integer i)
    {
        llResetScript();
    }
    touch_end(integer i)
    {
        if (llDetectedKey(0) == llGetOwner())
        {
            list T = llParseString2List(llStringTrim(llGetObjectDesc(),STRING_TRIM),[","," "],[]);
            if (llGetListLength(T) == 2)
            {
                integer frames_per_second = (integer)llList2String(T,0);
                if ((frames_per_second >= 1) && (frames_per_second <= 254))
                {
                    integer t;
                    if (t = llGetInventoryNumber(INVENTORY_TEXTURE))
                    {
                        //llSetLinkAlpha(2,1.0,0);
                        llSetLinkTextureAnim(2,ANIM_ON,0,255,1,1.0,254.0,(float)frames_per_second);
                        llSleep(llListStatistics(LIST_STAT_MAX,[254.0 / (float)frames_per_second,0.0]));
                        //llSetLinkPrimitiveParamsFast(2,[PRIM_ALPHA_MODE,0,PRIM_ALPHA_MODE_MASK,0]);
                        llSleep(0.022222);
                        llSetLinkPrimitiveParamsFast(1,[PRIM_TEXTURE,4,llGetInventoryName(INVENTORY_TEXTURE,++image_index % t),<1.0,1.0,0.0>,<0.0,0.0,0.0>,0.0]);
                        llSleep(llFabs((float)llList2String(T,1))); //delay_time, allow time for texture caching/CDN download?
                        llSetLinkTextureAnim(2,ANIM_ON | REVERSE,0,255,1,1.0,254.0,(float)frames_per_second);
                        //llSetLinkPrimitiveParamsFast(2,[PRIM_ALPHA_MODE,0,PRIM_ALPHA_MODE_BLEND,0]);
                        llSleep(254.0 / (float)frames_per_second);
                        llSetLinkTextureAnim(2,0,0,0,0,0.0,0.0,0.0);
                        //llSetLinkAlpha(2,0.0,0);
                    }
                    else
                    {
                        llOwnerSay("no textures in inventory");
                    }
                }
                else
                {
                    llOwnerSay("frames per second in desc must be a value between 1 & 254");
                }
            }
            else
            {
                llOwnerSay("desc must contain an integer(frames_per_second) and a float(delay_time) in CSV format");
            }
        }
    }
}

Despite trying for hours with starting of 0.0 and length of 255, since there was a strange "relapse" at the end of the cycle putting the texture near center as well as not being able to use SMOOTH without LOOP, I settled on the values you see above.

Anyone duplicating this method may have to tweak their numbers if their gradient isn't perfect.

It's also best to use a frame around both layers so the bottom layer isn't seen while the cover hovers in front.

Edited by Lucia Nightfire
  • Like 1
  • Thanks 2
Link to comment
Share on other sites

On 2/2/2020 at 1:45 AM, Lucia Nightfire said:

Here is what I was talking about with a UV fixed cover that does all the work with the fewest updates sent to viewers(notice when the update indicators show):

https://gyazo.com/930b4c3aff6729591e06dfabef2ca027

Here is what it looks like in Blender, where a single face(material) with all uv's "fixed" at 0.001953125(1 / 512) for x and 0.5 for y.

https://gyazo.com/02b15f89f09d1e487e7402f8e63f70f6

I made an alpha gradient in paint.net on a 256x256 canvas, then saved as targa.

https://gyazo.com/9877c2b2569ee5a1896da6d9abff1a93

I use a legacy prim root, link the mesh as link #2 and saved this script (with non-mesh attempts intact, but commented out):


integer image_index = -1;
default
{
    state_entry()
    {
        llSetObjectDesc("83,2.0");
    }
    on_rez(integer i)
    {
        llResetScript();
    }
    touch_end(integer i)
    {
        if (llDetectedKey(0) == llGetOwner())
        {
            list T = llParseString2List(llStringTrim(llGetObjectDesc(),STRING_TRIM),[","," "],[]);
            if (llGetListLength(T) == 2)
            {
                integer frames_per_second = (integer)llList2String(T,0);
                if ((frames_per_second >= 1) && (frames_per_second <= 254))
                {
                    integer t;
                    if (t = llGetInventoryNumber(INVENTORY_TEXTURE))
                    {
                        //llSetLinkAlpha(2,1.0,0);
                        llSetLinkTextureAnim(2,ANIM_ON,0,255,1,1.0,254.0,(float)frames_per_second);
                        llSleep(llListStatistics(LIST_STAT_MAX,[254.0 / (float)frames_per_second,0.0]));
                        //llSetLinkPrimitiveParamsFast(2,[PRIM_ALPHA_MODE,0,PRIM_ALPHA_MODE_MASK,0]);
                        llSleep(0.022222);
                        llSetLinkPrimitiveParamsFast(1,[PRIM_TEXTURE,4,llGetInventoryName(INVENTORY_TEXTURE,++image_index % t),<1.0,1.0,0.0>,<0.0,0.0,0.0>,0.0]);
                        llSleep(llFabs((float)llList2String(T,1))); //delay_time, allow time for texture caching/CDN download?
                        llSetLinkTextureAnim(2,ANIM_ON | REVERSE,0,255,1,1.0,254.0,(float)frames_per_second);
                        //llSetLinkPrimitiveParamsFast(2,[PRIM_ALPHA_MODE,0,PRIM_ALPHA_MODE_BLEND,0]);
                        llSleep(254.0 / (float)frames_per_second);
                        llSetLinkTextureAnim(2,0,0,0,0,0.0,0.0,0.0);
                        //llSetLinkAlpha(2,0.0,0);
                    }
                    else
                    {
                        llOwnerSay("no textures in inventory");
                    }
                }
                else
                {
                    llOwnerSay("frames per second in desc must be a value between 1 & 254");
                }
            }
            else
            {
                llOwnerSay("desc must contain an integer(frames_per_second) and a float(delay_time) in CSV format");
            }
        }
    }
}

Despite trying for hours with starting of 0.0 and length of 255, since there was a strange "relapse" at the end of the cycle putting the texture near center as well as not being able to use SMOOTH without LOOP, I settled on the values you see above.

Anyone duplicating this method may have to tweak their numbers if their gradient isn't perfect.

It's also best to use a frame around both layers so the bottom layer isn't seen while the cover hovers in front.

Thanks a lot. I did not immediately understand how the gradient would go from left to right, but when you explained I realized that the UV was "compressed" to the left side, and the gradient leaked pixel by pixel through it, everything became clear. really very interesting method. need to take note! Thank you very much!

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 1612 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...