I'm using WebCamTexture to get input from the camera (iOS&Android). However, since this is raw input, the rotation is wrong when rendered to a texture. I read around a lot, and found this (look at the bottom): WebCamTexture rotated and flipped on iPhone
His code (but with test-values):
Quaternion rotation = Quaternion.Euler(45f, 30f, 90f);
Matrix4x4 rotationMatrix = Matrix4x4.TRS(Vector3.zero, rotation, new Vector3(1, 1, 1));
material.SetMatrix("_Rotation", rotationMatrix);
But whatever value I use, nothing happens (neither in the editor or on devices)...
Thanks!
Edit
After some intense testing, I found that material.SetMatrix, SetFloat, SetWhatever has NO effect (not setting the value) unless it's declared inside the "Properties"-block. Looking at unity:s own example, this should't have to (and can't) be done for a matrix (can't be declared inside Properties, only inside the CGProgram). So... How do you set a matrix then? Or what else am I doing wrong?
You should be using: WebCamTexture.videoRotationAngle
its designed to solve exactly this problem, read more about this here.
Example code:
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour {
public WebCamTexture webcamTexture;
public Quaternion baseRotation;
void Start() {
webcamTexture = new WebCamTexture();
renderer.material.mainTexture = webcamTexture;
baseRotation = transform.rotation;
webcamTexture.Play();
}
void Update() {
transform.rotation = baseRotation * Quaternion.AngleAxis(webcamTexture.videoRotationAngle, Vector3.up);
}
}
Just rotate the camera to 90 degrees along the z axis (the camera is which is rendering the webcamtexture gameobject).
Related
I'm writing my first Qt 5 application... This uses a third-party map library (QGeoView).
I need to draw an object (something like a stylized airplane) over this map. Following the library coding guidelines, I derived from the base class QGVDrawItem my QGVAirplane.
The airplane class contains heading and position values: such values must be used to draw the airplane on the map (of course in the correct position and with correct heading). The library requires QGVDrawItem derivatives to override three base class methods:
QPainterPath projShape() const;
void projPaint(QPainter* painter);
void onProjection(QGVMap* geoMap)
The first method is used to achieve the area of the map that needs to be updated. The second is the method responsible to draw the object on the map. The third method is needed to reproject the point from the coordinate space on the map (it's not relevant for the solution of my problem).
My code looks like this:
void onProjection(QGVMap* geoMap)
{
QGVDrawItem::onProjection(geoMap);
mProjPoint = geoMap->getProjection()->geoToProj(mPoint);
}
QPainterPath projShape() const
{
QRectF _bounding = createGlyph().boundingRect();
double _size = fmax(_bounding.height(), _bounding.width());
QPainterPath _bounding_path;
_bounding_path.addRect(0,0,_size,_size);
_bounding_path.translate(mProjPoint.x(), mProjPoint.y());
return _bounding_path;
}
// This function creates the path containing the airplane glyph
// along with its label
QPainterPath createGlyph() const
{
QPainterPath _path;
QPolygon _glyph = QPolygon();
_glyph << QPoint(0,6) << QPoint(0,8) << QPoint(14,6) << QPoint(28,8) << QPoint(28,6) << QPoint(14,0);
_path.addPolygon(_glyph);
_path.setFillRule(Qt::FillRule::OddEvenFill);
_path.addText(OFF_X_TEXT, OFF_Y_TEXT, mFont , QString::number(mId));
QTransform _transform;
_transform.rotate(mHeading);
return _transform.map(_path);
}
// This function is the actual painting method
void drawGlyph(QPainter* painter)
{
painter->setRenderHints(QPainter::Antialiasing, true);
painter->setBrush(QBrush(mColor));
painter->setPen(QPen(QBrush(Qt::black), 1));
QPainterPath _path = createGlyph();
painter->translate(mProjPoint.x(), mProjPoint.y());
painter->drawPath(_path);
}
Of course:
mProjPoint is the position of the airplane,
mHeading is the heading (the direction where the airplane is pointing),
mId is a number identifying the airplane (will be displayed as a label under airplane glyph),
mColor is the color assigned to the airplane.
The problem here is the mix of rotation and translation. Transformation: since the object is rotated, projShape() methods return a bounding rectangle that's not fully overlapping the object drawn on the map...
I also suspect that the center of the object is not correctly pointed on mProjPoint. I tried many times trying to translate the bounding rectangle to center the object without luck.
Another minor issue is the fillup of the font... the label under the airplane glyph is not solid, but it is filled with the same color of the airplane.
How can I fix this?
Generically speaking, the general pattern for rotation is to scale about the origin first and then finish with your final translation.
The following is pseudocode, but it illustrates the need to shift your object's origin to (0, 0) prior to doing any rotation or scaling. After the rotate and scale are done, the object can be moved back from (0, 0) back to where it came from. From here, any post-translation step may be applied.
translate( -origin.x, -origin.y );
rotate( angle );
scale( scale.x, scale y);
translate( origin.x, origin.y );
translate( translation.x, translation.y )
I finally managed to achieve the result I meant....
QPainterPath projShape() const
{
QPainterPath _path;
QRectF _glyph_bounds = _path.boundingRect();
QPainterPath _textpath;
_textpath.addText(0, 0, mFont, QString::number(mId));
QRectF _text_bounds = _textpath.boundingRect();
_textpath.translate(_glyph_bounds.width()/2-_text_bounds.width()/2, _glyph_bounds.height()+_text_bounds.height());
_path.addPath(_textpath);
QTransform _transform;
_transform.translate(mProjPoint.x(),mProjPoint.y());
_transform.rotate(360-mHeading);
_transform.translate(-_path.boundingRect().width()/2, -_path.boundingRect().height()/2);
return _transform.map(_path);
}
void projPaint(QPainter* painter)
{
painter->setRenderHint(QPainter::Antialiasing, true);
painter->setRenderHint(QPainter::TextAntialiasing, true);
painter->setRenderHint(QPainter::SmoothPixmapTransform, true);
painter->setRenderHint(QPainter::HighQualityAntialiasing, true);
painter->setBrush(QBrush(mColor));
painter->setPen(QPen(QBrush(Qt::black), 1));
painter->setFont(mFont);
QPainterPath _path = projShape();
painter->drawPath(_path);
}
Unluckly I still suffer the minor issue with text fill mode:
I would like to have a solid black fill for the text instead of the mColor fill I use for the glyph/polygon.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraFeed : MonoBehaviour {
// Use this for initialization
public Renderer rend;
void Start () {
WebCamDevice[] devices = WebCamTexture.devices;
// for debugging purposes, prints available devices to the console
for(int i = 0; i < devices.Length; i++)
{
print("Webcam available: " + devices[i].name);
}
Renderer rend = this.GetComponentInChildren<Renderer>();
// assuming the first available WebCam is desired
WebCamTexture tex = new WebCamTexture(devices[0].name);
rend.material.mainTexture = tex;
//rend.material.SetTextureScale("tex", new Vector2(1.2f, 1.2f));
tex.Play();
}
// Update is called once per frame
void Update () {
}
}
I use the above code to render camera feed on a plane. The code works fine but I see zoomed feed(around 1.2x) when deployed to iPad. How can I get the normal feed. Or How do I zoom out the camera feed
According to https://answers.unity.com/questions/1421387/webcamtexture-zoomed-in-on-ipad-pro.html if you insert this code it should scale properly:
rend.material.SetTextureScale("_Texture", new Vector2(1f, 1f))
Furthermore, it seems that you were trying something like this but your vector was off (by 0.2f) though you have commented out that line as well. You could reduce the scale even more though that could make the image just smaller if the camera couldn't support that zoomout :).
Currently, my game using some pixel detections.
For exemple, for sprites, i retrieve the pixel of its position.
When i move it, the position values have some decimals like :
thePixel = new vector(position.X, position.Y);
//thePixel = (52.2451, 635.2642)
so i have to Round These values
thePixel = new vector((float)Math.Round(position.X, 0), (float)Math.Round(position.Y, 0));
//thePixel = (52, 635)
I would like to know if there are some other ways to get perfect position (means, without decimal) without Rounding them.
Is it maybe a moving method problem ?
Thx for reading, hope you can help.
You can't really get around the need to round your values, but you can make it a lot nicer to code by using an extension method:
public static class Vector2Extensions
{
public static Vector2 Floor(this Vector2 vector)
{
return new Vector2((float)Math.Floor(vector.X), (float)Math.Floor(vector.Y));
}
}
(As you can see, personally I prefer Floor to Round. I also have one for Ceiling.)
Then you can just use it like this:
HandleCollision(position.Floor());
Of course, if you're doing per-pixel collision detection - your collision maths should probably be integer-based (not stored as float in a Vector2). You could use Point. Turns out I have an extension method for that too:
public static class Vector2Extensions
{
public static Point AsXnaPoint(this Vector2 v)
{
return new Point((int)v.X, (int)v.Y);
}
}
Then:
HandleCollision(position.AsXNAPoint());
Or possibly:
HandleCollision(position.Floor().AsXNAPoint());
Why Vector2 (from XNA's library) uses float not int?
Position on computer screen is given in pixels so that cursor position can be defined by two integers. There is no such a thing like half a pixel. Why we use floats then?
In SpriteBatch class I've found 7 overloaded methods called Draw. Two of them:
public void Draw(Texture2D texture, Rectangle destinationRectangle, Color color);
public void Draw(Texture2D texture, Vector2 position, Color color);
So we can see that Draw accepts both int and float coordinates.
I came across this problem when I've been implementing screen coordinates of my game's objects. I assumed that Rectangle is good choice to hold object's size and screen coordinates. But now I'm not sure...
Mathematically, a vector is a motion, not a position. While a position on the screen might not technically be able to be between integers, a motion definitely can. If a vector used ints then the slowest you could move would be (1, 1). With floats you can move (.1, .1), (.001, .001), and so on.
(Notice also that the XNA struct Point does actually use ints.)
You could use both Vector2 and Rectangle to represent your objects coordinates. I usually do it like this:
public class GameObject
{
Texture2D _texture;
public Vector2 Position { get; set; }
public int Width { get; private set; } //doesn't have to be private
public int Height { get; private set; } //but it's nicer when it doesn't change :)
public Rectangle PositionRectangle
{
get
{
return new Rectangle((int)Position.X, (int)Position.Y, Width, Height);
}
}
public GameObject(Texture2D texture)
{
this._texture = texture;
this.Width = texture.Width;
this.Height = texture.Height;
}
}
To move objects, just set their Position property to a new value.
_player.Position = new Vector2(_player.Position.X, 100);
You don't have to worry about the rectangle, as it's value depends directly on Position.
My game objects also usually contain methods to draw themselves, such as
public void Draw(SpriteBatch spriteBatch, GameTime gameTime)
{
spriteBatch.Draw(this._texture, this.Position, Color.White);
}
Collision detection code in your Game.Update() could just use the PositionRectangle to test for collisions
//_player and _enemy are of type GameObject (or one that inherits it)
if(_player.PositionRectangle.Intersects(_enemy.PositionRectangle))
{
_player.Lives--;
_player.InvurnerabilityPeriod = 2000;
//or something along these lines;
}
You could also call the spriteBatch.Draw() with PositionRectangle, you shouldn't notice much difference.
There is such a thing as "half a pixel." Using float coordinates that aren't pixel-aligned will cause your sprites to be rendered at sub-pixel coordinates. This is often necessary to make objects appear to scroll smoothly, but it can also produce an unpleasant shimmering effect in some circumstances.
See here for a summary of the basic idea: Subpixel rendering
Im doing some practices on XNA, and i created a class that represents a Camera.
My objective is that when the user press some keys make a translation of the camera (not the target) 90 degrees in the X axys (to see an object that i placed in the scene from different angles). By the moment i move the camera in X, Y, and Z without problems.
Actually to set up my camera i use the following lines of code:
public void SetUpCamera()
{
#region ## SET DEFAULTS ##
this.FieldOfViewAngle = 45.0f;
this.AspectRatio =1f;
this.NearPlane = 1.0f;
this.FarPlane = 10000.0f;
#endregion
this.ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(this.FieldOfViewAngle), 16 / 9, this.NearPlane, this.FarPlane);
this.ViewMatrix = Matrix.CreateLookAt(new Vector3(this.PositionX, this.PositionY, this.PositionZ), new Vector3(this.TargetX, this.TargetY, this.TargetZ), Vector3.Up);
}
I have this method to move the camera:
public void UpdateView()
{
this.ViewMatrix = Matrix.CreateLookAt(new Vector3(this.PositionX, this.PositionY, this.PositionZ), new Vector3(this.TargetX, this.TargetY, this.TargetZ), Vector3.Up);
}
Then in the game (update event handler i have the following code)
if (keyboardstate.IsKeyDown(Keys.NumPad9))
{
this.GameCamera.PositionZ -= 1.0f;
}
if (keyboardstate.IsKeyDown(Keys.NumPad3))
{
this.GameCamera.PositionZ += 1.0f;
}
this.GameCamera.UpdateView();
I would like to know how to make this camera translation of 90 degrees to surround one object that i placed in the screen.
To explain my self better about the camera movement here is a video on youtube that uses the exact movement that im trying to describe (see from 14 second)
http://www.youtube.com/watch?v=19mbKZ0I5u4
Assuming the camera in the video is orbiting the car, here is how you would accomplish that in XNA.
For the sake of readability, we'll just use vectors instead of their individual components. So 'target' means it's a Vector3 that includes TargetX, TargetY, & TargetZ. Same with the camera’s position. You can break X, Y, Z values out into fields and make Vector3s out of them to plug into this code if you want to later, but really it would be best for you to work at vector level instead of component level.
//To orbit the car (target)
cameraPosition = Vector3.Transform(cameraPosition – target, Matrix.CreateRotationY(0.01f)) + target;
this.ViewMatrix = Matrix.CreateLookAt(cameraPosition, target, Vector3.Up);
Since all matrix rotations act about an axis that intersects the world origin, to use a rotation matrix to rotate the camera around the car, the object of rotation has to be shifted such that the target (and thus the rotation axis) is located at the world origin. CameraPosition - target accomplishes that. Now cameraPosition can be rotated a little bit. Once cameraPosition is rotated a little bit, it needs to be sent back to the scene at hand, that's what the '+ target' at the end of the line is for.
The 0.01f can be adjusted to whatever rotation rate suits you.