Drawing a Rectangle with color and thickness in OnGUI - unity3d

I would like to draw a frame / rectangle in OnGUI in order to display a certain area for debugging purposes.
This rectangle should be displayed with a certain "thickness" / line width and color.
So far, I have only found GUI.Label and GUI.Box, which both seems inadequate for this.
Thank you!

If it is only for debugging I would recommend to use Gizmos.DrawWireCube
Note: Only drawn in the SceneView not in the GameView so really only for debugging
private void OnDrawGizmosSelected()
{
// Draw a yellow cube at the transform position
var color = Gizmos.color;
Gizmos.color = Color.yellow;
Gizmos.DrawWireCube(transform.position, new Vector3(1, 1, 1));
Gizmos.color = color;
}
for showing it only if object is selected or OnDrawGizmos for showing it allways
Note that this is done in WorldSpace so if you rather want the size vector etc rotate together with the object you can wrap in between
var matrix = Gizmos.matrix;
Gizmos.matrix = transform.localToWorldMatrix;
//...
Gizmos.matrix = matrix;
Unfortunately there is no option to change the line thikness...
... but you could overcome this by simply drawing e.g. 4 normal cubes using Gizmos.DrawCube to form a rectangle. Something maybe like
private void OnDrawGizmos()
{
DrawDebugRect(new Vector2(0.5f, 0.3f), 0.05f);
}
private void DrawRect(Vector2 size, float thikness)
{
var matrix = Gizmos.matrix;
Gizmos.matrix = transform.localToWorldMatrix;
//top cube
Gizmos.DrawCube(Vector3.up * size.y / 2, new Vector3(size.x, thikness, 0.01f);
//bottom cube
Gizmos.DrawCube(Vector3.down * size.y / 2, new Vector3(size.x, thikness, 0.01f);
//left cube
Gizmos.DrawCube(Vector3.left * size.x / 2, new Vector3(thikness, size.y, 0.01f);
//right cube
Gizmos.DrawCube(Vector3.right * size.x / 2, new Vector3(thikness, size.y, 0.01f);
Gizmos.matrix = matrix;
}
I'm only on smartphone so it might not be copy-past-able but I think you'll get the idea ;)

Related

Unity and VR: offset using "ReadPixels()" function

I've ran into a small issue developing a picture taker for a VR project. I need to take a screenshot of a specific zone, which is a rectangle with variable width and height. To do that, I have a transform anchored to the top right corner of the bounding box that represents where the picture is going to be taken, and one anchored to the lower right corner.
Here's what it should look like. I've added little red circles to show the transforms's position.
Here's what a screencap using the left eye looks like. It's the same result if I use "both eyes" as a target in the Camera settings.
Here's what a screencap using the right eye looks like. So not only is it too far left or right, it's also a tad too high.
Here's the code that creates the Rect, and here's the code that reads the pixels.
When the Main Camera targets the left eye, there's almost half of the Rect's with as an offset to the left, when it targets the right eye, there's that same offset to the right, when it targets both, there's a softer offset to the left, and all of these have a slight vertical offset upwards.
Any help is appreciated. I'll keep this thread updated if I find anything!
public void SubmitPicture()
{
Vector2 upperLeftPosition = mainCamera.WorldToScreenPoint(upperLeftTransform.position);
Vector2 lowerRightPosition = mainCamera.WorldToScreenPoint(lowerRightTransform.position);
pictureBoxRect.x = upperLeftPosition.x;
pictureBoxRect.y = mainCamera.scaledPixelHeight - upperLeftPosition.y;
pictureBoxRect.width = lowerRightPosition.x - upperLeftPosition.x;
pictureBoxRect.height = lowerRightPosition.y - upperLeftPosition.y;
pictureSnapper.OnInput(AbsoluteRect(pictureBoxRect));
}
public void OnInput(Rect pictureBox)
{
if ((int)pictureBox.width > 0 && (int)pictureBox.height > 0)
{
videoPlayer.Stop();
Texture2D videoTexture = new Texture2D((int)pictureBox.width, (int)pictureBox.height);
videoTexture.ReadPixels(pictureBox, 0, 0);
videoTexture.Apply();
byte[] imageData = videoTexture.GetRawTextureData();
if (debug)
{
byte[] imagePng = videoTexture.EncodeToPNG();
File.WriteAllBytes(Application.dataPath + "/" + savename + ".png", imagePng);
}
}
}
private Rect AbsoluteRect(Rect rect)
{
if (rect.width < 0)
{
rect.x -= rect.width;
rect.width = Mathf.Abs(rect.width);
}
if (rect.height < 0)
{
rect.y += rect.height / 2;
rect.height = Mathf.Abs(rect.height);
}
return rect;
}
Updated to add the picture references.

How to modify a Texture pixels from a compute shader in unity?

I stumbled upon a strange problem in vuforia.When i request a camera image using CameraDevice.GetCameraImage(mypixelformat), the image returned is both flipped sideways and rotated 180 deg. Because of this, to obtain a normal image i have to first rotate the image and then flip it sideways.The approach i am using is simply iterating over pixels of the image and modifying them.This approach is very poor performance wise.Below is the code:
Texture2D image;
CameraDevice cameraDevice = Vuforia.CameraDevice.Instance;
Vuforia.Image vufImage = cameraDevice.GetCameraImage(pixelFormat);
image = new Texture2D(vufImage.Width, vufImage.Height);
vufImage.CopyToTexture(image);
Color32[] colors = image.GetPixels32();
System.Array.Reverse(colors, 0, colors.Length); //rotate 180deg
image.SetPixels32(colors); //apply rotation
image = FlipTexture(image); //flip sideways
//***** THE FLIP TEXTURE METHOD *******//
private Texture2D FlipTexture(Texture2D original, bool upSideDown = false)
{
Texture2D flipped = new Texture2D(original.width, original.height);
int width = original.width;
int height = original.height;
for (int col = 0; col < width; col++)
{
for (int row = 0; row < height; row++)
{
if (upSideDown)
{
flipped.SetPixel(row, (width - 1) - col, original.GetPixel(row, col));
}
else
{
flipped.SetPixel((width - 1) - col, row, original.GetPixel(col, row));
}
}
}
flipped.Apply();
return flipped;
}
To improve the performance i want to somehow schedule these pixel operations on the GPU, i have heard that a compute shader can be used, but i have no idea where to start.Can someone please help me write the same operations in a compute shader so that the GPU can handle them, Thankyou!.
The whole compute shader are new for me too, but i took the occasion to research it a little bit for myself too. The following works for flipping a texture vertically (rotating and flipping horizontally should be just a vertical flip).
Someone might have a more elaborate solution for you, but maybe this is enough to get you started.
The Compute shader code:
#pragma kernel CSMain
// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
RWTexture2D<float4> Result;
Texture2D<float4> ImageInput;
float2 flip;
[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
flip = float2(512 , 1024) - id.xy ;
Result[id.xy] = float4(ImageInput[flip].x, ImageInput[flip].y, ImageInput[flip].z, 1.0);
}
and called from any script:
public void FlipImage()
{
int kernelHandle = shader.FindKernel("CSMain");
RenderTexture tex = new RenderTexture(512, 1024, 24);
tex.enableRandomWrite = true;
tex.Create();
shader.SetTexture(kernelHandle, "Result", tex);
shader.SetTexture(kernelHandle, "ImageInput", myTexture);
shader.Dispatch(kernelHandle, 512/8 , 1024 / 8, 1);
RenderTexture.active = tex;
result.ReadPixels(new Rect(0, 0, tex.width, tex.height), 0, 0);
result.Apply();
}
This takes an input Texture2D, flips it in the shader, applies it to a RenderTexture and to a Texture2D, whatever you need.
Note that the image sizes are hardcoded in my instance and should be replaced by whatever size you need. (for within the shader use shader.SetInt(); )

Draw a Rect using GUI.DrawTexture on exactly gameobject's position Unity

I have to use the "GUI.DrawTexture(new Rect..." function to draw a rectangle on my screen(actually, it's a gradient GUI bar i got from https://www.assetstore.unity3d.com/en/#!/content/19972, but deep inside it's just a rectangle). I want to do it right beside a gameobject i have on my screen.
The problem is: It seems like rectangle's coordinates are not the same as a gameobjects coordinates(i have searched online and i guess it's true). I have tried the function below to convert a gameobject's position to a rectangle's coordinates but still no luck:
public Vector2 WorldToGuiPoint(Vector2 position)
{
var guiPosition = Camera.main.WorldToScreenPoint(position);
guiPosition.y = Screen.currentResolution.height - guiPosition.y;
return guiPosition;
}
My best strike was when i did this:
Vector3 gameObjectsPosition = Camera.main.WorldToScreenPoint(gameObject);
And then when i wanted to draw the rectangle i did:
GUI.DrawTexture(new Rect(gameObjectsPosition.x, Screen.height - gameObjectsPosition.y, Background.width * ScaleSize, Background.height * ScaleSize), Background);
But still, the Rect isn't on the exact gameObject's position. It's x is right but y don't and when i searched the internet, they said I only had to do the "Screen.height - gameObjectsPosition.y" when drawing the Rect. It didn't work for me, the y is still wrong.
What should i do to create a rectangle that's like, right beside a current gameobject on screen (like, if the gameobject's position is x = -401 and y = -80, i want it on y=-80 and x=-300)
You need to use Screen.height instead of
Screen.currentResolution.height
using UnityEngine;
using System.Collections;
public class GuiPosition : MonoBehaviour
{
public Vector2 WorldToGuiPoint(Vector3 GOposition)
{
var guiPosition = Camera.main.WorldToScreenPoint(GOposition);
// Y axis coordinate in screen is reversed relative to world Y coordinate
guiPosition.y = Screen.height - guiPosition.y;
return guiPosition;
}
void OnGUI()
{
var guiPosition = WorldToGuiPoint(gameObject.transform.position);
var rect = new Rect(guiPosition, new Vector2(200, 70));
GUI.Label(rect, "TEST");
}
}
I've just tested attaching that MonoBehaviour to a Cube GameObject and it works

cocos2dx: Sprite3D rotating, culling error

Hi I'm trying to have 2 sprites with different z in 3d world and a camera that rotates around the center of the screen and points at the center of the screen.
Even if the sprites has different z (and zorder, I don't know if this is necessary) the sprites are always visualized while I'm expecting to have the second sprite hided from the other...
This is helloworld layer init
auto sp3d = Sprite3D::create();
sp3d->setPosition(visibleSize.width/2, visibleSize.height/2);
addChild(sp3d);
auto sprite = Sprite::create("JP9_table.png");
auto spritePos = Vec3(0,0,0);
sprite->setScale(0.3);
sprite->setPosition3D(spritePos);
sp3d->addChild(sprite,0);
auto sprite2 = Sprite::create("JP9_logo_yc.png");
auto spritePos2 = Vec3(0,0,10);
sprite2->setPosition3D(spritePos2);
sp3d->addChild(sprite2,10);
sp3d->setCullFace(GL_BACK);
sp3d->setCullFaceEnabled(true);
this->setCameraMask((unsigned short)CameraFlag::USER2, true);
camera = Camera::createPerspective(60, (float)visibleSize.width/visibleSize.height, 1.0, 1000);
camera->setCameraFlag(CameraFlag::USER2);
camera->setPosition3D(spritePos + Vec3(-200,0,800));
camera->lookAt(spritePos, Vec3(0.0,1.0,0.0));
this->addChild(camera);
this->scheduleUpdate();
angle=0;
and this is update:
void TestScene::update(float dt)
{
angle+=0.1;
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
Vec3 spritePos=Vec3(visibleSize.width/2,visibleSize.height/2,0);
camera->setPosition3D(Vec3(visibleSize.width/2,visibleSize.height/2,0) + Vec3(800*cos(angle),0,800*sin(angle)));
camera->lookAt(spritePos, Vec3(0.0,1.0,0.0));
}
I have tryed something simplier:
auto sp3d = Sprite3D::create();
sp3d->setPosition(visibleSize.width/2, visibleSize.height/2);
addChild(sp3d);
auto sprite = Sprite::create("JP9_table.png");
auto spritePos = Vec3(0,0,0);
sprite->setScale(0.3);
sprite->setPosition3D(spritePos);
sp3d->addChild(sprite,0);
auto sprite2 = Sprite::create("JP9_logo_yc.png");
auto spritePos2 = Vec3(0,0,10);
sprite2->setPosition3D(spritePos2);
sp3d->addChild(sprite2,10);
sp3d->setCullFace(GL_BACK);
sp3d->setCullFaceEnabled(true);
even with sp3d->runAction(RotateTo::create(20,vec3(0,3000,0))) same error.
Is it a cocos2dx bug?
the sprite with z=10 disappear before it is covered by the other sprite...
remain hidden for a while, and when it should be hidden completely reappear!!!
Do I have forgot something?
thanks
Maybe you should check this.
_camControlNode = Node::create();
_camControlNode->setNormalizedPosition(Vec2(.5,.5));
addChild(_camControlNode);
_camNode = Node::create();
_camNode->setPositionZ(Camera::getDefaultCamera()->getPosition3D().z);
_camControlNode->addChild(_camNode);
auto sp3d = Sprite3D::create();
sp3d->setPosition(s.width/2, s.height/2);
addChild(sp3d);
auto lship = Label::create();
lship->setString("Ship");
lship->setPosition(0, 20);
sp3d->addChild(lship);
and
_lis->onTouchMoved = [this](Touch* t, Event* e) {
float dx = t->getDelta().x;
Vec3 rot = _camControlNode->getRotation3D();
rot.y += dx;
_camControlNode->setRotation3D(rot);
Vec3 worldPos;
_camNode->getNodeToWorldTransform().getTranslation(&worldPos);
Camera::getDefaultCamera()->setPosition3D(worldPos);
Camera::getDefaultCamera()->lookAt(_camControlNode->getPosition3D());
};

Unity - Limit Camera Movement XY axis

I have the following code which works really well for scrolling map using the draggable mouse. I am trying to define limits so that I cannot scroll too far in either the x or y co-ordinates. I've seen various examples of code, such as:
"transform.position.x = Mathf.Clamp(-100, 100);" though have not been able to incorporate it into the code. I am a bit of a beginner to all this and have just done a 2D tutorial animating zombies and have a camera that can scroll, but would like to add limits to how far it can scroll in any given directions.
Thanks heaps
Adam
using UnityEngine;
using System.Collections;
public class ViewDrag : MonoBehaviour {
Vector3 hit_position = Vector3.zero;
Vector3 current_position = Vector3.zero;
Vector3 camera_position = Vector3.zero;
float z = 0.0f;
// Use this for initialization
void Start () {
}
void Update(){
if(Input.GetMouseButtonDown(0)){
hit_position = Input.mousePosition;
camera_position = transform.position;
}
if(Input.GetMouseButton(0)){
current_position = Input.mousePosition;
LeftMouseDrag();
}
}
void LeftMouseDrag(){
// From the Unity3D docs: "The z position is in world units from the camera." In my case I'm using the y-axis as height
// with my camera facing back down the y-axis. You can ignore this when the camera is orthograhic.
current_position.z = hit_position.z = camera_position.y;
// Get direction of movement. (Note: Don't normalize, the magnitude of change is going to be Vector3.Distance(current_position-hit_position)
// anyways.
Vector3 direction = Camera.main.ScreenToWorldPoint(current_position) - Camera.main.ScreenToWorldPoint(hit_position);
// Invert direction to that terrain appears to move with the mouse.
direction = direction * -1;
Vector3 position = camera_position + direction;
transform.position = position;
}
}
What exactly is the error you are getting? I imagine it is something along the lines of being unable to modify the return value of position because it is not a variable.
If this is the case, you should however be able to set the whole position vector at once. So try something along the lines of this:
var pos = transform.position;
transform.position = new Vector3(
Math.clampf(pos.x, -100, 100),
Math.clampf(pos.y, -100, 100),
pos.z
);
You may need to swap around clamping Y and Z, depending on how you are using them.