Tattooshop Posted January 31, 2020 Share Posted January 31, 2020 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 More sharing options...
KT Kingsley Posted January 31, 2020 Share Posted January 31, 2020 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); } } } 1 Link to comment Share on other sites More sharing options...
Rolig Loon Posted January 31, 2020 Share Posted January 31, 2020 (edited) 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 January 31, 2020 by Rolig Loon 1 Link to comment Share on other sites More sharing options...
Mollymews Posted February 1, 2020 Share Posted February 1, 2020 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); } } 1 Link to comment Share on other sites More sharing options...
Mollymews Posted February 1, 2020 Share Posted February 1, 2020 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; } } } } } 1 1 Link to comment Share on other sites More sharing options...
Mollymews Posted February 1, 2020 Share Posted February 1, 2020 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); } } } } } 1 Link to comment Share on other sites More sharing options...
Tattooshop Posted February 1, 2020 Author Share Posted February 1, 2020 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 More sharing options...
Lucia Nightfire Posted February 1, 2020 Share Posted February 1, 2020 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. 2 1 Link to comment Share on other sites More sharing options...
KT Kingsley Posted February 1, 2020 Share Posted February 1, 2020 (edited) 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 February 1, 2020 by KT Kingsley 1 Link to comment Share on other sites More sharing options...
Mollymews Posted February 1, 2020 Share Posted February 1, 2020 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 1 Link to comment Share on other sites More sharing options...
Lucia Nightfire Posted February 1, 2020 Share Posted February 1, 2020 (edited) 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 February 1, 2020 by Lucia Nightfire 1 2 Link to comment Share on other sites More sharing options...
Tattooshop Posted February 3, 2020 Author Share Posted February 3, 2020 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 More sharing options...
Recommended Posts
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