Search Unity

Change caterpillars texture via script?

Discussion in 'Scripting' started by EndUser, Sep 22, 2014.

  1. EndUser

    EndUser

    Joined:
    Aug 12, 2013
    Posts:
    51
    Salut!

    I have a GO "TrackLeft" (and "TrackRight" as well ;)).

    What am I trying to do is to change track texture (as vehicle moves).

    Here what I have:

    On the scene/in the prefab a GO "TrackLeft", a non-morphing fixed mesh. It also contains road wheels, so TextureOffset cannot be used.
    TrackLeft has several materials:


    Then, in the C# script:

    Code (CSharp):
    1. void UpdateTracks()
    2. {
    3.     //Advance idxTracktexture by 1 in the range of 0..3
    4.     idxTrackLeftTexture = (idxTrackLeftTexture + 1) % 4;
    5.     idxTrackRightTexture = (idxTrackRightTexture + 1) % 4;
    6.     Material [] matTest = trfmTrackLeft.transform.renderer.materials; //Dummy
    7.     trfmTrackLeft.transform.renderer.material =
    8.         trfmTrackLeft.transform.renderer.materials[idxTrackLeftTexture];
    9.     trfmTrackRight.transform.renderer.material =
    10.         trfmTrackRight.transform.renderer.materials[idxTrackRightTexture];
    11.     Debug.Log("Tracks changed");
    12. }
    But this code does not have any effects on the visualization of the vehicle (except plenty of log records "Tracks changed").

    What can I do to change the texture of the game object?

    P.S. That dummy "Material [] matTest" could be seen in step-by-step debugging and it looks like it really contains all these textures.

    P.P.S. I browsed a plenty of examples.
    All of them contain lines "public Material [4] mtrlTracks" filled via Editor\Inspector, that looks quite dumb in this case. I don't want to drag-and-drop every pixel via that crowded global variables.

    Thank you!
     
    Last edited: Sep 22, 2014
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    I think you want to pull out and copy the materials you want in your Start() function for this object, keeping them in a local member Material[] array.

    Then at run time replace from that saved array.

    Also, try this first: make two textures, one red, one green, and two materials using each, and replace the chunk you think is the tank tread with alternating red/green materials every other frame.

    Until you have that working (which will be very obvious when it does work), it will be tricky to get the other more-complicated case of four specific tread-scrolling textures working.

    Kurt
     
    EndUser likes this.
  3. EndUser

    EndUser

    Joined:
    Aug 12, 2013
    Posts:
    51
    /me Worked on the project these days
    Yes, you are absolutely correct!
    Thank you!

    Here what I've found:
    Assigning multiple materials to meshrenderer makes Unity3D to visualize all materials at once (SIC!).
    And track change was not visible, since any material I wanted to display was already displayed amongst a crowd all others.
    Therefore, the array of materials to be inserted into meshrenderer must be stored somewhere aside.
    So, I am forced to make Inspector-accessible array of materials in public variables.
    I could screw around to hide and to fill the array dynamically at run-time, but for a moment I gave up. ;)

    Otherwise, idea is working.
    Current code is:
    Code (CSharp):
    1. public class UpdateTracks : MonoBehaviour
    2. {
    3.     //Assigned via Inspector, drag-and-drop style. :(
    4.     public Material[] mtrlTracks;
    5.     int idxTrackTexture = 0;
    6.     void Update()
    7.     {
    8.         //Lines of code to choose the right moment and right index of texture to act.
    9.         //Quite a mess!..
    10.         this.renderer.material = mtrlTracks[idxTrackTexture];
    11.     }
    12. }
    While GObj now looks this way:


    Thank you again!
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    Excellent! Glad to hear of your success.

    If you want to load the materials dynamically at Start() time, try this:

    Code (csharp):
    1.  
    2.     Material[] mtrlTracks;  // no need to be public now
    3.     void Start()
    4.     {
    5.         int numFrames = 4;
    6.         mtrlTracks = new Material[numFrames];
    7.         for (int i = 0; i < numFrames; i++)
    8.         {
    9.             mtrlTracks[i] = Instantiate( Resources.Load( System.String.Format(
    10.                 "Track{0}", i))) as Material;
    11.         }
    12.     }
    13.  
    Then you won't need to set anything in the inspector... win-win!

    Make sure the material assets you are loading are stored in your project under a folder named Resources (anywhere in Assets) otherwise Unity won't be able to find it at runtime.

    Like so:

    Assets/Resources/Track0.mat
    etc.

    Kurt
     
    EndUser likes this.
  5. EndUser

    EndUser

    Joined:
    Aug 12, 2013
    Posts:
    51
    Thank you!

    Is ".\resources" folder guaranteed to be redistributed?

    I tested loading from files from various folders, and found out that standalone .exe could miss those paths. Everything is alright once you stay within the editor. ;)
     
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    Check the Unity docs for the "official" point of view, but any folder anywhere in your hierarchy named Resources will have all of its contents brought into the final game bundle, regardless of references to it. You must do this for code-driven loading of assets.

    You can also have more than one Resources folder scattered around the hierarchy too, which obviously enables name conflicts, so be careful.

    Kurt
     
    EndUser likes this.