I’ve completed engaged on my 3D renderer from the earlier questions for now. I’ve created a category library that handles the sport logic.
Again then, I moved the digital camera straight, however now there is a participant. So I take advantage of the Translate technique to maneuver the participant by the delta values first, after which transfer the digital camera afterward.
To make it clear that that is the participant, I’ve quickly positioned a sq. as an object.
There are at present two digital camera fashions: FirstPerson and BehindPerson. Within the latter case, there’s an issue with the calculation. The problem lies in MoveBodyTo. The x, y, and z positions aren’t including up.
If I assigned absolutely the values (p.X = newPos.X) as a substitute of utilizing p.X += delta.X, the place turns into big.
May somebody assist me with the method?
I am utilizing a right-handed coordinate system (+x is true, +y is up, and +z factors out of the display screen in the direction of the viewer).
Hooked up are all of the courses you want for compiling, although they’re barely abbreviated. However an important components are included.
Recreation.cs
utilizing System;
utilizing System.Collections.Generic;
public sealed class Recreation
{
personal readonly Dictionary<string, IEnumerable<Face>> _allSceneObjects;
public Point3 CameraPos { get; personal set; }
/// <abstract>
/// In levels
/// </abstract>
public float CameraYaw { get; personal set; }
/// <abstract>
/// In levels
/// </abstract>
public float CameraPitch { get; personal set; }
personal Participant _player;
personal enum Digital camera
{
FirstPerson,
BehindPerson
}
personal Digital camera _cameraPlace = Digital camera.BehindPerson;
public Recreation(int screenWidth, int screenHeight)
{
this._allSceneObjects = new Dictionary<string, IEnumerable<Face>>();
this.CameraPos = new Point3(0.0f, 0.0f, 800.0f);
this.CameraYaw = 0.0f;
this.CameraPitch = 0.0f;
IEnumerable<Face> playerBody = WorldBuilder.CreatePlayerBody(new Point3(0.0f, 0.0f, 785.0f));
this._allSceneObjects.Add("PlayerBody", playerBody);
this._player = new Participant(new Point3(0.0f, 0.0f, 785.0f), 5.0f);
}
public void TranslatePlayer(float leftRight, float upDown, float forwardBack)
{
float yawInRad = this.CameraYaw * (float)(Math.PI / 180.0);
float forwardX = (float)Math.Sin(yawInRad) * forwardBack;
float forwardZ = -(float)Math.Cos(yawInRad) * forwardBack;
float rightX = (float)Math.Cos(yawInRad) * leftRight;
float rightZ = (float)Math.Sin(yawInRad) * leftRight;
Point3 nextPos = new Point3(this._player.Pos.X + forwardX + rightX,
this._player.Pos.Y + upDown,
this._player.Pos.Z + forwardZ + rightZ);
if (this._player.CanMoveTo(nextPos, this._allSceneObjects))
{
this._player.Pos = nextPos;
if (this._allSceneObjects.TryGetValue("PlayerBody", out IEnumerable<Face> playerFaces))
{
this._player.MoveBodyTo(nextPos, ref playerFaces);
}
UpdateCameraPosition();
}
}
personal void UpdateCameraPosition()
{
if (this._cameraPlace == Digital camera.FirstPerson)
{
this.CameraPos = this._player.Pos;
}
else if (this._cameraPlace == Digital camera.BehindPerson)
{
float yawInRad = this.CameraYaw * (float)(Math.PI / 180.0);
float dist = 10.0f; // Distance behind the participant
this.CameraPos = new Point3(this._player.Pos.X + (float)Math.Sin(yawInRad) * dist,
this._player.Pos.Y + 1.0f, // Slightly over the shoulder
this._player.Pos.Z + (float)Math.Cos(yawInRad) * dist);
}
}
}
Participant.cs
utilizing System.Collections.Generic;
utilizing System.Linq;
inner sealed class Participant
{
inner Point3 Pos { get; set; }
inner float Radius { get; set; }
inner Participant(Point3 pos, float radius)
{
this.Pos = pos;
this.Radius = radius;
}
inner bool CanMoveTo(Point3 newPos, Dictionary<string, IEnumerable<Face>> sceneObjects)
{
float minX = newPos.X - Radius;
float maxX = newPos.X + Radius;
float minY = newPos.Y - Radius;
float maxY = newPos.Y + Radius;
float minZ = newPos.Z - Radius;
float maxZ = newPos.Z + Radius;
foreach (KeyValuePair<string, IEnumerable<Face>> entry in sceneObjects)
{
if (entry.Key.Comprises("Outer") || entry.Key == "PlayerBody")
{
proceed; // Don't take account of the 2nd wall or the participant itself
}
foreach (Face f in entry.Worth)
{
float fMinX = f.Factors.Min(p => p.X);
float fMaxX = f.Factors.Max(p => p.X);
float fMinY = f.Factors.Min(p => p.Y);
float fMaxY = f.Factors.Max(p => p.Y);
float fMinZ = f.Factors.Min(p => p.Z);
float fMaxZ = f.Factors.Max(p => p.Z);
if (minX <= fMaxX && maxX >= fMinX &&
minY <= fMaxY && maxY >= fMinY &&
minZ <= fMaxZ && maxZ >= fMinZ)
{
return false;
}
}
}
return true;
}
public void MoveBodyTo(Point3 newPos, ref IEnumerable<Face> playerFaces)
{
Point3 delta = new Point3(newPos.X - Pos.X, newPos.Y - Pos.Y, newPos.Z - Pos.Z);
this.Pos = newPos;
foreach (Face face in playerFaces)
{
foreach (Point3 p in face.Factors)
{
p.X += delta.X;
p.Y += delta.Y;
p.Z += delta.Z;
}
}
}
}
Point3.cs
public sealed class Point3
{
public float X { get; set; }
public float Y { get; set; }
public float Z { get; set; }
public Point3(float x, float y, float z)
{
this.X = x;
this.Y = y;
this.Z = z;
}
}
Vector3.cs
utilizing System;
public sealed class Vector3
{
public float X { get; inner set; }
public float Y { get; inner set; }
public float Z { get; inner set; }
personal const double _180divPi = 180.0 / Math.PI;
personal const double _Pidiv180 = Math.PI / 180.0;
public Vector3(float x, float y, float z)
{
this.X = x;
this.Y = y;
this.Z = z;
}
inner static Vector3 CrossProductAndNormalize(Vector3 v1, Vector3 v2)
{
float nx = (v1.Y * v2.Z) - (v1.Z * v2.Y);
float ny = (v1.Z * v2.X) - (v1.X * v2.Z);
float nz = (v1.X * v2.Y) - (v1.Y * v2.X);
double size = Math.Sqrt(nx * nx + ny * ny + nz * nz);
if (size == 0.0)
{
return new Vector3(0f, 0f, 0f);
}
return new Vector3((float)(nx / size), (float)(ny / size), (float)(nz / size));
}
inner static float DotProduct(Vector3 v1, Vector3 v2)
{
return (v1.X * v2.X) + (v1.Y * v2.Y) + (v1.Z * v2.Z);
}
public void Negate()
{
this.X = -X;
this.Y = -Y;
this.Z = -Z;
}
}
Face.cs
utilizing System;
utilizing System.Collections.Generic;
public sealed class Face
{
public Checklist<Point3> Factors { get; }
public Vector3 Normalenvektor { get; set; }
/// <abstract>
/// Specifies whether or not the article ought to be rotated together with the scene within the render loop. For objects that ought to stay stationary within the scene (for instance, a light-weight bulb), move true.
/// </abstract>
public bool IgnoreObjectRotation { get; set; }
public SKColor? BaseColor { get; set; } // SkiaSharp
public Face(Checklist<Point3> pointsList, bool ignoreObjectRotation)
{
this.Factors = pointsList;
this.Normalenvektor = CalculateFaceNormalVector();
this.IgnoreObjectRotation = ignoreObjectRotation;
this.BaseColor = null;
}
public Face(Checklist<Point3> pointsList, bool ignoreObjectRotation, SKColor baseColor)
{
this.Factors = pointsList;
this.Normalenvektor = CalculateFaceNormalVector();
this.IgnoreObjectRotation = ignoreObjectRotation;
this.BaseColor = baseColor;
}
personal Vector3 CalculateFaceNormalVector()
{
if (this.Factors != null && this.Factors.Depend >= 3)
{
Point3 p0 = this.Factors[0];
Point3 p1 = this.Factors[1];
Vector3 v1 = new Vector3(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
for (int i = 2; i < this.Factors.Depend; i++)
{
Point3 p2 = this.Factors[i];
Vector3 v2 = new Vector3(p2.X - p0.X, p2.Y - p0.Y, p2.Z - p0.Z);
Vector3 testNormale = Vector3.CrossProductAndNormalize(v1, v2);
if (Math.Abs(testNormale.X) > 0.001f || Math.Abs(testNormale.Y) > 0.001f || Math.Abs(testNormale.Z) > 0.001f)
{
return testNormale;
}
}
}
return new Vector3(0.0f, 0.0f, 1.0f);
}
inner void CheckNormalVectorDirectionAndInvertIfNecessary(Vector3 objectCenter)
{
Point3 p0 = this.Factors[0];
Vector3 centerToPlane = new Vector3(p0.X - objectCenter.X, p0.Y - objectCenter.Y, p0.Z - objectCenter.Z);
// If the conventional vector factors towards the within of the article, we flip it
if (Vector3.DotProduct(this.Normalenvektor, centerToPlane) < 0.0F)
{
this.Normalenvektor.Negate();
}
}
}
SKColor, so you may compile simply (with out putting in SkiaSharp)
public class SKColor
{
personal byte R;
personal byte G;
personal byte B;
public SKColor(byte r, byte g, byte b)
{
this.R = r;
this.G = g;
this.B = b;
}
}
WorldBuilder.cs
utilizing System.Collections.Generic;
inner sealed class WorldBuilder
{
inner static IEnumerable<Face> CreatePlayerBody(Point3 pos)
{
Checklist<Face> physique = new Checklist<Face>();
float dimension = 1.0f;
Checklist<Point3> frontPoints = new Checklist<Point3>()
{
new Point3(pos.X - dimension, pos.Y - dimension, pos.Z - dimension - 4.0F),
new Point3(pos.X + dimension, pos.Y - dimension, pos.Z - dimension - 4.0F),
new Point3(pos.X + dimension, pos.Y + dimension, pos.Z - dimension - 4.0F),
new Point3(pos.X - dimension, pos.Y + dimension, pos.Z - dimension - 4.0F)
};
Face entrance = new Face(frontPoints, false, new SKColor(255, 0, 0));
entrance.Normalenvektor = new Vector3(0, 0, 1.0F);
physique.Add(entrance);
return physique;
}
}


