Here’s some code I use to draw a graph on a texture:
// Attach to simple sprite
// sprite anchor must be set to BOTTOM_LEFT
// sprite texture Wrap Mode must be set to Clamp
// must have rigid body and collider attached for smart cursor
//----------------------------------------------
var blankTexture: Texture2D; // the blank "paper", assigned in Inspector
var graphTexture: Texture2D; // the "paper" to draw on, assigned in Inspector
var dotSymbol: Texture2D; // the symbol to draw, assigned in Inspector
var graphCoordinates: TextMesh; // where to put the smart cursor info, assigned in Inspector
var pXMin: float; // x axis min value, // set in Inspector
var pXMax: float; // x axis max value, // set in Inspector
var pYMin: float; // y axis min value, // set in Inspector
var pYMax: float; // y axis max value, // set in Inspector
var pPlotXRange = new Array(); // min/max list
var pPlotYRange = new Array(); // min/max list
var pPlotXScale: float; // size of the bitmap
var pPlotYScale: float; // size of the bitmap
var pNewXScale: float; // adjusted scale
var pNewYScale: float; // adjusted scale
var axisWidth: float; // length of X axis + offset, set in Inspector
var axisHeight: float; // length of Y axis + offset, set in Inspector
var xOffset: float; // x axis origin offset, // set in Inspector
var yOffset: float; // y axis origin offset, // set in Inspector
var symbolSize: int; // set in Inspector
var symbolHalfWidth: float; // half size of symbol
var symbolHalfHeight: float; // half size of symbol
var dRect: Rect;
var dotColors: Color[];
var xx: int;
var yy: int;
var i: int;
var theRay: Ray;
var hit: RaycastHit;
var theCursor: GameObject; // set in Inspector
var spriteWidth: float; // set in Inspector
var spriteHeight: float; // set in Inspector
var cursorCenterOffset: int; // offset from eduge to center of cursor, set in Inspector
private var lastPosition : Vector3; // Where the mouse position was last
//----------------------------------------------
function Start () {
InitGraph();
SetXRange(pXMin, pXMax);
SetYRange(pYMin, pYMax);
pPlotXScale = axisWidth;
pPlotYScale = axisHeight;
SetupScale();
theCursor.active = false;
lastPosition = Input.mousePosition;
cursorCenterOffset = 5;
}
//----------------------------------------------
// only used for smart cursor
function Update() {
var mousePos = Input.mousePosition;
theRay = mainCamera.ScreenPointToRay(mousePos);
// we need to hit a collider
if (!Physics.Raycast(theRay, hit, 100)){
if (theCursor.active == true) {
theCursor.transform.position.x = -999.0;
Screen.showCursor = true;
theCursor.active = false;
return;
}
}
// We need to hit a rigidbody
if (!hit.rigidbody) {
if (theCursor.active == true) {
theCursor.transform.position.x = -999.0;
Screen.showCursor = true;
theCursor.active = false;
return;
}
}
if (hit.transform == transform) {
// If the mouse has moved since the last update
if (mousePos != lastPosition) {
lastPosition = mousePos;
// Get mouse X and Y position as a percentage of screen width and height
Screen.showCursor = false;
theCursor.active = true;
MoveMouse(mousePos.x - (Screen.width / 2.0), mousePos.y - (Screen.height / 2.0));
UpdateCursorCoordinates(mousePos.x - (Screen.width / 2.0), mousePos.y - (Screen.height / 2.0));
}
}
}
// ------------------------------------------
function InitGraph () {
dotColors = blankTexture.GetPixels(0);
graphTexture.SetPixels(dotColors, 0);
graphTexture.Apply();
renderer.material.mainTexture = graphTexture;
}
//----------------------------------------------
function DrawGraph (theData: Array) {
dotColors = blankTexture.GetPixels(0);
graphTexture.SetPixels(dotColors, 0);
SetupScale();
for (i = 0; i < theData.length; i++) {
PlotPoint(theData[i].x, theData[i].y, false);
}
graphTexture.Apply();
renderer.material.mainTexture = graphTexture;
}
//----------------------------------------------
function PlotPoint (xx, yy: float, redraw: boolean) {
yy = Mathf.Round((yy * pNewYScale) - (pPlotYRange[0] * pNewYScale)) + yOffset;
xx = Mathf.Round((xx * pNewXScale) - (pPlotXRange[0] * pNewXScale)) + xOffset;
symbolHalfWidth = Mathf.Round(symbolSize / 2.0);
symbolHalfHeight = Mathf.Round(symbolSize / 2.0);
if (xx > spriteWidth - symbolHalfWidth)
return;
if (yy > spriteHeight - symbolHalfHeight)
return;
if (xx < xOffset)
return;
if (yy < yOffset)
return;
//Circle(graphTexture, xx, yy, symbolHalfWidth, Color.black); // draw circle
dRect = Rect(xx - symbolHalfWidth, yy - symbolHalfHeight, dotSymbol.width, dotSymbol.height); // draw symbol
dotColors = dotSymbol.GetPixels(0);
graphTexture.SetPixels(xx - symbolHalfWidth, yy - symbolHalfHeight, dotSymbol.width, dotSymbol.height, dotColors, 0);
if (redraw)
graphTexture.Apply();
}
//----------------------------------------------
function SetXRange (tMin, tMax: float) {
pXMin = tMin;
pXMax = tMax;
pPlotXRange = [tMin, tMax];
}
//----------------------------------------------
function SetYRange (tMin, tMax: float) {
pYMin = tMin;
pYMax = tMax;
pPlotYRange = [tMin, tMax];
}
//----------------------------------------------
// must call before plotting first point if anything has changed since InitGraph
function SetupScale () {
pNewXScale = pPlotXScale/(pPlotXRange[1] - pPlotXRange[0]);
pNewYScale = pPlotYScale/(pPlotYRange[1] - pPlotYRange[0]);
}
//----------------------------------------------
// "texture" is the texture you want to draw the circle in
// "x" and "y" are the x and y coordinates of the midpoint of the circle
// "radius" is the radius of the circle in pixels
// "color" is the color of the circle
function Circle (tex : Texture2D, cx : int, cy : int, r : int, col : Color) {
var y = r;
var d = 1/4 - r;
var end = Mathf.Ceil(r/Mathf.Sqrt(2));
for (x = 0; x <= end; x++) {
tex.SetPixel(cx+x, cy+y, col);
tex.SetPixel(cx+x, cy-y, col);
tex.SetPixel(cx-x, cy+y, col);
tex.SetPixel(cx-x, cy-y, col);
tex.SetPixel(cx+y, cy+x, col);
tex.SetPixel(cx-y, cy+x, col);
tex.SetPixel(cx+y, cy-x, col);
tex.SetPixel(cx-y, cy-x, col);
d += 2*x+1;
if (d > 0) {
d += 2 - 2*y--;
}
}
}
//----------------------------------------------
function MoveMouse(mousePosX : float, mousePosY : float) {
theCursor.transform.position.x = mousePosX - cursorCenterOffset;
theCursor.transform.position.y = mousePosY + cursorCenterOffset;
}
//----------------------------------------------
function UpdateCursorCoordinates (mousePosX : float, mousePosY : float) {
var tLoc: Vector2;
var tempNewXScale: float;
var tempNewYScale: float;
tLoc.x = mousePosX - transform.position.x;
tLoc.y = mousePosY - transform.position.y;
tempNewYScale = pNewYScale;
tLoc.y = (tLoc.y + (pPlotYRange[0] * tempNewYScale) - yOffset) / tempNewYScale;
tempNewXScale = pNewXScale;
tLoc.x = (tLoc.x + (pPlotXRange[0] * tempNewXScale) - xOffset) / tempNewXScale;
if (tLoc.x < pXMin)
tLoc.x = pXMin;
if (tLoc.y < pYMin)
tLoc.y = pYMin;
graphCoordinates.text = "t = " + tLoc.x.ToString("F2") + " sec, y = " + tLoc.y.ToString("F3") + " m";
}
It uses EZ GUI, hence the sprite reference, but should work with any 2D texture. It also includes a “smart cursor” that you can move over the graph and display the coordinates. It currently draws either predefined symbols or circles. It could easily be modified to draw a line between two points. Check out the Unify wiki for line-drawing code.