I have a script attached to the main camera in my Unity scene that enables me to draw an isometric grid centered on the origin point, using good old OpenGl Lines.
As indicated in Unity's documentation (there), I launch the drawing on the "OnPostRender" event ; problem is lines only get drawn in Game view, and not in Edit view (even with the [ExecuteInEditMode] instruction).
Is there a way to get them drawn there?
--
Btw, here is the code (C#) for the function :
void OnPostRender()
{
CreateLineMaterial();
// set the current material
lineMaterial.SetPass( 0 );
GL.Begin( GL.LINES );
GL.Color(mainColor);
// Draw x lines
for (int x = - gridSizeX / 2; x <= gridSizeX / 2; x++) {
GL.Vertex3 (- gridSizeX / 4 + x, - gridSizeX / 8, 0 - x * 0.5f);
GL.Vertex3 (gridSizeX / 4 + x, gridSizeX / 8, 0 - x * 0.5f);
}
// Draw y lines
for (int y = - gridSizeY / 2; y <= gridSizeY / 2; y++) {
GL.Vertex3 (- gridSizeY / 4 + y, gridSizeY / 8, 0 - y * 0.5f);
GL.Vertex3 (gridSizeY / 4 + y, - gridSizeY / 8, 0 - y * 0.5f);
}
GL.End();
}
God, I knew it would be like this. I got stuck on this the whole afternoon and when I eventually decide to submit a question here, I actually find the solution.
So I apologize for your wasted time.
Btw, solution was just to draw grid on the OnDrawGizmos event...
Related
Is there any possibility to plot a circle in a WindowsForm Chart?
A method-call as follows would be really nice!
Graph.Series["circle"].Circle.Add(centerX, centerY, radius);
Well, I created myself a work around.
Maybe it helps someone
public void DrawCircle(Chart Graph, double centerX, double centerY, double radius, int amountOfEdges)
{
string name = "circle_" + centerX + centerY + radius + amountOfEdges;
// Create new data series
if (Graph.Series.IndexOf(name) == -1)
Graph.Series.Add(name);
// preferences of the line
Graph.Series[name].ChartType = SeriesChartType.Spline;
Graph.Series[name].Color = Color.FromArgb(0, 0, 0);
Graph.Series[name].BorderWidth = 1;
Graph.Series[name].IsVisibleInLegend = false;
// add line segments (first one also as last one)
for (int k = 0; k <= amountOfEdges; k++)
{
double x = centerX + radius * Math.Cos(k * 2 * Math.PI / amountOfEdges);
double y = centerY + radius * Math.Sin(k * 2 * Math.PI / amountOfEdges);
Graph.Series[name].Points.AddXY(x, y);
}
}
You can call it for example via
DrawCircle(Graph, 5, 4, 3, 30);
Around 30 points should be enough to get a nice circle instead of a polygon, but depends on the size of your chart.
I'm very new to c# and running into a problem while trying to program and visualize the Mandelbrotset.
I have created a 400 by 400 panel and want to use this to graph the set. I want my graph to go from -2 to 2 on both axes so I'm using a scale of 0.01. When looking at my code, I think the paint method should work; the coordinates are converted in the correct way it seems. The problem is that the graph is not fully shown on the panel while running. (0,0) is somewhere in the lower right corner, removing much of the coordinates in that corner.
Below is the function used to draw the graph on the panel. Did I make a mistake in coding the coordinates this way? Or am I misunderstanding how coordinates work in a panel?
for (int xco =0; xco<400; xco++)
{
for (int yco=0; yco<400; yco++)
{
double x = (xco - 200) * scale;
double y = (yco - 200) * scale;
int mandel = 0;
double fx = x, fy = y;
double distance = 0;
while ((mandel<max) && (distance<2))
{
double fx1 = fx;
fx = fx * fx - fy * fy + x;
fy = 2 * fx1 * fy + y;
distance = Math.Sqrt(fx * fx + fy * fy);
mandel++;
}
if (mandel%2==1)
pea.Graphics.FillRectangle(Brushes.White, xco, yco, xco + 1, yco + 1);
else
pea.Graphics.FillRectangle(Brushes.Black, xco, yco, xco + 1, yco + 1);
}
}
I was trying to map the 360 video pixel coordinate to sphere surface coordinate but I couldn't get right result... It just mapped to the wrong position I already know the points of the XY data for 360 video pixels.
how map 2d grid points (x,y) onto sphere as 3d points (x,y,z)
I checked this link and I copied method from this but what I'm getting is not mapped to the desired position.
How can I get radius from the pixels?
I am not sure if I'm passing right radius for imageRadius but I thought it will be circumference/PI to get radius and the video ratio is 4096x2048. I also tried to pass the number 1 because UV is 0-1 but it was not right...
Is Method wrong?
Maybe the method is wrong. I passed random numbers into the imageRadius but couldn't get the right position... If I make X to negative number the seems like little bit closer to result....?
Current Result
https://youtu.be/t0I7Hlb-tbk
It mapped to up right position with the method that I found online...
Project File
https://drive.google.com/a/swordfish-sf.com/file/d/0B45RYzVs0t0_VVdaaHdmNHRWTk0/view?usp=sharing
If somebody can check the Unity project file that will be great...
Current Code
public class mapScript : MonoBehaviour {
public int input = 4098;
float imageRadius = 4098f / Mathf.PI; //2098? 3072? 4098?
float radius;
public GameObject testSphere;
void Start () {
radius = this.transform.localScale.x;
}
void Update () {
imageRadius = input / Mathf.PI;
int currentFrame = (int)this.GetComponent<VideoPlayer>().frame;
testSphere.transform.position = MercatorProjection(mapVals[currentFrame,0],mapVals[currentFrame,1]);
}
Vector3 MercatorProjection(float xVal, float yVal)
{
float lon = (xVal / imageRadius);
float lat = (2 * Mathf.Atan(Mathf.Exp(yVal / imageRadius)) - Mathf.PI / 2);
float calcX = radius * Mathf.Cos(lat) * Mathf.Cos(lon);
float calcY = radius * Mathf.Cos(lat) * Mathf.Sin(lon);
float calcZ = radius * Mathf.Sin(lat);
Vector3 result = new Vector3(calcX,calcY,calcZ);
Debug.Log(result);
return result;
}
float[,] mapVals = new float[,] {
{1969.21f, 928.625f},
{1969.6f, 928.533f},
{1968.92f, 928.825f},
{1968.68f, 929f},
{1968.47f, 929.067f},
{1968.41f, 929.025f},
{1968.48f, 928.992f},
....
};
}
Thank you.
As a side note, the radius is arbitrary. The pixel coordinates only map to the directional coordinates (polar [θ] and azimuthal [ϕ] angles).
We can do this by mapping each pixel to equal θ and ϕ intervals. The diagram below illustrates a low-resolution setup:
Let us adopt the convention that, for an image of with W, ϕ = 0 corresponds to:
Even W: half way between X = floor((W - 1) / 2) and X = ceil((W - 1) / 2)
Odd W: in the middle of the pixel column at X = floor((W - 1) / 2)
The pixel row at Y maps to the equilatitudinal line at θ = (Y + 0.5) / H * π.
To map all pixels in their entirety, let X start at -0.5 instead of 0, and end at W - 0.5; likewise for Y. Since integer coordinates map to the centers of the pixel regions shown above, this allows the whole area of any particular pixel to be addressed. You may need this later on if you plan on doing multi-sampling filtering for e.g. anti-aliasing.
Code:
Vector3 Mercator(float x, float y, int w, int h)
{
// outside of valid pixel region
if (x < -0.5f || x >= w - 0.5f || y < -0.5f || y >= h - 0.5f)
return new Vector3();
float theta = (y + 0.5f) / h * Math.PI;
float phi = ((x + 0.5f) / w - 0.5f) * 2.0 * Math.PI;
float c_t = Math.Cos(theta);
return new Vector3(c_t * Math.Cos(phi), c_t * Math.Sin(phi), Math.Sin(theta));
}
... and multiply the resulting direction vector by any "radius" you like, since it has (basically) nothing to do with the mapping anyway.
Good evening, I know on the web there are similar questions and a few tutorials about it, but I'd like you to check my code and correct it. I mean, I'd like to know what's wrong with my project.
I have to draw a parabola graph given its equation on my main panel.
I also must include two buttons, zoom in and zoom out, which are used to reduce and enlarge the "view" panel's view (and so the parabola).
I was recommended to use a scale var.
This is my code:
note: x0, y0 are panel_main x center, y center.
I have x, y that are used to determine x,y from the equation.
xpc, ypc are converted for the window scale (so are pixels).
xmin, xmax are the extreme values that, with a certain scale, stay on the panel
I hope you can give me a hint, thanks a lot!
public void DisegnaParabola()
{
Graphics gs = panel_main.CreateGraphics();
pen.Color = Color.Black;
scale = (x0*2) / zoom; //Pixels equivalent to 1x or 1y
n_punti = (x0*2) / scale; //Number of x math points that are visible in window
xmin = -(n_punti / 2);
xmax = n_punti / 2;
precision = 1 / scale; //Increment of x to have 1px
if (asse_parabola.SelectedIndex == 0) //if Y axis
{
for (double i = xmin + precision; i < xmax; i += precision)
{
rifx = i - precision; //Old points
rifxpc = rifx * scale;
rify = (a * Math.Pow(rifx, 2)) + b * rifx + c;
rifypc = y0 - (rify * scale);
x = i; //New points
y = (a * Math.Pow(x, 2)) + b * x + c;
ypc = y0 - (y * scale);
gs.DrawLine(pen, (float)rifxpc, (float)rifypc, (float)xpc, (float)ypc);
}
}
else
{
scale = (y0*2) / zoom; //Pixels for 1y
n_punti = (y0*2) / scale; //Numbers of y in the window
ymin = -(n_punti / 2);
ymax = n_punti / 2;
for(double i=ymin+precision; i<ymax; i+=precision)
{
rify = y - precision;
rifypc = (y0*2) - rify * scale;
rifx = (a * Math.Pow(rify, 2)) + b * rify + c;
rifxpc = x0 + (rifx * scale);
y = i;
x = (a * Math.Pow(y, 2)) + b * y + c;
xpc = x0 + (x * scale);
gs.DrawLine(pen, (float)rifypc, (float)rifxpc, (float)ypc, (float)xpc);
}
}
lbl_canc.Visible = true;
}
Your question actually consists of several tasks and as usual the key is to take and break those apart..
One issue is getting the data, I will leave the details to you but show how to sparate it from the rest.
The next issue is to scale the data. I'll show you how to avoid this one altogether and scale the drawing tool instead.
And the third one is to draw them to a display surface. As you'll see this is really simple once the other issues are taken care of.
Let's start with the most important step: Collecting the data. You try to create and scale and draw them all in the same piece of code. This has many disadvantages..
Let's first collect the data in a suitable structure:
List<PointF> points = new List<PointF>();
List<T> is the collection of choice most of the time; certainly much nicer than arrays! In some method you should fill that list with your data, calculated from some formula.
Here is an example:
List<PointF> getPoints(float start, float end, int count, float ymax)
{
List<PointF> points = new List<PointF>();
float deltaX = (end - start) / count;
for (int i = 0; i < count; i++)
{
float x = i * deltaX;
// insert your own formula(s) here!
float y = ymax + (float)Math.Sin(x * somefactor) * ymax;
points.Add(new PointF(x, y));
}
return points;
}
Now for the second important part: How to scale the data? This can be done either when creating them; but again, separating the two taks makes them both a lot simpler.
So here is a function that, instead of scaling the data scales the Graphics object we will use to plot them:
void ScaleGraphics(Graphics g, List<PointF> data)
{
float xmax = data.Select(x => x.X).Max();
float ymax = data.Select(x => x.Y).Max();
float xmin = data.Select(x => x.X).Min();
float ymin = data.Select(x => x.Y).Min();
float width = Math.Abs(xmax - xmin);
float height = Math.Abs(ymax - ymin);
var vr = g.VisibleClipBounds;
g.ScaleTransform(vr.Width / width, vr.Height / height);
}
This method makes sure that all the data in our list will fit into the drawing surface. If you want to restrict them to a different size you can pass it in and change the code accordingly..
Finally we need to do the actual drawing. We do that where we should, that is in the Paint event of our drawing surface control..:
private void panel1_Paint(object sender, PaintEventArgs e)
{
if (points.Count < 2) return; // no lines to draw, yet
ScaleGraphics(e.Graphics, points);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
using ( Pen pen = new Pen(Color.Blue )
{ Width = 1.5f , LineJoin = LineJoin.Round, MiterLimit = 1f} )
e.Graphics.DrawLines(pen, points.ToArray());
}
I would like to create a map of the enviroment, ie. my room. I want to have a 2D representation of my room using 2D Array.
I am trying to map a room, which has coordinate start at (5,5), (10,5), (5,10) and (10,10). This is a square of size 5x5 if you ever wonder. I would like to map this into a 2D grid of 100x100 cells.
The math I am using to map is,
X' = (maxRangeX - minRangeX)*(X - minX)/(maxX - minX) + minRangeX
Y' = (maxRangeY - minRangeY)*(Y - minY)/(maxY - minY) + minRangeY
where
maxRangeX 100 maxX 10 maxRangeY 100 maxY 10
minRangeX 0 minX 5 minRangeY 0 minY 5
As you know, the way Array works is it start (0,0) at the top left, and (100,100) at the bottom right, in this case I mean. But, by using the math I showed above, it seems to map the room into a 2D array which has (0,0) start at bottom left and (100,100) ends at top right, (0,100) on top left and (100,0) on bottom right.
I want to map the room over so that the result is ordered in a structure like how array structure does.
Any help is greatly appreciated.
Update:
The idea is still as above, and here is a picture to illustrate further.
http://i.stack.imgur.com/h4Mgm.png
Using your notation:
X' = maxRangeY - ((maxRangeY - minRangeY)*(maxY-(Y - minY))/(maxY - minY) + minRangeY)
Y' = maxRangeX - ((maxRangeX - minRangeX)*(maxX-(X - minX))/(maxX - minX) + minRangeX)
The "invert" of x maps to the "invert" of y and the "invert" of y maps to the "invert" of x.
C# functions:
static int Transform(int coord, int coordMin, int newCoordMin, double factor)
{
return (newCoordMin + (int)((coord - coordMin) * factor));
}
static void Transform(int[,] arrIn, int minX, int minY, int maxX, int maxY,
out int[,] arrOut, int minRangeX, int minRangeY, int maxRangeX, int maxRangeY)
{
double factorX = (maxRangeX - minRangeX) / (maxX - minX);
double factorY = (maxRangeY - minRangeY) / (maxY - minY);
arrOut = new int[maxRangeX + 1, maxRangeY + 1];
for (int x = minX; x <= maxX; ++x)
for (int y = minY; y <= maxY; ++y)
arrOut[maxRangeY - Transform(y, minY, minRangeY, factorY), maxRangeX - Transform(x, minX, minRangeX, factorX)] = arrIn[maxX - (x - minX), maxY - (y - minY)];
}
This is working supposing the following conditions:
- the ranges on x and on y are the same for the first square and for the second, respectively
- the intermediate points in the larger square aren't calculated (interpolated)