I have a problem with my ViewBobScript, it snaps back to the lerps start position for 1 frame.
Here is a Recreation/Video of my problem:
(Due to the framerate of the video not matching up to the game it might look as if the lerp is not smooth, while it is. the problem is the snap at the beginning and end of the video and seems to occur at irregular intervals)
https://youtu.be/UOz2pQcMFjY
And here is my code:
private float aTimer;
private int viewBobPath = 1;
private float startViewBob;
private float viewBobPathTimer;
private void ViewBob()
{
startViewBob = viewBobSpeed / 2;
aTimer += Time.deltaTime;
viewBobPathTimer += Time.deltaTime;
if (aTimer > startViewBob * viewBobPath) { viewBobPath++; }
if (viewBobPathTimer > startViewBob) { viewBobPathTimer = 0; }
if (aTimer < (viewBobSpeed * 2))
{
switch (viewBobPath)
{
case 1:
playerCam.transform.localPosition = Vector3.Lerp(new Vector3(-viewBobHorizontal / 2, 0, 0), new Vector3(0, -viewBobVertical, 0), viewBobPathTimer);
break;
case 2:
playerCam.transform.localPosition = Vector3.Lerp(new Vector3(0, -viewBobVertical, 0), new Vector3(viewBobHorizontal / 2, 0, 0), viewBobPathTimer);
break;
case 3:
playerCam.transform.localPosition = Vector3.Lerp(new Vector3(viewBobHorizontal / 2, 0, 0), new Vector3(0, -viewBobVertical, 0), viewBobPathTimer);
break;
case 4:
playerCam.transform.localPosition = Vector3.Lerp(new Vector3(0, -viewBobVertical, 0), new Vector3(-viewBobHorizontal / 2, 0, 0), viewBobPathTimer);
break;
}
}
else { aTimer = 0; viewBobPathTimer = 0; viewBobPath = 1; }
}
Also, I know the unity character controller has ViewBobbing. but this is not an option for my application.
Thank you so so much for helping!
Edit: This is called from the update function, although I have tried Fixed and late update both don't change, solve or reduce the problem.
Although my script works and I'm continuing with my project, if you know why my code above didn't work/did the Snap I would appreciate knowing so I learn from it!
I would take a different approach, adding Time.deltaTime to one field, then calculating which path and what t param that field corresponds to. Mathf.Repeat is useful for this.
[SerializeField] int pathIndex;
[SerializeField] float pathT;
[SerializeField] float aTimer;
[SerializeField] float pathDuration = 1f; // how long each path takes in seconds
private void ViewBob()
{
// update aTimer but wrap around at pathDuration x 4 ( [0, 4pD) )
aTimer = Mathf.Repeat(aTimer + Time.deltaTime, pathDuration * 4f);
// How many path durations is aTimer along? ( {0, 1, 2, 3} )
pathIndex = Mathf.FloorToInt(aTimer/pathDuration);
// How far into the current path duration is aTimer? ( [0,1) )
pathT = Mathf.Repeat(aTimer, pathDuration) / pathDuration;
Vector3 fromVector;
Vector3 toVector;
// assign to/from vectors based on pathIndex
switch (pathIndex)
{
default:
case 0:
fromVector = new Vector3(-viewBobHorizontal / 2, 0, 0);
toVector = new Vector3(0, -viewBobVertical, 0);
break;
case 1:
fromVector = new Vector3(0, -viewBobVertical, 0);
toVector = new Vector3(viewBobHorizontal / 2, 0, 0);
break;
case 2:
fromVector = new Vector3(viewBobHorizontal / 2, 0, 0);
toVector = new Vector3(0, -viewBobVertical, 0);
break;
case 3:
fromVector = new Vector3(0, -viewBobVertical, 0);
toVector = new Vector3(-viewBobHorizontal / 2, 0, 0);
break;
}
// lerp position based on pathT and the to/from vectors
playerCam.transform.localPosition = Vector3.Lerp(fromVector, toVector, pathT);
}
Related
I am drawing lines on a canvas using the 'UIVertex' struct and I would like to be able to detect click events on the lines I have drawn.
Here is how I draw lines (largely inspired from this tutorial => https://www.youtube.com/watch?v=--LB7URk60A):
void DrawVerticesForPoint(Vector2 point, float angle, VertexHelper vh)
{
vertex = UIVertex.simpleVert;
//vertex.color = Color.red;
vertex.position = Quaternion.Euler(0, 0, angle) * new Vector3(-thickness / 2, 0);
vertex.position += new Vector3(unitWidth * point.x, unitHeight * point.y);
vh.AddVert(vertex);
vertex.position = Quaternion.Euler(0, 0, angle) * new Vector3(thickness / 2, 0);
vertex.position += new Vector3(unitWidth * point.x, unitHeight * point.y);
vh.AddVert(vertex);
}
Any idea?
Here is the solution I have found thanks to this post:
public bool PointIsOnLine(Vector3 point, UILineRenderer line)
{
Vector3 point1 = line.points[0];
Vector3 point2 = line.points[1];
var dirNorm = (point2 - point1).normalized;
var t = Vector2.Dot(point - point1, dirNorm);
var tClamped = Mathf.Clamp(t, 0, (point2 - point1).magnitude);
var closestPoint = point1 + dirNorm * tClamped;
var dist = Vector2.Distance(point, closestPoint);
if(dist < line.thickness / 2)
{
return true;
}
return false;
}
The UILineRenderer class is the class I have which represents my lines.
line.points[0] and line.points[1] contain the coordinates of the two points which determine the line length and position. line.thickness is the... thickness of the line :O
I'm learning OpenGL with the openTK librairy in c#.
I've managed to successefuly renderer triangles on my window,
and things are running properly.
However, the performance is terrible (running at half a fps with only 100k triangles).
My question is, is there anything that I am doing badly ?
how could I improve performances ?
for the most part, I've followed this tutorial translated from c++.
Here is the render method, called each frame :
public static void Render()
{
//render the mesh render queue to the screen and clear it
GL.UseProgram(shaderProgram.id);
//meshRenderQueue is a List<Mesh>
foreach(Mesh mesh in meshRenderQueue)
{
mesh.Draw();
}
meshRenderQueue.Clear();
}
Here is my Mesh class :
public class Mesh
{
private Vertex[] vertices;
private uint[] triangles;
private int VAO;
private int VBO;
private int EBO;
public Mesh()
{
//create lots of unoptimized triangles to test performances
int triCount = 100000;
vertices = new Vertex[3 * triCount];
for(int i = 0; i < triCount; i++)
{
vertices[3 * i + 0] = new Vertex(new Vector3(-0.5f, -0.5f, 0f));
vertices[3 * i + 1] = new Vertex(new Vector3(0.5f, -0.5f, 0f));
vertices[3 * i + 2] = new Vertex(new Vector3(0, 0.5f, 0f));
};
triangles = new uint[3 * triCount];
for (int i = 0; i < triCount; i++)
{
triangles[3 * i + 0] = 0;
triangles[3 * i + 1] = 1;
triangles[3 * i + 2] = 2;
};
SetUpMesh();
}
private void SetUpMesh()
{
//initialize the openGL buffers
VAO = GL.GenVertexArray();
VBO = GL.GenBuffer();
EBO = GL.GenBuffer();
GL.BindVertexArray(VAO);
GL.BindBuffer(BufferTarget.ArrayBuffer, VBO);
GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * 8 * 4, vertices, BufferUsageHint.StaticDraw);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, EBO);
GL.BufferData(BufferTarget.ElementArrayBuffer, triangles.Length * sizeof(int), triangles, BufferUsageHint.StaticDraw);
//vertex positions
GL.EnableVertexAttribArray(0);
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 8 * 4, 0);
//vertex normals
GL.EnableVertexAttribArray(1);
GL.VertexAttribPointer(1, 3, VertexAttribPointerType.Float, false, 8 * 4, 3 * 4);
//vertex texture coords
GL.EnableVertexAttribArray(2);
GL.VertexAttribPointer(2, 2, VertexAttribPointerType.Float, false, 8 * 4, 6 * 4);
//unbind vertex array (what for ?)
GL.BindVertexArray(0);
}
public void Draw()
{
//render the mesh with the given shader
GL.BindVertexArray(VAO);
GL.DrawElements(BeginMode.Triangles, triangles.Length, DrawElementsType.UnsignedInt, 0);
GL.BindVertexArray(0);
}
}
And finally the Vertex struct, if usefull :
public struct Vertex
{
public Vector3 position;
public Vector3 normal;
public Vector2 textureCoords;
public Vertex(Vector3 pos, Vector3 norm, Vector2 textCoords)
{
position = pos;
normal = norm;
textureCoords = textCoords;
}
public Vertex(Vector3 pos)
{
position = pos;
normal = Vector3.zero;
textureCoords = new Vector2(0, 0);
}
}
Thanks in advance for any help. cheers !
I'm trying to draw a polygon of a solid color. I'm given a vector of 2D vectors, ordered such that there will be an edge from v0 to v1 to v2 to ... to vn to v0.
Does such a primitive exist?
Credit to Stefan Agartsson for the post this answer's code is based upon.
To describe the vertices as edges instead of triangles, You can use the PrimitiveType.LineStrip instead of PrimitiveType.TriangleList you have to adjust the index and counts as well since each vertex is used only once.
BasicEffect basicEffect = new BasicEffect(device);
basicEffect.Texture = myTexture;
basicEffect.TextureEnabled = true;
VertexPositionTexture[] vert = new VertexPositionTexture[4];
vert[0].Position = new Vector3(0, 0, 0); //These connect in order
vert[1].Position = new Vector3(100, 0, 0);
vert[2].Position = new Vector3(100, 100, 0);
vert[3].Position = new Vector3(0, 100, 0);
vert[0].TextureCoordinate = new Vector2(0, 0);
vert[1].TextureCoordinate = new Vector2(1, 0);
vert[2].TextureCoordinate = new Vector2(1, 1);
vert[3].TextureCoordinate = new Vector2(0, 1);
short[] ind = new short[n+1]; // the +1 is to close the shape
for(int i = 0; i < n; i++)
ind[i] = i;
ind[n] = 0; // return to start to close.
Then in your render loop you do this:
foreach (EffectPass effectPass in basicEffect.CurrentTechnique.Passes)
{
effectPass.Apply();
device.DrawUserIndexedPrimitives<VertexPositionTexture>(
PrimitiveType.LineStrip, vert, 0, vert.Length, ind, 0, ind.Length);
}
I am working on a 3D application in WPF and having trouble with the camera. It should be possible to rotate the camera around its own axis (with other words, look around) using the mouse but I can not get it to work properly. I create the camera with the following code:
PerspectiveCamera perspectiveCamera = new PerspectiveCamera(new Point3D(0, 30, 0), new Vector3D(0, -1, 0), new Vector3D(0, 0, 1), 90);
perspectiveCamera.NearPlaneDistance = 0.001;
perspectiveCamera.FarPlaneDistance = 1000;
center = new TranslateTransform3D(0, 30, 0);
rot_x = new AxisAngleRotation3D(new Vector3D(1, 0, 0), 0);
rot_y = new AxisAngleRotation3D(new Vector3D(0, 1, 0), 0);
rot_z = new AxisAngleRotation3D(new Vector3D(0, 0, 1), 0);
zoom = new ScaleTransform3D(1, 1, 1);
Transform3DGroup t = new Transform3DGroup();
t.Children.Add(zoom);
t.Children.Add(new RotateTransform3D(rot_x));
t.Children.Add(new RotateTransform3D(rot_y));
t.Children.Add(new RotateTransform3D(rot_z));
t.Children.Add(center);
perspectiveCamera.Transform = t;
myViewport3D.Camera = perspectiveCamera;
And then I try to rotate it using the following code:
private void OnViewportMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (mouseLeftIsDown)
{
Point position = e.GetPosition(this);
double rotZAngle = (rot_z.Angle % 360) + oldLeftPosition.X - position.X;
double rotXAngle = (rot_x.Angle % 360) + position.Y - oldLeftPosition.Y;
if (rotZAngle < 0) //rotZAngle is negative, make it positive
{
rotZAngle = 360 + rotZAngle;
}
if (rotXAngle < 0) //rotXAngle is negative, make it positive
{
rotXAngle = 360 + rotXAngle;
}
rot_z.Angle = rotZAngle;
rot_x.Angle = rotXAngle;
oldLeftPosition = position;
}
}
However, it seams that the rotation is not happening around the camera and instead somehere else. The model that I load at position (0,0,0) is becoming visible after I rotate 180 degrees around the z axis which should not be the case.
What am I missing?
I use Tao Framework and I have a problem with using glLoadIdentity(), I'm loading picture in to a gluDisk successfully, I can see the picture, then when I try to change the camera's position with gluLookAt the picture I have loaded on the gluDisk is gone , instead, all I see is a color that reminds the background color of the picture I have loaded, after using debugging I saw that it happens because of the glLoadIdentity() function.
Here is the function that redraw the Disk:
Gl.glClearColor(0F, 0F, 0F, 1.0F);
while (true)
{
world.drawWorld();
Application.DoEvents();
Thread.Sleep(20);
}
here is my code for changing the lookat:
Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
Gl.glMatrixMode(Gl.GL_MODELVIEW); //Switch to the drawing perspective
Gl.glLoadIdentity();
switch (Convert.ToInt32(e.KeyChar))
{
//down arrow
case 76:
rotAngle -= 0.5f;
rotY -= 0.1f;
//rotX = 0;
break;
//up arrow
case 82:
rotAngle += 0.5f;
rotY += 0.1f;
//rotX = 0;
break;
// left arrow
case 85:
rotAngle -= 0.5f;
//rotY = 0;
rotX -= 0.1f;
break;
//right arrow
case 68:
rotAngle += 0.5f;
//rotY = 0;
rotX += 0.1f;
break;
case 'a':
xMove -= 1;
Glu.gluLookAt(xMove, yMove, zMove, xMove + 2, yMove + 2, zMove + 2, 0, 1, 0);
break;
case 'd':
xMove += 1;
Glu.gluLookAt(xMove, yMove, zMove, xMove + 2, yMove + 2, zMove + 2, 0, 1, 0);
break;
case 'w':
yMove +=1;
Glu.gluLookAt(xMove, yMove, zMove, xMove + 2, yMove + 2, zMove + 2, 0, 1, 0);
break;
case 's':
yMove -= 1;
Glu.gluLookAt(xMove, yMove, zMove, xMove + 2, yMove + 2, zMove + 2, 0, 1, 0);
break;
case 'z':
zMove += 1F;
Glu.gluLookAt(xMove, yMove, zMove, 0, 0, 0, 0, 1, 0);
break;
case 'x':
zMove -= 1F;
Glu.gluLookAt(xMove, yMove, zMove, 0, 0, 0, 0, 1, 0);
break;
case '0':
//zMove -= 1F;
Glu.gluLookAt(1, 1, 1, 0, 0, 0, 0, 1, 0);
break;
Here is my drawing code:
Gl.glClear(Gl.GL_COLOR_BUFFER_BIT);
Gl.glEnable(Gl.GL_TEXTURE_2D);
LoadTexture();
Glu.GLUquadric qobj = Glu.gluNewQuadric();
Glu.gluQuadricTexture(qobj, Gl.GL_TRUE);
//Glut.glutSetCursor(Glut.GLUT_CURSOR_NONE);
Gl.glPushMatrix();
Gl.glRotatef(80f, 1.0f, 0.0f, 0.0f);
Glu.gluDisk (qobj,0, 800, 900, 300);
Gl.glPopMatrix();
Never(!) put OpenGL state change functions into an event handler! Right now you have exactly this. In your keypress handler change some variable, then issue a redraw event and use that to apropriately setup the matrices in the drawing function.
glLoadIdentity has to do with this only insofar, that you call it at a place, where it does not belong. OpenGL is a drawing API not a scene graph.