I was wondering if it is possible to render part of a texture over the 2D screen space.
The problem with GUI.DrawTexture and Graphics.DrawTexture is that they only provide a way to draw the full texture to a rectangular area. What I am trying to achieve is to draw a sub-part of the texture and not the full texture. For example the texture dimension is 512x512, but I want to draw part of it, say Rect(10, 10, 300, 400).
Try using a GUITexture for this instead of the GUI functions. This class’s pixelInset property lets you adjust the position of the texture at a pixel level.
Hmmm… Are you sure GUITexture’s pixelInset can do that?
I just tried adding one to the scene, specified the texture, played with different pixelInset values to see if it can draw “part” of the texture, but it didn’t. What it did is draw the texture on screen with the screen offset (x, y) and dimension (width, height). Unless I’m missing something here.
Or maybe I was not clear while explaining. I already know how to draw the whole texture in a screen offset and with specific dimensions. What I am aiming for is to draw part of the texture and not the whole texture. For example the texture size is 512x512, and I want to draw a small part of from within the picture starting from an offset and with specific width and height. After getting this part, I will draw it on the screen just like the way I draw a full texture using GUI.DrawTexture.
So… Is what you suggested do that? Or is there is something to achieve such thing?
Ah, I think I misunderstood - I thought you wanted to fill the screen with a part of a texture larger than the screen. I can’t think of a direct way to chop a small section from a larger image, but you use the Texture2D class to create a new texture containing only part of the original image (see the doc page for Texture2D.SetPixels for some example code).
I’ve had the opportunity to tinker with the texture2D abilities recently. You can get an array of colors from the source texture using Texture2D.GetPixels(0). After that you could create a new texture, fill it with 0.0 alpha, and then copy the desired pixels to the new texture. So it would go something like this (in C#):
public Texture2D m_SourceTexture;
public Texture2D m_DestinationTexture;
void Awake()
{
m_DestinationTexture = new Texture2D(m_SourceTexture.width, m_SourceTexture.height, TextureFormat.ARGB32, false);
Color[] sourcePixels = m_SourceTexture.GetPixels(0);
Color[] destinationPixels = m_DestinationTexture.GetPixels(0);
for (int i = 0; i < destinationPixels.length; ++i)
destinationPixels[i].a = 0.0f;
int xStart = 10;
int yStart = 10;
for (int y = 0; y < 512; ++y)
{
for (int x = 0; x < 512; ++x)
{
int index = (y * 512 + x);
destinationPixels[index] = sourcePixels[index];
}
}
m_DestinationTexture.SetPixels(destinationPixels, 0);
m_DestinationTexture.Apply();
}
I’m not 100% sure if the math is correct, but you get the gist of it, I hope.
I believe I can achieve such thing using Texture2D’s GetPixels and SetPixels. Though not sure about the performance if I am planning to do that frequently.
Thank you andeeee for the direction. Also, thank you ernestor for the quick example.
In my case, the plugin I wrote plays back a movie. I had to roll my own, because I required more functionality for movie playback than what was provided. So my solution was to use the FixedUpdate() method to do the updating of the texture. I set the update frequency to 0.083 (12 FPS). This solution helped drastically.
I used the GUI group to draw part of a texture on the screen. The function only have 5 lines of code…
//Test area
var x0:float=20;
var y0:float= 50;
var u1:float=30;
var v1:float=10;
var u2:float=90;
var v2:float=50;
DrawTextureClipped(speedBaseTexture,u1,v1,u2,v2,x0,y0); //speedBase:Texture2D texture assigned in inspector
}
function DrawTextureClipped(textureToDraw : Texture2D,u1:float,v1:float,u2:float,v2:float,x:float,y:float)
/* Goal: to draw part of a texture on the screen
parameters:
u1,v1,u2,v2: pixel coordinates of the textureToDraw
x,y pixel coordinates of the box (up, left corner)
WARNING: u2>u1 and v2>v1
*/
{
var du: float=u2-u1;
var dv: float=v2-v1;
GUI.BeginGroup (Rect (x, y, du+1, dv+1));
GUI.Label ( Rect(-u1,-v1 ,textureToDraw.width,textureToDraw.height), textureToDraw );
GUI.EndGroup ();
}
Of course the function call must be inside the OnGui function…
//open GUIgroup in front of the healthBarEmpty texture. Base the width on the hero’s remaining health % (x,y,w,h)
GUI.BeginGroup(new Rect (Screen.width *.7F , Screen.height * .06F, Screen.width *.2F *HH.CurrentHealth/HH.MaxHealth, Screen.height * .05F));
//draw the healthBarFull texture inside the GUIgroup box
GUI.DrawTexture(new Rect(0,0, Screen.width *.2F, Screen.height * .05F), healthBarFull);
//close GUIgroup
GUI.EndGroup();
As the remaining health % goes down, the width of the GUIgroup box will decrease drawing less of what is inside and exposing more of what is behind it.