Rotation Matrix to Euler Angles in Degrees - c#

I have this function to convert Euler Angles to a rotation matrix but I would like to reverse it and get the Euler Angles when I only have the rotation matrix.
The reason for it is I want to be able to set an objects transform using a transform matrix then I would like to update that objects Euler rotation variable that is in degrees. (I have a function that calculate the rotation matrix from the transform matrix)
public static Mat4 RotMat(Vec3 _rot)
{
double rx = Math2.degToRad(_rot.x);
double[,] trmx = new double[4, 4] { { 1, 0, 0, 0 }, { 0, Math.Cos(rx), Math.Sin(rx), 0 }, { 0, -Math.Sin(rx), Math.Cos(rx), 0 }, { 0, 0, 0, 1 } };
Mat4 rmx = new Mat4(trmx);
double ry = Math2.degToRad(_rot.y);
double[,] trmy = new double[4, 4] { { Math.Cos(ry), 0, -Math.Sin(ry), 0 }, { 0, 1, 0, 0 }, { Math.Sin(ry), 0, Math.Cos(ry), 0 }, { 0, 0, 0, 1 } };
Mat4 rmy = new Mat4(trmy);
double rz = Math2.degToRad(_rot.z);
double[,] trmz = new double[4, 4] { { Math.Cos(rz), Math.Sin(rz), 0, 0 }, { -Math.Sin(rz), Math.Cos(rz), 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } };
Mat4 rmz = new Mat4(trmz);
return (rmx * rmy * rmz);
}
This is an attempt based on some code I found but does not always give me the expected result, it works sometimes (I know there is the gimbal lock issue with euler angles so maybe this is a futile attempt ).
public static Vec3 GetRot(Mat4 _tm)
{
Mat4 rm = GetRotMat(_tm);
double sy = Math.Sqrt(rm[0, 0] * rm[0, 0] + rm[1, 0] * rm[1, 0]);
bool singular = sy < 1e-6; // If
double x, y, z;
if (!singular)
{
x = Math.Atan2(rm[2, 1], rm[2, 2]);
y = Math.Atan2(-rm[2, 0], sy);
z = Math.Atan2(rm[1, 0], rm[0, 0]);
}
else
{
x = Math.Atan2(-rm[1, 2], rm[1, 1]);
y = Math.Atan2(-rm[2, 0], sy);
z = 0;
}
x = Math2.radToDeg(x);
y = Math2.radToDeg(y);
z = Math2.radToDeg(z);
return new Vec3(x, y, z) * -1;
}

Related

How to correct weird projection flickering? c#

I have created a spinning cube and it's working fine except the weird flickering caused by clearing the picturebox.
This is my first 3D project and I have 0 experience in this.
I have recreated javidx9's code in c#
c# Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using static System.Math;
using static _3DTutorial1.Form1.Tools1;
namespace _3DTutorial1
{
public partial class Form1 : Form
{
private static PictureBox pictureBox1 = new PictureBox();
private static mesh meshCube;
//Projection Matrix
private static matrix4x4 matrixProjection;
private static float fNear = 0.1f;
private static float fFar = 1000;
private static float fFov = 90;
private static float fAspectRatio = (float)1000 / 1000;//Height / Width;
private static float fFovRad = 1 / (float)Tan(fFov * 0.5 / 180 * PI);
//Rotation
private static float fTheta = 0;
private static matrix4x4 matrixRotationZ;
private static matrix4x4 matrixRotationX;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Width = 1000;
Height = 1000;
pictureBox1.Dock = DockStyle.Fill;
pictureBox1.BackColor = Color.Black;
Controls.Add(pictureBox1);
timer1.Interval = 20;
meshCube = Create_mesh(
//SOUTH
Create_triangle(Create_vector3d(0, 0, 0), Create_vector3d(0, 1, 0), Create_vector3d(1, 1, 0)),
Create_triangle(Create_vector3d(0, 0, 0), Create_vector3d(1, 1, 0), Create_vector3d(1, 0, 0)),
//EAST
Create_triangle(Create_vector3d(1, 0, 0), Create_vector3d(1, 1, 0), Create_vector3d(1, 1, 1)),
Create_triangle(Create_vector3d(1, 0, 0), Create_vector3d(1, 1, 1), Create_vector3d(1, 0, 1)),
//NORTH
Create_triangle(Create_vector3d(1, 0, 1), Create_vector3d(1, 1, 1), Create_vector3d(0, 1, 1)),
Create_triangle(Create_vector3d(1, 0, 1), Create_vector3d(0, 1, 1), Create_vector3d(0, 0, 1)),
//WEST
Create_triangle(Create_vector3d(0, 0, 1), Create_vector3d(0, 1, 1), Create_vector3d(0, 1, 0)),
Create_triangle(Create_vector3d(0, 0, 1), Create_vector3d(0, 1, 0), Create_vector3d(0, 0, 0)),
//TOP
Create_triangle(Create_vector3d(0, 1, 0), Create_vector3d(0, 1, 1), Create_vector3d(1, 1, 1)),
Create_triangle(Create_vector3d(0, 1, 0), Create_vector3d(1, 1, 1), Create_vector3d(1, 1, 0)),
//BOTTOM
Create_triangle(Create_vector3d(1, 0, 1), Create_vector3d(0, 0, 1), Create_vector3d(0, 0, 0)),
Create_triangle(Create_vector3d(1, 0, 1), Create_vector3d(0, 0, 0), Create_vector3d(1, 0, 0))
);
//Projection Matrix
matrixProjection = Create_matrix4x4(
(0, 0, fAspectRatio * fFovRad),
(1, 1, fFovRad),
(2, 2, fFar / (fFar - fNear)),
(3, 2, (-fFar * fNear) / (fFar - fNear)),
(2, 3, 1),
(3, 3, 0)
);
}
private void Form1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyCode == Keys.X)
{
timer1.Start();
}
}
private void timer1_Tick(object sender, EventArgs e)
{
Graphics g = pictureBox1.CreateGraphics();
//Rotation
fTheta += 0.01f;
matrixRotationZ = Create_matrix4x4(
(0, 0, (float)Cos(fTheta)),
(0, 1, (float)Sin(fTheta)),
(1, 0, (float)-Sin(fTheta)),
(1, 1, (float)Cos(fTheta)),
(2, 2, 1),
(3, 3, 1)
);
matrixRotationX = Create_matrix4x4(
(0, 0, 1),
(1, 1, (float)Cos(fTheta)),
(1, 2, (float)Sin(fTheta)),
(2, 1, (float)-Sin(fTheta)),
(2, 2, (float)Cos(fTheta)),
(3, 3, 1)
);
//Clear / Draw
List<triangle> Ready2DrawCube = new List<triangle>();
//Calculate Draw
foreach (var item in meshCube.tris)
{
triangle triangleProjected, triangleTranslated, triangleRotatedZ, triangleRotatedZX;
triangleRotatedZ = Create_triangle(Create_vector3d(), Create_vector3d(), Create_vector3d());
triangleRotatedZX = Create_triangle(Create_vector3d(), Create_vector3d(), Create_vector3d());
triangleProjected = Create_triangle(Create_vector3d(), Create_vector3d(), Create_vector3d());
triangleRotatedZ.p[0] = MultiplyMatrixVector(item.p[0], matrixRotationZ);
triangleRotatedZ.p[1] = MultiplyMatrixVector(item.p[1], matrixRotationZ);
triangleRotatedZ.p[2] = MultiplyMatrixVector(item.p[2], matrixRotationZ);
triangleRotatedZX.p[0] = MultiplyMatrixVector(triangleRotatedZ.p[0], matrixRotationX);
triangleRotatedZX.p[1] = MultiplyMatrixVector(triangleRotatedZ.p[1], matrixRotationX);
triangleRotatedZX.p[2] = MultiplyMatrixVector(triangleRotatedZ.p[2], matrixRotationX);
triangleTranslated = triangleRotatedZX;
triangleTranslated.p[0].z = triangleRotatedZX.p[0].z + 3.0f;
triangleTranslated.p[1].z = triangleRotatedZX.p[1].z + 3.0f;
triangleTranslated.p[2].z = triangleRotatedZX.p[2].z + 3.0f;
triangleProjected.p[0] = MultiplyMatrixVector(triangleTranslated.p[0], matrixProjection);
triangleProjected.p[1] = MultiplyMatrixVector(triangleTranslated.p[1], matrixProjection);
triangleProjected.p[2] = MultiplyMatrixVector(triangleTranslated.p[2], matrixProjection);
//Scale into view
triangleProjected.p[0].x += 1; triangleProjected.p[0].y += 1;
triangleProjected.p[1].x += 1; triangleProjected.p[1].y += 1;
triangleProjected.p[2].x += 1; triangleProjected.p[2].y += 1;
triangleProjected.p[0].x *= 0.5f * Width; triangleProjected.p[0].y *= 0.5f * Width;
triangleProjected.p[1].x *= 0.5f * Width; triangleProjected.p[1].y *= 0.5f * Width;
triangleProjected.p[2].x *= 0.5f * Width; triangleProjected.p[2].y *= 0.5f * Width;
//Done
Ready2DrawCube.Add(triangleProjected);
}
//Draw Triangles
g.Clear(Color.Black);
foreach (var item in Ready2DrawCube)
{
DrawTriangle(
(int)item.p[0].x, (int)item.p[0].y,
(int)item.p[1].x, (int)item.p[1].y,
(int)item.p[2].x, (int)item.p[2].y,
Pens.White
);
}
}
public class Tools1
{
private static Graphics g = pictureBox1.CreateGraphics();
public static void DrawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, Pen p)
{
g.DrawLine(p, new Point(x1, y1), new Point(x2, y2));
g.DrawLine(p, new Point(x2, y2), new Point(x3, y3));
g.DrawLine(p, new Point(x3, y3), new Point(x1, y1));
}
public static vector3d MultiplyMatrixVector(vector3d _i, matrix4x4 _m)
{
vector3d o_ = Create_vector3d();
o_.x = _i.x * _m.m[0, 0] + _i.y * _m.m[1, 0] + _i.z * _m.m[2, 0] + _m.m[3, 0];
o_.y = _i.x * _m.m[0, 1] + _i.y * _m.m[1, 1] + _i.z * _m.m[2, 1] + _m.m[3, 1];
o_.z = _i.x * _m.m[0, 2] + _i.y * _m.m[1, 2] + _i.z * _m.m[2, 2] + _m.m[3, 2];
float w = _i.x * _m.m[0, 3] + _i.y * _m.m[1, 3] + _i.z * _m.m[2, 3] + _m.m[3, 3];
if (w != 0)
{
o_.x /= w;
o_.y /= w;
o_.z /= w;
}
return o_;
}
public static vector3d Create_vector3d(float _x = 0, float _y = 0, float _z = 0)
{
vector3d v_ = new vector3d();
v_.x = _x;
v_.y = _y;
v_.z = _z;
return v_;
}
public static triangle Create_triangle(params vector3d[] _p)
{
triangle t_ = new triangle();
t_.p = _p;
return t_;
}
public static mesh Create_mesh(params triangle[] _t)
{
mesh m_ = new mesh();
m_.tris = _t.ToList();
return m_;
}
public static matrix4x4 Create_matrix4x4(params (int x, int y, float value)[] inputs)
{
matrix4x4 m_ = new matrix4x4();
m_.m = new float[4, 4];
foreach (var item in inputs)
{
m_.m[item.x, item.y] = item.value;
}
return m_;
}
public struct vector3d
{
public float x, y, z;
}
public struct triangle
{
public vector3d[] p;
}
public struct mesh
{
public List<triangle> tris;
}
public struct matrix4x4
{
public float[,] m;
};
}
}
}
I tried storing the cube with the calculated parameters, so I could draw it at once.
This was my only idea..

Saving a 2D array as JSON

I Have problem to save my simulation into JSON File.
the basics I make a moving ship. in the world space there will be a probe button that will provide information about the ship. I want to save that information into JSON.
Anyone know how to do that. I am new in Unity.
In button () I want to save the ship information (eg. position, depthsea, windspeed, temperature,flow
public class test : MonoBehaviour
{
// Start is called before the first frame update
public GameObject Ship;
public GameObject hole;
public GameObject turtle;
public GameObject panelhole;
public GameObject panelturtle;
public RectTransform shipvalue;
//public RectTransform flowvalue;
//public RectTransform windspeedvalue;
//public RectTransform temperaturevalue;
//public RectTransform depthvalue;
public Vector3 offset;
public RectTransform Basicobject; //parent
//public static bool captureAllKeyboardInput = false;
private bool paneloff = false;
public float duration = 1;
public int[,] grid = new int[10, 16];
public float[,] depth = new float[4, 3]
{{1.6f, 2.3f, 3.5f },
{4, 5, 6.5f},
{7, 8, 6.5f},
{7, 8, 6.5f}};
public float[,] temperaturedata = new float[10, 16]
{{0, 0, 0, 0, 0, 0, 0, 22.5f, 22.7f, 23, 23.9f, 24, 26.3f, 26.4f, 26.4f, 26.3f},
{0, 0, 0, 0, 0, 0, 22.8f, 23.2f, 23.8f, 24.4f, 25, 24.3f, 26.5f, 26.5f, 26.5f, 26.6f},
{0, 0, 0, 0, 0, 22.5f, 23.1f, 24.8f, 25.3f, 25.7f, 0, 0, 26.7f, 26.3f, 26.2f, 26.6f},
{0, 0, 0, 0, 23.2f, 23.8f, 25.1f, 25.4f, 25.9f, 0, 0, 26.8f, 26.9f, 26.5f, 26.3f, 26.3f},
{0, 0, 24.5f, 23.3f, 23.9f, 24.5f, 25.7f, 25.6f, 26.8f, 0, 0, 26.9f, 27.1f, 26.6f, 26.4f, 26.4f},
{0, 24.1f, 23.9f, 24.9f, 25.4f, 25.5f, 25.9f, 27.4f, 27.2f, 0, 0, 27, 27.2f, 26.8f, 26.4f, 26 },
{27.4f, 27.7f, 27.3f, 26.2f, 26.2f, 25.9f, 27.5f, 27.7f, 27.3f, 0, 26.8f, 27.2f, 27.2f, 26.9f, 26.4f, 26.2f},
{28.5f, 29, 27.5f, 27.3f, 27.3f, 27.5f, 27.7f, 27.7f, 27.5f, 27.2f, 27.2f, 27.4f, 27.4f, 26.9f, 26.3f, 26.7f},
{28.5f, 27.6f, 27.1f, 27, 26.5f, 27.6f, 27.6f, 27.6f, 27.7f, 27.4f, 27.8f, 27.7f, 27.7f, 27, 27, 26.6f},
{28.5f, 27.6f, 25, 27.3f, 26.8f, 27.8f, 27.3f, 27.5f, 28.1f, 27.9f, 28, 27.6f, 27.7f, 26.9f, 27.1f, 26.8f}};
public float[,] flowdata = new float[10, 16]
{{0, 0, 0, 0, 0, 0, 0, 0.4f, 0.4f, 0.6f, 0.8f, 0.6f, 0.7f, 0.4f, 0.4f, 0.4f},
{0, 0, 0, 0, 0, 0, 0.3f, 0.5f, 0.5f, 0.8f, 0.8f, 0.8f, 0.6f, 0.6f, 0.5f, 0.5f},
{0, 0, 0, 0, 0, 0.4f, 0.7f, 0.7f, 0.7f, 0.7f, 0, 0, 0.9f, 0.6f, 0.4f, 0.4f},
{0, 0, 0, 0, 0.5f, 0.5f, 0.6f, 0.7f, 0.6f, 0, 0, 0.8f, 0.8f, 0.4f, 0.3f, 0.3f},
{0, 0, 000, 0.7f, 0.6f, 0.5f, 0.7f, 1, 0.8f, 0, 0, 0.9f, 0.5f, 0.3f, 0.1f, 0.3f},
{0, 0.5f, 0.7f, 0.6f, 0.8f, 0.8f, 1.3f, 0.9f, 0.5f, 0, 0, 0.8f, 0.3f, 0.1f, 0.2f, 0.2f},
{0.6f, 0.6f, 0.6f, 0.7f, 1.1f, 0.9f, 0.8f, 0.4f, 0.3f, 0, 0.9f, 0.6f, 0.2f, 0.2f, 0.2f, 0.2f},
{0.4f, 0.4f, 0.5f, 0.5f, 0.3f, 0.4f, 0.3f, 0.2f, 0.4f, 0.2f, 0.8f, 0.3f, 0.2f, 0.2f, 0.2f, 0.1f},
{000, 0.3f, 0.5f, 0.2f, 0.2f, 0.2f, 0.2f, 0.1f, 0.2f, 0.6f, 0.6f, 0.3f, 0.3f, 0.2f, 0.2f, 0.2f},
{000, 000, 0.1f, 0.4f, 0.3f, 0.3f, 0.2f, 0.2f, 0.1f, 0.2f, 0.3f, 0.1f, 0.2f, 0.2f, 0.2f, 0.2f}};
public float[,] windspeeddata = new float[10, 12]
{{0,0,0,0,0,0,0,4,4,4,3,3},
{0,0,0,0,0,0,4,5,4,3,3,3},
{0,0,0,0,0,5,5,5,5,3,0,0},
{0,0,0,0,4,4,4,4,4,0,0,3},
{0,0,3,0,4,4,4,4,4,0,0,3},
{0,4,4,4,4,4,4,4,3,0,0,3},
{4,4,4,4,4,4,4,3,3,0,3,4},
{5,4,4,4,4,4,3,3,3,3,4,4},
{4,4,4,4,4,4,3,3,3,3,4,4},
{5,4,4,4,4,4,4,4,4,3,3,3}};
int row, column, num1, num2;
int p1;
int p2;
int[] grid2 = new int[5];
public Text shiposition = null;
public Text depthtext = null;
public Text windspeedtext = null;
public Text temperaturetext = null;
public Text flowtext = null;
//direction = Ship.transform.rotation.z;
float LastMove;
float timeIn = 0.5f;
public Vector3 direction;
float zvalue;
[Serializable]
public class ShipData
{
public int grid;
public float depth;
public float windspeed;
public float temperature;
}
[SerializeField]
private ShipData JSON_ShipData = new ShipData();
public void SaveintoJson()
{
string data = JsonUtility.ToJson(JSON_ShipData);
System.IO.File.WriteAllText(Application.persistentDataPath + "/DataCenter.json", data);
Debug.Log("Saving as JSON" + JSON_ShipData);
Debug.Log(Application.persistentDataPath);
}
void Start()
{
p1 = 9;
p2 = 0;
grid[p1, p2] = 1;
panelhole.SetActive(false);
panelturtle.SetActive(false);
Debug.Log(grid[p1, p2]);
Debug.Log(shiposition.transform.position);
}
// Update is called once per frame
void Update()
{
//Debug.Log(Ship.transform.localEulerAngles.z);
zvalue = Ship.transform.localEulerAngles.z;
if (Input.GetKeyDown(KeyCode.RightArrow))
{
StartCoroutine(Forward());
}
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
StartCoroutine(Backward());
}
if (Input.GetKeyDown(KeyCode.DownArrow))
{
StartCoroutine(Rotate(Vector3.forward, -90, 1.0f));
Debug.Log(transform.rotation.eulerAngles.z);
}
if (Input.GetKeyDown(KeyCode.UpArrow))
{
StartCoroutine(Rotate(Vector3.forward, 90, 1.0f));
Debug.Log(transform.rotation.eulerAngles.z);
}
if (Time.time - LastMove > timeIn)
{
LastMove = Time.time;
}
if (Input.GetKeyDown(KeyCode.W))
{
StartCoroutine(Rotate(Vector3.forward, 90, 1.0f));
// position(grid);
// depthsea(depth);
}
if (Input.GetKeyDown(KeyCode.A))
{
if (p2 >= 0)
{
StartCoroutine(Backward());
grid[p1, p2] = 0;
grid[p1, --p2] = 1;
//position(grid);
//depthsea(depth);
}
else
{
Debug.Log("You can't move left!!");
}
}
if (Input.GetKeyDown(KeyCode.D))
{
// z = 0
if (p2 <= 12 && zvalue == 0)
{
StartCoroutine(Forward());
grid[p1, p2] = 0;
grid[p1, ++p2] = 1;
//position(grid);
//depthsea(depth);
Debug.Log(zvalue);
}
// z = 270
else if (p2 <= 12 && zvalue == 270)
{
StartCoroutine(Forward());
grid[p1, p2] = 0;
grid[++p1, p2] = 1;
// position(grid);
//depthsea(depth);
Debug.Log(zvalue);
}
//// z = 180
else if (p2 <= 12 && zvalue == 180)
{
StartCoroutine(Forward());
grid[p1, p2] = 0;
grid[p1, --p2] = 1;
// position(grid);
//depthsea(depth);
Debug.Log(zvalue);
}
//// z = 90
else if (p2 <= 12 && zvalue == 90)
{
StartCoroutine(Forward());
grid[p1, p2] = 0;
grid[--p1, p2] = 1;
// position(grid);
//depthsea(depth);
Debug.Log(zvalue);
}
else
{
Debug.Log("You can't move right any further!!");
Debug.Log(Ship.transform.localEulerAngles.z);
}
}
if (Input.GetKeyDown(KeyCode.S))
{
StartCoroutine(Rotate(Vector3.forward, -90, 1.0f));
//position(grid);
//depthsea(depth);
}
//WebGLInput.captureAllKeyboardInput = false;
}
private void position(int[,] grid)
{
for (int i = 0; i < grid.GetLength(0); i++)
{
for (int j = 0; j < grid.GetLength(1); j++)
{
if (grid[i, j] == 1)
{
// Debug.Log("x: " + i + " y: " + j + " Grid: " + grid[i, j]);
shiposition.text = "X : " + i + " " + "Y : " + j;
shiposition.text.ToString();
PlayerPrefs.SetString("position", shiposition.text);
PlayerPrefs.Save();
Debug.Log(shiposition.text);
}
}
}
}
public void windspeed(float[,] windspeeddata)
{
for (int x = 0; x < windspeeddata.GetLength(0); x++)
{
for (int y = 0; y < windspeeddata.GetLength(1); y++)
{
if (grid[x, y] == 1)
{
windspeedtext.text = "Windspeed Level :" + windspeeddata[x, y];
}
}
}
}
public void temperature(float[,] temperaturedata)
{
for (int x = 0; x < temperaturedata.GetLength(0); x++)
{
for (int y = 0; y < temperaturedata.GetLength(1); y++)
{
if (grid[x, y] == 1)
{
//Debug.Log(temperaturedata[x, y]);
temperaturetext.text = "Temperature :" + temperaturedata[x, y] + "C";
}
}
}
}
public void flow(float[,] flowdata)
{
for (int x = 0; x < flowdata.GetLength(0); x++)
{
for (int y = 0; y < flowdata.GetLength(1); y++)
{
if (grid[x, y] == 1)
{
flowtext.text = "Flow :" + flowdata[x, y];
}
}
}
}
public void depthsea(float[,] depth)
{
for (int x = 0; x < depth.GetLength(0); x++)
{
for (int y = 0; y < depth.GetLength(1); y++)
{
if (grid[x, y] == 1)
{
depthtext.text = "Depth :" + depth[x, y];
Debug.Log(depth[x, y]);
}
}
}
}
public void moveobject()
{
shipvalue.transform.position = Ship.transform.position;
//shipvalue.transform.position.y + 0.5f;
//flowvalue.transform.position = Ship.transform.position;
//windspeedvalue.transform.position = Ship.transform.position;
//temperaturevalue.transform.position = Ship.transform.position;
//depthvalue.transform.position = Ship.transform.position;
}
public void button()
{
position(grid);
depthsea(depth);
windspeed(windspeeddata);
temperature(temperaturedata);
flow(flowdata);
moveobject();
//value.transform.position = Ship.transform.position;
//string newposition = JsonUtility.ToJson(shiposition.text);
//System.IO.File.WriteAllText(Application.persistentDataPath + "PositionData.json", newposition);
//Debug.Log(shiposition.text);
}
The JSON export itself should work that way
However, never use + "/" for system file paths. Rather use Path.Combine which inserts the correct path separator automatically
System.IO.File.WriteAllText(Path.Combine(Application.persistentDataPath, "DataCenter.json", data);
Main Problem
You are never assigning any values into the JSON_ShipData so you will always export a JSON with default values!
So first what you want is to store a Vector2Int for the position
[Serializable]
public class ShipData
{
public Vector2Int position;
public float depth;
public float windspeed;
public float temperature;
}
Then you probably would want to update the content at certain places like e.g.
private bool TryGetPosition(int[,] grid, out Vector2Int position)
{
position = default;
for (int x = 0; x < grid.GetLength(0); i++)
{
for (int y = 0; y < grid.GetLength(1); j++)
{
if (grid[x, y] == 1)
{
// store into the returned out value
position = new Vector2Int(x, y);
shiposition.text = $"X : {x} Y : {y}";
shiposition.text.ToString();
PlayerPrefs.SetInt("positionX", position.x);
PlayerPrefs.SetInt("positionY", position.y);
PlayerPrefs.Save();
Debug.Log(shiposition.text);
return true;
}
}
}
return false;
}
Note that this is also more efficient since it doesn't iterate through the rest of your grid if it already has found the position
Repeat the same for your other methods and then use them like e.g.
public void button()
{
// Check if a position is found and if yes update the json data
if(TryGetPosition(grid, out var position)
{
JSON_ShipData.position = position;
}
// Repeat the same for your other values
SaveintoJson();
}
General notes:
Before doing stuff like
grid[p1, --p2] = 1;
You should always check if your are maybe getting out of bounds e.g. like
private bool TryGoToPosition(int[,] grid, Vector2Int from, Vector2Int to)
{
if(to.x >= 0 && to.x < grid.GetLength(0) - 1 && to.y >= 0 && to.y < grid.GetLength(1) - 1)
{
grid[from.x, from.y] = 0;
grid[to.x, to.x] = 1;
}
else
{
Debug.LogWarning("Reached grid border! -> Ignored");
}
}
Then I would simply work with a Vector2Int in general instead of setting some value in a grid to 0 or 1 like
Vector2Int gridDimensions = new Vector2Int(10, 16);
public ShipData currentShipData;
public ShipData JSON_ShipData;
private bool CanGoToPosition(Vector2Int to)
{
return to.x >= 0 && to.x < gridDimensions.x - 1 && to.y >= 0 && to.y < gridDimensions.y - 1;
}
void Start()
{
currentShipData.position = new Vector2Int(9, 0);
panelhole.SetActive(false);
panelturtle.SetActive(false);
Debug.Log(JSON_ShipData.position);
Debug.Log(shiposition.transform.position);
}
void Update()
{
......
if (Input.GetKeyDown(KeyCode.A))
{
if (CanGoToPosition(JSON_ShipData.position + Vector2Int.down))
{
currentShipData.position += Vector2Int.down;
}
else
{
Debug.Log("You can't move left!!");
}
}
...
// Then after you handled user input for movement update the other data
currentShipData.windspeed = windspeedData[JSON_ShipData.position.x, JSON_ShipData.position.y];
currentShipData.flow = flowData[JSON_ShipData.position.x, JSON_ShipData.position.y];
...
}
Then for the button press you simply only copy over the current values
public void button()
{
JSON_ShipData.position = currentShipData.position;
...
SaveintoJson();
}

Marching Cubes generating holes in mesh

I'm working on a Marching Cubes implementation in Unity. My code is based on Paul Bourke's code actually with a lot of modifications, but anyway i'm checking if a block at a position is null if it is than a debug texture will be placed on it.
This is my MC script
public class MarchingCubes
{
private World world;
private Chunk chunk;
private List<Vector3> vertices = new List<Vector3> ();
private List<Vector3> normals = new List<Vector3> ();
private Vector3[] ns;
private List<int> triangles = new List<int> ();
private List<Vector2> uvs = new List<Vector2> ();
private Vector3[] positions = new Vector3[8];
private float[] corners = new float[8];
private Vector3i size = new Vector3i (16, 128, 16);
Vector3[] vertlist = new Vector3[12];
private float isolevel = 1f;
private float Corner (Vector3i pos)
{
int x = pos.x;
int y = pos.y;
int z = pos.z;
if (x < size.x && z < size.z) {
return chunk.GetValue (x, y, z);
} else {
int ix = chunk.X, iz = chunk.Z;
int rx = chunk.region.x, rz = chunk.region.z;
if (x >= size.x) {
ix++;
x = 0;
}
if (z >= size.z) {
iz++;
z = 0;
}
return chunk.region.GetChunk (ix, iz).GetValue (x, y, z);
}
}
Block block;
public Mesh MarchChunk (World world, Chunk chunk, Mesh mesh)
{
this.world = world;
this.chunk = chunk;
vertices.Clear ();
triangles.Clear ();
uvs.Clear ();
for (int x = 0; x < size.x; x++) {
for (int y = 1; y < size.y - 2; y++) {
for (int z = 0; z < size.z; z++) {
block = chunk.GetBlock (x, y, z);
int cubeIndex = 0;
for (int i = 0; i < corners.Length; i++) {
corners [i] = Corner (new Vector3i (x, y, z) + offset [i]);
positions [i] = (new Vector3i (x, y, z) + offset [i]).ToVector3 ();
if (corners [i] < isolevel)
cubeIndex |= (1 << i);
}
if (eTable [cubeIndex] == 0)
continue;
for (int i = 0; i < vertlist.Length; i++) {
if ((eTable [cubeIndex] & 1 << i) == 1 << i)
vertlist [i] = LinearInt (positions [eCons [i, 0]], positions [eCons [i, 1]], corners [eCons [i, 0]], corners [eCons [i, 1]]);
}
for (int i = 0; triTable [cubeIndex, i] != -1; i += 3) {
int index = vertices.Count;
vertices.Add (vertlist [triTable [cubeIndex, i]]);
vertices.Add (vertlist [triTable [cubeIndex, i + 1]]);
vertices.Add (vertlist [triTable [cubeIndex, i + 2]]);
float tec = (0.125f);
Vector2 uvBase = block != null ? block.UV : new Vector2 ();
uvs.Add (uvBase);
uvs.Add (uvBase + new Vector2 (0, tec));
uvs.Add (uvBase + new Vector2 (tec, tec));
triangles.Add (index + 0);
triangles.Add (index + 1);
triangles.Add (index + 2);
}
}
}
}
if (mesh == null)
mesh = new Mesh ();
mesh.Clear ();
mesh.vertices = vertices.ToArray ();
mesh.triangles = triangles.ToArray ();
mesh.uv = uvs.ToArray ();
mesh.RecalculateNormals ();
return mesh;
}
bool IsBitSet (int b, int pos)
{
return ((b & pos) == pos);
}
Vector3 LinearInt (Vector3 p1, Vector3 p2, float v1, float v2)
{
Vector3 p;
p.x = p1.x + (isolevel - v1) * (p2.x - p1.x) / (v2 - v1);
p.y = p1.y + (isolevel - v1) * (p2.y - p1.y) / (v2 - v1);
p.z = p1.z + (isolevel - v1) * (p2.z - p1.z) / (v2 - v1);
return p;
}
private static int[,] eCons = new int[12, 2] {
{ 0, 1 },
{ 1, 2 },
{ 2, 3 },
{ 3, 0 },
{ 4, 5 },
{ 5, 6 },
{ 6, 7 },
{ 7, 4 },
{ 0, 4 },
{ 1, 5 },
{ 2, 6 },
{ 3, 7 }
};
private static Vector3i[] offset = new Vector3i[8] {
new Vector3i (0, 0, 1),
new Vector3i (1, 0, 1),
new Vector3i (1, 0, 0),
new Vector3i (0, 0, 0),
new Vector3i (0, 1, 1),
new Vector3i (1, 1, 1),
new Vector3i (1, 1, 0),
new Vector3i (0, 1, 0)
};
}
I didn't put the tables in the sample, because they are the same as the ones in Bourke's code.
EDIT:
What I figured out yet is that the cell's value at the blue triangles are 0 so they don't have to be triangulated, but the cell's value under them is 1 and because of this a top triangle is created to complete the mesh.

How to use multiple passes in HLSL?

HLSL newbie question:
I'm trying to port the following MATLAB code to work on the graphics card.
function diff_im = anisodiff2D(im, num_iter, delta_t, kappa, option)
im = double(im);
% PDE (partial differential equation) initial condition.
diff_im = im;
% Center pixel distances.
dx = 1;
dy = 1;
dd = sqrt(2);
% 2D convolution masks - finite differences.
hN = [0 1 0; 0 -1 0; 0 0 0];
hS = [0 0 0; 0 -1 0; 0 1 0];
hE = [0 0 0; 0 -1 1; 0 0 0];
hW = [0 0 0; 1 -1 0; 0 0 0];
hNE = [0 0 1; 0 -1 0; 0 0 0];
hSE = [0 0 0; 0 -1 0; 0 0 1];
hSW = [0 0 0; 0 -1 0; 1 0 0];
hNW = [1 0 0; 0 -1 0; 0 0 0];
% Anisotropic diffusion.
for t = 1:num_iter
% Finite differences. [imfilter(.,.,'conv') can be replaced by conv2(.,.,'same')]
nablaN = imfilter(diff_im,hN,'conv');
nablaS = imfilter(diff_im,hS,'conv');
nablaW = imfilter(diff_im,hW,'conv');
nablaE = imfilter(diff_im,hE,'conv');
nablaNE = imfilter(diff_im,hNE,'conv');
nablaSE = imfilter(diff_im,hSE,'conv');
nablaSW = imfilter(diff_im,hSW,'conv');
nablaNW = imfilter(diff_im,hNW,'conv');
% Diffusion function.
if option == 1
cN = exp(-(nablaN/kappa).^2);
cS = exp(-(nablaS/kappa).^2);
cW = exp(-(nablaW/kappa).^2);
cE = exp(-(nablaE/kappa).^2);
cNE = exp(-(nablaNE/kappa).^2);
cSE = exp(-(nablaSE/kappa).^2);
cSW = exp(-(nablaSW/kappa).^2);
cNW = exp(-(nablaNW/kappa).^2);
elseif option == 2
cN = 1./(1 + (nablaN/kappa).^2);
cS = 1./(1 + (nablaS/kappa).^2);
cW = 1./(1 + (nablaW/kappa).^2);
cE = 1./(1 + (nablaE/kappa).^2);
cNE = 1./(1 + (nablaNE/kappa).^2);
cSE = 1./(1 + (nablaSE/kappa).^2);
cSW = 1./(1 + (nablaSW/kappa).^2);
cNW = 1./(1 + (nablaNW/kappa).^2);
end
% Discrete PDE solution.
diff_im = diff_im + ...
delta_t*(...
(1/(dy^2))*cN.*nablaN + (1/(dy^2))*cS.*nablaS + ...
(1/(dx^2))*cW.*nablaW + (1/(dx^2))*cE.*nablaE + ...
(1/(dd^2))*cNE.*nablaNE + (1/(dd^2))*cSE.*nablaSE + ...
(1/(dd^2))*cSW.*nablaSW + (1/(dd^2))*cNW.*nablaNW );
% Iteration warning.
fprintf('\rIteration %d\n',t);
end
It the moment I have it working with one pass:
texture2D Input0;
sampler2D Input0Sampler = sampler_state
{
Texture = <Input0>;
MinFilter = Point;
MagFilter = Point;
MipFilter = Point;
AddressU = Clamp;
AddressV = Clamp;
};
struct VertexShaderInput
{
float4 Position : POSITION0;
float2 TextureCoordinate : TEXCOORD0;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float2 TextureCoordinate : TEXCOORD0;
};
struct PixelShaderOutput
{
// TODO: Optionally add/remove output indices to match GPUProcessor.numOutputs
float4 Index0 : COLOR0;
};
// input texture dimensions
static float w = 1920 - 8;
static float h = 1080 - 8;
static const float2 pixel = float2(1.0 / w, 1.0 / h);
static const float2 halfPixel = float2(pixel.x / 2, pixel.y / 2);
static const float3x3 hN =
{
0, 1, 0,
0, -1, 0,
0, 0, 0
};
static const float3x3 hS =
{
0, 0, 0,
0, -1, 0,
0, 1, 0
};
static const float3x3 hE =
{
0, 0, 0,
0, -1, 1,
0, 0, 0
};
static const float3x3 hW =
{
0, 0, 0,
1, -1, 0,
0, 0, 0
};
static const float3x3 hNE =
{
0, 0, 1,
0, -1, 0,
0, 0, 0
};
static const float3x3 hSE =
{
0, 0, 0,
0, -1, 0,
0, 0, 1
};
static const float3x3 hSW =
{
0, 0, 0,
0, -1, 0,
1, 0, 0
};
static const float3x3 hNW =
{
1, 0, 0,
0, -1, 0,
0, 0, 0
};
VertexShaderOutput VertexShaderFunction(VertexShaderInput vsInput)
{
//VertexShaderOutput output;
//output.Position = vsInput.Position;
//output.TextureCoordinate = vsInput.TextureCoordinate;
VertexShaderOutput output;
vsInput.Position.x = vsInput.Position.x - 2*halfPixel.x;
vsInput.Position.y = vsInput.Position.y + 2*halfPixel.y;
output.Position = vsInput.Position;
output.TextureCoordinate = vsInput.TextureCoordinate ;
return output;
//return output;
}
float4 Convolution(VertexShaderOutput input, float3x3 kernel)
{
//PixelShaderOutput output;
float4 pixel = float4(0.0f, 0.0f, 0.0f, 0.0f);
for (int i = -1; i <= 1; ++i)
{
for (int j = -1; j <= 1; ++j)
{
pixel += kernel[i+1][j+1] * tex2D(Input0Sampler, input.TextureCoordinate + float2(i,j));
};
};
return pixel;
}
PixelShaderOutput PixelShaderFunction(VertexShaderOutput psInput)
{
PixelShaderOutput output;
output.Index0 = tex2D(Input0Sampler, psInput.TextureCoordinate);
float dx, dy, dd;
dx = 1; dy = 1; dd = pow(2, 0.5);
float delta_t = 1/7;
float4 nablaN = Convolution(psInput, hN);
float4 nablaS = Convolution(psInput, hS);
float4 nablaW = Convolution(psInput, hW);
float4 nablaE = Convolution(psInput, hE);
float4 nablaNE = Convolution(psInput, hNE);
float4 nablaSE = Convolution(psInput, hSE);
float4 nablaSW = Convolution(psInput, hSW);
float4 nablaNW = Convolution(psInput, hNW);
float4 cN = 1 / pow( 1 + (nablaN / 40), 2);
float4 cS = 1 / pow( 1 + (nablaS / 40), 2);
float4 cW = 1 / pow( 1 + (nablaW / 40), 2);
float4 cE = 1 / pow( 1 + (nablaE / 40), 2);
float4 cNE = 1 / pow( 1 + (nablaNE / 40), 2);
float4 cSE = 1 / pow( 1 + (nablaSE / 40), 2);
float4 cSW = 1 / pow( 1 + (nablaSW / 40), 2);
float4 cNW = 1 / pow( 1 + (nablaNW / 40), 2);
output.Index0 += delta_t *
(
mul(cN, nablaN) + mul(cS, nablaS) + mul(cW, nablaW) + mul(cE, nablaE) + (dd*dd)*(mul(cNE, nablaNE) + mul(cSE, nablaSE) + mul(cSW, nablaSW) + mul(cNW, nablaNW))
);
return output;
}
technique PeronaMalik
{
pass pass1
{
VertexShader = compile vs_2_0 VertexShaderFunction();
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}
The problem is I need this technique to be applied several times succesively as in the matlab code.
Should I even be using multiple passes to do this?
EDIT
if I decide to use C# to controll the passes then I could try:
byte[] theBytes = TemplateMatch.Bytes;
for (int iters = 0; iters < 3; iters++)
{
t.SetData<byte>(theBytes);
GraphicsDevice.SetRenderTarget(renOutput);
effect.Parameters["Input0"].SetValue(t);
quad.RenderFullScreenQuad(effect);
for (int i = 0; i < effect.Techniques.Count; i++)
{
for (int j = 0; j < effect.Techniques[i].Passes.Count; j++)
{
effect.Techniques[i].Passes[j].Apply();
}
}
GraphicsDevice.SetRenderTarget(null);
renOutput.GetData<float>(arrayOutput);
Buffer.BlockCopy(arrayOutput, 0, theBytes, 0, theBytes.Length);
}
But on the second iteration I get an error
You may not call SetData on a resource while it is actively set on the
GraphicsDevice. Unset it from the device before calling SetData.
on line t.SetData(theBytes);
EDIT
I've tried
byte[] theBytes = TemplateMatch.Bytes;
for (int iters = 0; iters < 3; iters++)
{
t.SetData<byte>(theBytes);
GraphicsDevice.SetRenderTarget(renOutput);
effect.Parameters["Input0"].SetValue(t);
quad.RenderFullScreenQuad(effect);
for (int i = 0; i < effect.Techniques.Count; i++)
{
for (int j = 0; j < effect.Techniques[i].Passes.Count; j++)
{
effect.Techniques[i].Passes[j].Apply();
}
}
GraphicsDevice.SetRenderTarget(null);
renOutput.GetData<float>(arrayOutput);
Buffer.BlockCopy(arrayOutput, 0, theBytes, 0, theBytes.Length);
GraphicsDevice.Textures[0] = null;
}
this seems to fix the runtime error but this gives me the same un-filtered image!
EDIT
I've modified the above matlab code so that it runs in freemat. I've stepped through the code and I've found that the problem is related to the lines like this cN = exp(-(nablaN/kappa).^2);
In the freemat version these do not evaluate to zeros (while my HLSL version does). This leads me to suspect that the problem is related to precision issues with HLSL or how I'm handling floating point arithmetic on the graphics card.
You are applying the pass but don¡t draw anything.
At least you should have the code similar to this:
for (int i = 0; i < effect.Techniques.Count; i++)
{
for (int j = 0; j < effect.Techniques[i].Passes.Count; j++)
{
effect.Techniques[i].Passes[j].Apply();
quad.RenderFullScreenQuad(effect);
}
}

Trouble detecting the number of blocks drawn on the board *XNA*

I have this code that draws the boxes on a Qbert board, how would i figure out how to detect what color blocks are stepped on?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace QBert
{
public class Map
{
public int[,] board;
public Color[] blockColors = new Color[] { Color.Blue, Color.Green }; //this makes it so it takes one time to step to get to green
Texture2D block;
public Map(Texture2D block) //draws the map of the blocks
{
this.block = block;
board = new int[8, 7]
{
{ 0, 0, 0, 1, 0, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 0 },
{ 0, 0, 1, 1, 1, 0, 0 },
{ 0, 1, 1, 1, 1, 0, 0 },
{ 0, 1, 1, 1, 1, 1, 0 },
{ 1, 1, 1, 1, 1, 1, 0 },
{ 1, 1, 1, 1, 1, 1, 1 },
{ -1, -1, -1, -1, -1, -1, -1 },
}
;
}
public Vector2 GetSquareCoords(int x, int y) //cordinates of the block
{
int ofs = block.Width / 2;
ofs *= y % 2;
return new Vector2(x * block.Width + ofs, y * 96); // 96
}
public Vector2 GetSquareCenter(int x, int y) //method for to jump on the middle of a block
{
Vector2 coords = GetSquareCoords(x, y);
return new Vector2(coords.X + block.Width / 2, coords.Y + 32); //32
}
public Vector2 GetNextSquare(bool down, bool left, Vector2 position) //this is how you jump to a next square
{
// If on even row, right is directly below and left is below and to the left
// If on odd row, left is directly below and right is below and to the right
int next_x = 0, next_y = 0;
int x = (int)position.X;
int y = (int)position.Y;
if (down)
{
next_y = y + 1;
if (left)
{
next_x = x - 1; // -1
}
else
{
next_x = x;
}
}
else
{
next_y = y - 1;
}
if (y % 2 == 0)
{
if (left)
next_x = x - 1;
else
next_x = x;
}
else
{
if (left)
next_x = x;
else
next_x = x + 1; //+1
}
if (next_x < 0)
{
next_x += 1;
}
if (next_x > 6)
{
next_x -= 1;
}
if (next_y < 0)
{
next_y += 1;
}
if (next_y > 7)
{
next_y -= 1;
}
if (board[next_y, next_x] == 0)
{
return new Vector2(x, y);
}
else
{
return new Vector2(next_x, next_y);
}
}
public void Draw(SpriteBatch spriteBatch) //draws the blocks and colors of the block
{
int drawXOffset = 30;
int drawYOffset = 60;
for (int x = 0; x < 7; x++)
for (int y = 0; y < 7; y++)
{
Vector2 coord = GetSquareCoords(x, y);
if (board[y, x] > 0)
spriteBatch.Draw(block, new Rectangle(drawXOffset + (int)coord.X, drawYOffset + (int)coord.Y, block.Width, block.Height), blockColors[board[y, x] - 1]);
}
}
}
}
I am trying to have the code detect the number of blocks drawn so that I know when they are all a certain color.
I need to make it a certain color of a block to end the game.
Right now, i have it starting out as a Blue Block Color then changing to a Green Block, how would i make it detect that if all the green blocks are stepped on that the game ends?
Somewhere in your Update method, you will want something like this:
bool finished = true;
for (int x = 0; x < 7; x++)
{
for (int y = 0; y < 7; y++)
{
if (board != 0 && board != 2) // 2 is green
{
finished = true;
break;
}
}
if (finished)
break;
}
if (finished)
{
// Move to next level
}
I think somthing like this is what you want
public Vector2 GetNextSquare(bool down, bool left, Vector2 position)
{
int x = (int)position.X;
int y = (int)position.Y;
//...other code
if (blockColors[board[next_y, next_x]] == Color.Green)
{
//End
}
else if (board[next_y, next_x] == 0)
{
return new Vector2(x, y);
}
else
{
return new Vector2(next_x, next_y);
}
}
Usually you have some sort of data representing your game field and rendering code simply renders visual representation of the field. Your game code only works with internal field representation (i.e. in your case set of cubes objects with "Color" property).
You definitely can check color on the screen, but it will require significantly more effort.
#Jaview "what do you mean, can you show me an example how i can check?"
Here is an example how to get a pixel in XNA:
ResolveTexture2D backBufferData;
backBufferData = new ResolveTexture2D(
graphics.GraphicsDevice,
graphics.GraphicsDevice.PresentationParameters.BackBufferWidth,
graphics.GraphicsDevice.PresentationParameters.BackBufferHeight,
1,
graphics.GraphicsDevice.PresentationParameters.BackBufferFormat
);
Rectangle sourceRectangle = new Rectangle(Mouse.GetState().X, Mouse.GetState().Y, 1, 1);
Color[] retrievedColor = new Color[1];
graphics.GraphicsDevice.ResolveBackBuffer(backBufferData);
backBufferData.GetData<Color>(
0,
sourceRectangle,
retrievedColor,
0,
1);
selectedColor = retrievedColor[0];

Categories

Resources