Jump to content

Subtle Texture Animation


Macrocosm Draegonne
 Share

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

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

Recommended Posts

I have some plants and want to animate the texture slightly, to make it feel like wind, I didnt want to use a sprite animation because that really inhibits texture quality.  I've tried a few different ways, below is most recent.   Trouble is its animating the texture from the center of the surface, making the base move as much as the tips of the plant and of course nill in the middle, are there any other ways to animate the texture that would feel more natural, like a fixed bottom and slow minimal pingpong back and forth at the top?  Can I offset the rotation point?  I had some randomization code in this before but that isnt the issue so I pulled it until I can figure this part.  Im using rotation now, but I could go left right, rotation pingpong looks the nicest at the top though especially when randomized, still its not going to work as I outlined above.  Ill keep digging, but theres not much out there on this topic.  I'll post back what I find, but if anyone has any pointers that would be great too :)

// Texture Wobble

float CYCLES_PER_SECOND = 0.02;
integer FACES = ALL_SIDES; 
float ANGLE_DEGREES = 2.0;
default {    state_entry()     {
float angleRadians = ANGLE_DEGREES * DEG_TO_RAD;
llSetTextureAnim( ANIM_ON | SMOOTH | ROTATE | LOOP | PING_PONG,
FACES, 1, 1      // (These parameters ignored for ROTATE animation)
, -angleRadians    // Start angle in radians
, angleRadians * 2.0   // Length of animation in radians
, CYCLES_PER_SECOND
);
}}

 

 

Edited by Macrocosm Draegonne
  • Like 1
Link to comment
Share on other sites

Did/can you create the grass? If the answer is yes, you can offset the texture UV map so that the "center" of it is at the base of the mesh face where you need it.

If not, you can also set the texture offset parameters, but doing this is not smooth and can't be combined accurately with the client-side effect of moving the texture.

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

Flexiprims seem to be out of fashion these days, since people have moved so heavily to using mesh instead of prim construction.  In the Old Days, though, we used to simulate wind by making a tree flexi and then setting its params to respond very gently to wind but be fairly stiff, so it didn't wave about like a flag. Because flexi objects stay fixed at  one end but move at the other end, it was a pretty nice way to simulate wind rustling a tree.  It had the major disadvantage of looking goofy on trees build with intersecting flat prims, of course, but nothing's perfect.

Sadly, we can't make flexi mesh, so that's not an option. I imagine that your approach with animated textures is the best way to go, but I don't see a way to rotate the texture around a point other than the center of the face.  IIRC, llSetTextureAnim ignores any settings for offsets, scaling, and rotations of the texture itself, but I might be wrong.

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

14 minutes ago, Wulfie Reanimator said:

Did/can you create the grass? If the answer is yes, you can offset the texture UV map so that the "center" of it is at the base of the mesh face where you need it.

If not, you can also set the texture offset parameters, but doing this is not smooth and can't be combined accurately with the client-side effect of moving the texture.

Yes I created the mesh and textures, though im not sure I understand fully what you mean by center.  Move the uv section off the imagespace onto a repeat area in blender?  Or change the texture so the plant image is in the upper space and thus the uv is as well?

Edited by Macrocosm Draegonne
Link to comment
Share on other sites

1 minute ago, Rolig Loon said:

Flexiprims seem to be out of fashion these days, since people have moved so heavily to using mesh instead of prim construction.  In the Old Days, though, we used to simulate wind by making a tree flexi and then setting its params to respond very gently to wind but be fairly stiff, so it didn't wave about like a flag. Because flexi objects stay fixed at  one end but move at the other end, it was a pretty nice way to simulate wind rustling a tree.  It had the major disadvantage of looking goofy on trees build with intersecting flat prims, of course, but nothing's perfect.

Sadly, we can't make flexi mesh, so that's not an option. I imagine that your approach with animated textures is the best way to go, but I don't see a way to rotate the texture around a point other than the center of the face.  IIRC, llSetTextureAnim ignores any settings for offsets, scaling, and rotations of the texture itself, but I might be wrong.

Well, there will be flexymesh at some point, I saw that somewhere. :)  Thats a cool Idea about flexies I bet it was great for grasses, and being able to tie it to wind is nice as well, I was reading the legacy linden tree's have a lot of cool features like that too, but they're gone now.

Link to comment
Share on other sites

27 minutes ago, Wulfie Reanimator said:

Did/can you create the grass? If the answer is yes, you can offset the texture UV map so that the "center" of it is at the base of the mesh face where you need it.

If not, you can also set the texture offset parameters, but doing this is not smooth and can't be combined accurately with the client-side effect of moving the texture.

It worked!  But I did it backwards lol, it will work next upload though, cheers!❤️ 

I would have never thought of that as a solution, I was all digging into a code solution.

Edited by Macrocosm Draegonne
Link to comment
Share on other sites

44 minutes ago, Macrocosm Draegonne said:

It worked!  But I did it backwards lol, it will work next upload though, cheers!❤️ 

I would have never thought of that as a solution, I was all digging into a code solution.

The longer you script, the more you try to find ways to simplify your code. Sometimes your code can be simplified with the way the object is built.

  • Like 5
Link to comment
Share on other sites

9 minutes ago, Wulfie Reanimator said:

The longer you script, the more you try to find ways to simplify your code. Sometimes your code can be simplified with the way the object is built.

Yeah, especially goodies like that, zero script need at all! 

I will have to thin out my grass density in the texture a touch, but I love the animation.  It will take some tweaking to get the randomization and animation just right but its fun anyway. :)  I want it to be really subtle and randomish.   The most epic would be vertex animations dictated by Linden Wind and weight paint on the mesh, but thats not a thing here at the moment.  The texture anim is a great fall back though, especially the more subtle I can get it.  Im also putting several other plants on the same texture to save draw calls, so the uv map is going to be a lot of odd offset fun with this one hehe.

Edited by Macrocosm Draegonne
Link to comment
Share on other sites

The randomization is working great but Im wondering if thats the best thing, maybe something of a preset thats seemingly random anim would be better performant for more people? 

I want this to be as lightweight as possible so I can have more plants moving, works great on my PC but im wondering if the timers are the best route?  Also id like to introduce some spans of time with no animation so maybe adding a third timer cycle for that, or somehow injecting a zero in cycles_per_second on occasion?  Are timers taxing on the viewer/server?

Below is my latest code, feel free to laugh at my newbiness and poke holes in the approach lol.  Its more properly formatted now at least.

// Texture Plant Waver Chingus With Randomization
// Script can be deleted after activated.

float CYCLES_PER_SECOND = 0.02;
integer FACES = ALL_SIDES;  // Change if you want just one face
float ANGLE_DEGREES = 0.5;

default {    
    state_entry() 
        {
            llSetTimerEvent(5.00);  // trigger timer event (max once per second)
        } 
    timer()
        {
            llSetTimerEvent(1.0+llFrand(15.0)); //trigger the timer event every 15 seconds
            float angleRadians = ANGLE_DEGREES * DEG_TO_RAD;
            llSetTextureAnim( ANIM_ON | SMOOTH | ROTATE | LOOP | PING_PONG  
            , FACES, 1, 1      // (These parameters ignored for ROTATE animation)
            , -angleRadians    // Start angle in radians
            , angleRadians * 2.0   // Length of animation in radians
            , llFrand(0.04) - CYCLES_PER_SECOND);
        }
}

 

Link to comment
Share on other sites

3 hours ago, Macrocosm Draegonne said:

Are timers taxing on the viewer/server?

Nothing a script does internally has any effect on any viewer. Scripts are 100% server-side. That said, you're not going to kill a sim with a 1-15 second timer. Even if you had a 0.022 second timer running constantly, the sim would be chugging along just fine. (Not saying you should do it, that's still terrible practice.)

If you wanted a random chance for no animation, you could do an extra llFrand(1) with a ratio to determine whether or not to pick a random animation at all.

Your script is perfectly fine, by the way. I kinda like your unconventional multi-lining style, too.

  • Thanks 1
Link to comment
Share on other sites

1 hour ago, Wulfie Reanimator said:

Nothing a script does internally has any effect on any viewer. Scripts are 100% server-side. That said, you're not going to kill a sim with a 1-15 second timer. Even if you had a 0.022 second timer running constantly, the sim would be chugging along just fine. (Not saying you should do it, that's still terrible practice.)

If you wanted a random chance for no animation, you could do an extra llFrand(1) with a ratio to determine whether or not to pick a random animation at all.

Your script is perfectly fine, by the way. I kinda like your unconventional multi-lining style, too.

Thanks so much for the tips and encouragement, I will dig into the wiki on that more and tinker with adding an extra ..llFrand(1) seems like it would be nice for them to go dormant from time to time.  Im also going to switch to deal with linksets using llSetLinkTextureAnimation probably.  Thanks for letting me know about viewer/server strain area too, I really wanted to be sure I wasnt going to hurt performance as that is a primary goal of mine.  

I am  actually really pleased with how well it performs, and its super smooth too, once you get the numbers just right so its not jumpy, and let me tell ya, that texture animation can fly at blazing speed! lol made me dizzy a few times.  I will be doing many weird things with it in due time I hope. :D

Sometimes I really like the code to have a cozy macro view pattern, it helps me to jump into the different areas as the code gets larger and larger, especially when I am thinking of the code, I can mentally zoom in and out of the pattern lol. ?  Im not sure what syntax highlighing to use in Brackets though,  I saw some lsl ones in github but not for brackets.  Luckily there is a GLSL one that seems to work nicely built into Brackets, and also the C syntax highlighters seem to look well enough too.

Link to comment
Share on other sites

Omg I have so many questions, I love learning a new language, you only get this feeling for so long heheh.  I have had to stop myself so many times from coming here with a million questions, and then, no, get back to digging and testing, and tinkering.  LSL is quite different than i am used to doing with web stuff.

Im currently trying to reduce the number of the wind speed to fit nicely into the last section of the llSetTextureAnim   anything too high and its really a bit much.  ive tried all sorts of things.  Using a simple division messes up on rare occasion when it falls below zero, the texture goes off all cockeyed.    In my mind I want an array/list of values, I could use llRound to turn the windspeed into a single digit, and then on my array associate a small number to each range of those windspeeds, which then can be passed down to llSetTextureAnim  in the last spot for Float Rate.  But there are many other ways I could do this too, instead of float rate maybe tweaking the Float Length, or both?  lol so many things to test, I imagine it will change a lot over time as I learn more.

Link to comment
Share on other sites

15 minutes ago, KT Kingsley said:

May be a logarithmic, exponential or square function? This might give you an idea: http://wiki.secondlife.com/wiki/User:Dora_Gustafson/moderated_world_wind.

Oooh, thats interesting, I had not found that page when searching wind stuff.    Really smart to peg on that 0,0,0 spot for consistency, I will tinker with that for sure, also I did not know you could sail the winds in SL, thats new to me also are very cool.  Cheers!

Link to comment
Share on other sites

I was able to modulate the number a bit with that function from the sailing script, however, its all very tinkery, I am almost there, but its still too fast and active compared to similar plant animations ive seen out in the realms, it keeps getting better as I learn more though.  The trouble is as I tweak the number lower to get a slower speed the animation then breaks, and the texture splits up and/or stops moving all together.  ?

Below is my latest code tinkering with using the wind speed.

EDIT: Improved by reducing the angle, so tinkering around more with that area more might yield more interesting results, to get a mix for low wind vs high wind.

// Texture Plant Waver Chingus Based On LL Wind Speed
// Script can be deleted after activated.
float CYCLES_PER_SECOND = .04;
integer FACES = ALL_SIDES;  // Change if you want just one face
float ANGLE_DEGREES = .3;

 
default {    
    state_entry() 
        {
            llSetStatus(STATUS_PHANTOM,TRUE);
            llSetTimerEvent(6.00);  // trigger timer event (max once per second)
        } 
    timer()
        {
        vector windVector = llWind( ZERO_VECTOR);
        float windSpeed = llVecMag( windVector);
        integer windValue = llRound(windSpeed);
        float modSpeed = .1*llPow( llVecMag( windVector), .333333); // moderated speed
        //float windDirection = llAtan2( windVector.y, windVector.x);
        //integer compassWind = ( 450 - (integer)( RAD_TO_DEG*windDirection))%360;
        //llSetTimerEvent(1.0+llFrand(12.0)); //trigger the timer event every 15 seconds
            float angleRadians = ANGLE_DEGREES * DEG_TO_RAD;
            llSetTextureAnim( ANIM_ON | SMOOTH | ROTATE | LOOP | PING_PONG  
            , FACES, 1, 1      // (These parameters ignored for ROTATE animation)
            , -angleRadians    // Start angle in radians
            , angleRadians * .2   // Length of animation in radians
          //, llFrand(0.2) - CYCLES_PER_SECOND);
          //, windValue / CYCLES_PER_SECOND);
            , modSpeed );
        }
   
}

 

 

Edited by Macrocosm Draegonne
Link to comment
Share on other sites

Ill put this one up now, its much better for what I had in mind, and of course is reliant on my UV setup as mentioned above in the thread.  I am certain I will make this several times over again as I learn more and can do more, but I am happy now and should jump back to the graphics and mesh side of this to further enhance it on those fronts.

Thanks everyone for the encouragement and super useful pointers! :)

// Texture Plant Waver Chingus Based On LL Wind Speed
// Script should be deleted after activated.
float CYCLES_PER_SECOND = .06;
integer FACES = ALL_SIDES;  // Change if you want just one face
float ANGLE_DEGREES = .8;

 
default {    
    state_entry() 
        {
            llSetStatus(STATUS_PHANTOM,TRUE);
            llSetTimerEvent(4.00);  // trigger timer event (max once per second)
        } 
    timer()
        {
        vector windVector = llWind( ZERO_VECTOR);
        float windSpeed = llVecMag( windVector);
        integer windValue = llRound(windSpeed);
        float modSpeed = .1*llPow( llVecMag( windVector), .333333); // moderated speed
        //float windDirection = llAtan2( windVector.y, windVector.x);
        //integer compassWind = ( 450 - (integer)( RAD_TO_DEG*windDirection))%360;
        llSetTimerEvent(1.0+llFrand(12.0)); //trigger the timer event every 12 seconds
            float angleRadians = ANGLE_DEGREES * DEG_TO_RAD;
            llSetTextureAnim( ANIM_ON | SMOOTH | ROTATE | LOOP | PING_PONG  
            , FACES, 1, 1      // (These parameters ignored for ROTATE animation)
            , -angleRadians    // Start angle in radians
            , modSpeed * .02   // Length of animation in radians
            ,CYCLES_PER_SECOND * llFrand(0.66) * modSpeed);
        }
   
}

 

Edited by Macrocosm Draegonne
  • Like 1
Link to comment
Share on other sites

You're not off the hook yet. ? 

vector windVector = llWind( ZERO_VECTOR);
float windSpeed = llVecMag( windVector);
integer windValue = llRound(windSpeed);
float modSpeed = .1*llPow( llVecMag( windVector), .333333); // moderated speed

This reads a bit confusing. You raise the wind speed a power, but then only use 10% of that value? Why not just multiply by a value less than 1.0? Like:

        vector windVector = llWind( ZERO_VECTOR);
        float windSpeed = llVecMag( windVector);
        integer windValue = llRound(windSpeed);
        float modSpeed = windSpeed * 0.25; // moderated speed

Note how I replaced the refundant llVecMag with windSpeed that already used that exact result. Also, you don't use windValue or windVector so those can be removed and used inline.

float windSpeed = llVecMag( llWind(ZERO_VECTOR) );
float modSpeed = windSpeed * 0.25;

Much more consice and simpler to read and understand. That 0.25 is just an example though, it's probably not near the same value you had.

Edited by Wulfie Reanimator
  • Like 1
Link to comment
Share on other sites

12 minutes ago, Wulfie Reanimator said:

You're not off the hook yet. ? 


vector windVector = llWind( ZERO_VECTOR);
float windSpeed = llVecMag( windVector);
integer windValue = llRound(windSpeed);
float modSpeed = .1*llPow( llVecMag( windVector), .333333); // moderated speed

This reads a bit confusing. You raise the wind speed a power, but then only use 10% of that value? Why not just multiply by a value less than 1.0? Like:


        vector windVector = llWind( ZERO_VECTOR);
        float windSpeed = llVecMag( windVector);
        integer windValue = llRound(windSpeed);
        float modSpeed = windSpeed * 0.25; // moderated speed

Note how I replaced the refundant llVecMag with windSpeed that already used that exact result. Also, you don't use windValue or windVector so those can be removed and used inline.


float windSpeed = llVecMag((ZERO_VECTOR) );
float modSpeed = windSpeed * 0.25;

Much more consice and simpler to read and understand. That 0.25 is just an example though, it's probably not near the same value you had.

Thanks so much for that, I will test for sure, there was still some cruft in there from other testing too heheh, but also the numbers are very very touchy in the llSetTimerEvent, so it caused me to try some odd combos in the functions to try and make it calmer, especially in that line I brought over from the sailing script, also in that last paramater section too, may times I would get no animation, or the texture would split and freeze. 

I tried to look for some others like and opposite of llPow to replace that bit with but nothing jumped out as I was checking, I figured that line was the most messy of all and would need refactoring, if not the whlole script, but I still was very happy to get it down to a very subtle effect comparatively.

 

Edited by Macrocosm Draegonne
Link to comment
Share on other sites

When testing

float windSpeed = llVecMag((ZERO_VECTOR) );

I get zero's as a result with that for some reason when testing the output, is there some caveat about needing to separate out with this below?

 vector windVector = llWind( ZERO_VECTOR);
 float windSpeed = llVecMag( windVector);

I will keep testing for sure, but I can say the float modSpeed = windSpeed * 0.05  works perfectly. that indeed is a much cleaner and more concise line!  I was beating around the bush there a bit lol ?

Now that I a bit more fully understand things I can add in some If/else logic to treat the high and low wind differently in the animation which should be  a nice touch hopefully, and can add some more still time to it as well perhaps

Edited by Macrocosm Draegonne
Link to comment
Share on other sites

54 minutes ago, Macrocosm Draegonne said:

I get zero's as a result with that for some reason when testing the output, is there some caveat about needing to separate out with this below?

That was a typo I edited after I posted it. Check again.

P.S. Quoting and writing code from a phone is not a fun time.

Edited by Wulfie Reanimator
  • Like 1
Link to comment
Share on other sites

3 minutes ago, Wulfie Reanimator said:

That was a typo I edited after I posted it. Check again.

P.S. Quoting and writing code from a phone is not a fun time.

Oh I see now, the llWind wasnt there, thats why the separated one was working and not the other, it needed that function to get the right connection stack going.

I was almost figuring that out but not quite there hahaha, I knew something was off but I didnt detect that missing llWind, which should have been apparent but I guess im still a newb and thats going to keep happening until I scream and learn more.

  • Haha 1
Link to comment
Share on other sites

I have to put a video up of it once its in world,  the texture and mesh needs some more love first though, plus I have to put more plants in the same texture to save draw calls.   With animated leaves the texture density needs to be thinner too.  I made the grasses from scratch in Blender, hand painted mesh + material effects, then baked planes. 

Im guessing once I get enough of them out there in a scene the next hurdle could be the timing between them,  Im hoping that being based on the wind which is different in different areas will give enough diversity, but I would wager I need to add some more still time to them to make the effect even more subtle most of the time, Ive still got to play with the if/else logic some more today which should do that fine :)

Edited by Macrocosm Draegonne
Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 2009 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...