Tuesday, January 20, 2015

Unity Script: Oculus Selection Logic (2 of 3)

Oculus selection is something I've seen a lot of examples of in demo games, but almost no documentation on as to how to manage your selection. Here's some basic Unity logic I've learned while working on Brune's Oculus integration.
See how we made the pointer in post 1
____________________________________________________________





Goal

Selection: plain and simple. Choosing between game objects, which way to look, and what to interact with. Mainly this post is about how to use a pointer moved by the mouse (last post) that sends clicks where you want them to go.

____________________________________________________________

Obstacles:
Note the curve, and how each eye sees further to one side

Camera Distortion: It's important to keep in mind that the Oculus uses 2 in game cameras distorted together to simulate your eye-based vision inside the Rift. This also means that it's easy to aim at something with "one eye" and not really hit it within the distortion.







Mouse Function: I just haven't managed to get the windows mouse-pointer function in Unity to work inside the Rift. That said, OnMouseDown does work if referenced indirectly such as

public bool triggered;

void OnMouseDown () {
       Application.LoadLevel("MyScene");
}

void Update () {
       if  (triggered) {
          OnMouseDown();
       }
}

I use this to have Oculus and regular mouse function in the same script with the same click-response code.

____________________________________________________________

How to Trigger:
Building text and highlight appear when building is triggered


  1. Make a cube child object of the pointer named "PointCollider" (or whatever)
  2. give it a cube collider set to "Is Trigger" and a rigid body set to "Is Kinematic"
  3. transform it such that it makes a long thin line through pointer object on out into the world as far as you need. (make sure it goes far enough backward to tough the player)
  4. Put a collider and this snip of code on your click-responsive assets:

void OnTriggerEnter(Collider col) {
// this part keeps your script from responding to all collider interactions, only your pointer
       if (col.transform.name == "PointCollider") {
             triggered = true;
      }
}

void OnTriggerStay(Collider col) {
       if (col.transform.name == "PointCollider") {
             triggered = true;
      }
}

void OnTriggerExit(Collider col) {
       if (col.transform.name == "PointCollider") {
             triggered = false;
      }
}


____________________________________________________________

Example In Use

I've done it slightly different in this JS example, using if (Input.GetMouseButtonDown(0)) because OnMouseDown is linked to a GUI confirmation irrelevant to the Oc player.

____________________________________________________________

Raycasts

If you ask around about what to use for generic direction-based selection, much of the Unity community will suggest Raycasting. This is an invisible line you send out from a specified origin along a specified angle. If it hits something, it records what it hit.


Why I don't use them if I can help it:

a) conditionals for raycast hit can only be calculated in the script that sends the raycast. This means that
  • button-like scripts are useless 
  • trigger area scripts are useless
  • you are mostly reliant on tag-management to sort your responses
  • effecting other objects is a logistical pain
b) selecting what the raycast hits is a pain in the butt.
c) programming for Raycasts involves programming with catcher-scripts or backward-pointers that I find not-so-fun.


Why Raycasts are useful anyway and you'll see them later on:


They are the only way (that I know of) to select a point on a TEXTURE and not just a gameObject. Therefore we will be using a Raycast to handle the Web Vewier later.


____________________________________________________________

Wanna see how your Oculus pointer can select specific points on a Coherent UI web view? Tune in to final post of this trilogy next time! :D
____________________________________________________________


All blog posts by UnityGirl are inspired by my work with Brunelleschi: Age of Architects on the Aesop Games team. Download the current Unity client On IndieDB

Saturday, January 17, 2015

Unity Script: Oculus 3d Pointer (1 of 3)



One of the biggest obstacles to developing for the Oculus is simulating mouse. This post will take us through the first of three basic steps to get Oculus mouse integration working. We'll create a 3d mouse-object that follows the mouse-movement. Next time we'll add click-integration using triggers in post 2 and we'll finish with click-integration for Coherent UI web views.

____________________________________________________________

Myriad Limitations:

There are a couple of very good reasons why we can't just use the mouse the normal Unity way.
  1. Oculus won't display the windows mouse-cursor
  2. You can't hijack/alter the windows mouse-cursor at-all easily
  3. The windows mouse-cursor aims wrong through the Oculus distortion -even if you can see it-
  4. Oculus ALSO doesn't display Unity GUI, which only responds to windows-mouse anyway. (suggest 3d menu objects as well)

____________________________________________________________

The Solution:


A Unity-Object 3D Pointer

That's right. We're gonna take a Unity asset and turn it into our pointer with a few simple scripting tricks. We'll start with your player-camera and your pointer. I use a red sphere-object as default but you can use whatever works for you.


  • Create your object
  • Parent object under Right Eye Anchor
    •  this means it'll stick to the front of the head when you move
  • Transform thusly
  • It should look something like this with the pointer selected

  • Finally, add this script that will link the pointer-movement to your physical mouse movement. 
    • This responds like MouseLook and doesn't need the windows-mouse

____________________________________________________________

The Script



For Copying


using UnityEngine;
using System.Collections;

public class Pointer_Mock : MonoBehaviour {

public GameObject targetCam;
// Use this for initialization
void Start () {
targetCam = transform.parent.gameObject;
}

void Update() {
transform.LookAt (targetCam.transform);

float localX = transform.localPosition.x;
float localY = transform.localPosition.y;

float h = (localX += (Input.GetAxis("Mouse X") * 0.05f));
float v = (localY += (Input.GetAxis("Mouse Y") * 0.05f));
transform.localPosition = new Vector3 (h, v, transform.localPosition.z);

}
}

____________________________________________________________


All blog posts by UnityGirl are inspired by my work with Brunelleschi: Age of Architects on the Aesop Games team. Download the current Unity client On IndieDB

Tuesday, November 18, 2014

Unity Tutorial: Easy Mesh Combining For Highlights

Guess what devs? After months of head scratching I've put together a quick and dirty way to both
a) Combine meshes of a Unity-build Prefab into a single mesh and
b) Outline the damn thing OnMouseOver like many games in the past have done.

Best part? I did it out of found script pieces and didn't have to ask anyone directly! :D

____________________________________________________________


The Beginner's Problem:

Whether you're in this post for Performance or Graphics, you've probably determined that you've got way too many meshes per-object. Why do we have these problems? Lack of expertise being shared around effectively.

One thing I've noticed is this Mesh issue is something that mostly afflicts beginner to intermediate devs. If you're really hardcore you've been making your models in Blender or Maya from the start and know a bunch of Mesh / Shader / Camera based tricks to optimize both appearance and performance.

When I've seen the beginner Devs ask things like "how do I highlight the whole prefab like in diablo?" the most common answer is "Why don't you just make your whole model in Blender/Maya and import it?"
Sorry guys, but this is NOT REALLY HELPFUL for those of us who have most of our game models worked out in Unity basic shapes and myriad imported meshes.

____________________________________________________________

Mesh Combining

Your Prefab:


  • The Parent Object (one everything else is inside) MUST BE EMPTY 
    • No mesh
    • scripts OK
  • Take out all mesh-ed objects you don't want included in the single mesh
    • ex: things you want to move separately from the mesh
  • Place at (0,0,0) (you can write a compensation so this isn't necessary, but I didn't bother)
The Theory:
What we're doing here follows some basic steps
  1. Make an array of all meshes inside your Prefab
  2. Make a new Mesh that will be placed on the Parent Object
  3. Combine array of meshes into single mesh on Parent Object
  4. Save mesh you've created to a folder (this part took extra research)

The Steps:
How to Implement
  1. Make sure Line 36 directs to a real folder you have
    1. Mine is directed to the folder Experimental under Assets
  2. Place Prefab at 0,0,0
  3. Place script on empty Parent Object
    1. this will add Mesh Filter and Mesh Renderer assets
  4. Press Play
  5. Pres Play again to stop. The Mesh should be saved in the designated folder
  6. At this point you can do whatever you want with the mesh (or make it again by hitting Play again) In a following post I'll be using this Mesh to create a building outline.
____________________________________________________________

The Script



For Copying

using UnityEngine;
using System.Collections;
using UnityEditor;

[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]

public class CombineMeshes : MonoBehaviour {

GameObject highlight;

void Start() {
MeshFilter[] meshFilters = GetComponentsInChildren<MeshFilter>();
CombineInstance[] combine = new CombineInstance[meshFilters.Length];
int i = 0;
while (i < meshFilters.Length) {
Debug.Log (meshFilters[i].gameObject.transform.name);
combine[i].mesh = meshFilters[i].sharedMesh;
combine[i].transform = meshFilters[i].transform.localToWorldMatrix;
//meshFilters[i].gameObject.active = false;
i++;
}



transform.GetComponent<MeshFilter>().mesh = new Mesh();
transform.GetComponent<MeshFilter>().mesh.CombineMeshes(combine);
transform.gameObject.active = true;

saveMesh ();
}

void saveMesh() {
Debug.Log ("Saving Mesh?");
Mesh m1 = transform.GetComponent<MeshFilter>().mesh;
AssetDatabase.CreateAsset(m1, "Assets/Play Assets/Experimental/" + transform.name + ".asset"); // saves to "assets/"
AssetDatabase.SaveAssets();
}
}

____________________________________________________________

Why Not Blender / Maya?

Why not just re-make every asset of your game carefully in the detailed mesh programs? You're more than welcome to but here's my assessment

Blender

  • Blender is a huge free complex program that really is great. It's just so complex and great that I don't have time to learn it all.
  • To be short: the learning curve is too steep. I'd need more time than I have to make assets I'm not happy with. 
  • And to be honest, what little I have learned to make in Blender looks sloppy
On the other hand, I highly suggest Blendswap.com where real Blender artists occasionally deign to share their works with us script plebs. If you have the time and love it, please learn Blender and share with the rest of us. :D

Maya

  • In shortest terms, it costs money. If you've got it, I've heard it's great but still time consuming.

____________________________________________________________


The Journey
I started this journey in an attempt to take building prefabs (made mostly of textured Unity cubes) and highlight/outlining the entire building on mouse-over for selection and info purposes.

Simple right? Anyone who's done this research knows I'm kidding. You can try to do this a couple ways.
Most Common Suggestion: Outline Shaders
Unlikely Suggestion: Post Processing Effects
Even Less Likely: Eldritch Rituals with Camera Values

My list is also in order of complexity. From my research I figured there are two ways to take clusters of meshed objects and highlight only the outside
  1. combine the meshes into one and use an outline shader
  2. somehow identify the cluster of objects with camera effects and have the camera try to place an outline on the right lines.
Somehow the first seemed simpler so I looked into combining meshes.
THIS was suggested to be done in a couple of ways
  1. Export the whole thing with a bought-in asset thingy to a new file type
  2. Use a bought-in ($55) mesh combining package
  3. Use mesh.CombineMeshes,
Not buying something combined with THIS excellent resource
Swayed me toward the solution we chose today.

______________________________________________________________


If you haven't already figured out how I turn this mesh into an outline, stick around for the future post where I explain it. :D

______________________________________________________________


All blog posts by UnityGirl are inspired by my work with Brunelleschi: Age of Architects on the Aesop Games team. Check out our Crowd Funding page(s)!


Monday, October 13, 2014

Desk Maps with Unity Pro and Render Textures



In a previous post we talked about huge desks in unity basic hovering below true game objects pretending to render them on a map. This time we've invested in Unity Pro and are ready to deal with Render Textures.

______________________________________________________________


Major Upsides: 
  • No more candelabra floating above your map in the editor.
  • All districts about the same shape can share a single desk object set

You can either make a new universal desk or take one of the old ones and use it as a base like I did. 
  • Make sure to set it well out of your play-map range to keep it out of the way.
  • The size of this desk doesn't matter. It and all it's objects could be huge or tiny because it's relation to the game map is no longer important.


Now all that's left is creating the individual maps that you can turn on and off as you access the Desk Camera. Each desk can even activate it's own accessories on the Unified desk.

Like So

______________________________________________________________


To Create the Map Textures
  • Assets -> Create -> Render Texture
  • Create a camera and set it above what you want a map of. Orthographic view is great for this
  • Set your new Render Texture to the Camera's Target Texture in the Inspector
  • Set the Render Texture as the texture for the object you want to hold the map (I used a flat cube)
For for large or irregularly shaped districts, there's a second, larger desk. This also lurks out of sight, visible only through activated cameras.



Viola! Now you have an interchangeable map-desks using Render Textures!

______________________________________________________________



All blog posts by UnityGirl are inspired by my work with Brunelleschi: Age of Architects on the Aesop Games team. Check out our Crowd Funding page(s)!



Thursday, October 9, 2014

Draw Pad: Mapping, Proximity and Contours


Recently, the Aesop Games studio has acquired a Wacom Intuos Pen and UnityGirl is in art heaven. Here to share some of the joy and knowledge, we're going to go over the basics of draw pad usage.


______________________________________________________________

Getting Started
Surely if I hold out my hand long enough, it will fill with ink.
First Draw Pad Doodle
Some of the first things I learned were

  • You can totally install the drivers from the web site without having to put the CD Drive back into your computer to finish installation
  • For at least the first day, you'll be using the pen as your new mouse.
  • Don't leave the pen on the tablet, it'll mess up the sensitivity.
  • It CAN survive being fumbled
  • It can handle multiple monitors

______________________________________________________________


Mapping
Actually, one of the coolest things about the draw pad is that it will map to almost anything. Basically, mapping is the relationship between the surface area of the draw pad and the area you want it to be able to draw in. I have two screens, but prefer very small hand strokes to draw, therefore I leave it mapped to span both screens. If you're doing super detail work, or just don't want the pen to leave your work-area, you can map it to a specific small section of the screen.

It also has advanced settings for multiple display use, but I won't post on it until I've played with those more.


______________________________________________________________

Proximity
This is where you use your draw pen for your mouse the whole first day. Perhaps the coolest thing on that first day is realizing that when you hover your pen at-the-ready, the pad can tell. It's all about proximity.

When the tip of the pen is near the pad, the indicator light lights up and your pen takes over the cursor on your screen. I personally felt like a god of wireless control at the time.When you're ready to draw (or click, or drag) just press the tip of the pen to the pad. 

What it Takes Getting Used To
  • The mapping of the draw pad means the location of the pen is absolute, not relative like the mouse.
  • The tip of your pen doesn't "roll" like that of a ball point
  • Pressure only applies as much as the program and your settings allow - don't push too hard.
______________________________________________________________


Contours
Now where did I leave my eyebrows?The two major revolutions from mouse-based computer art to draw-pad based are pressure and control. Like most artists who started analog, I find the mouse lacking in finesse for the fine arch of a girl's forearm..... I mean UI elements. However, even for mouse-wizards, the draw pad pen offers the feature of Pressure.

Either way, the extra detail and control offered with the draw pad setup are remarkable. In a matter of days my image work has improved from Frankenstein-ian clip-art creations to pretty nice original art if I do say so myself.

The next time we talk about Draw Pads, we'll combine it with Inkscape and the sculpting tool.

______________________________________________________________


All blog posts by UnityGirl are inspired by my work with Brunelleschi: Age of Architects on the Aesop Games team. Check out our Crowd Funding page(s)!

Wednesday, October 1, 2014

Unity Script: Building a Small Village with JS / UnityScript


______________________________________________________________

This here's an introduction to instantiating onto multiple lots at the beginning of your scene (or script). We'll start with some good ol' fashioned JS. You'll recognize this structure as a stretched version of BuildHere which we used to instantiate just the one building on the one lot. This is the way to do it if you want to avoid an Array and For-Loop situation. Good for small stuff but not great for generating large towns.
______________________________________________________________

Basically we're just multiplying everything by six.


______________________________________________________________

The Script

#pragma strict

var building : GameObject;

var lot1 : GameObject;
var lot2 : GameObject;
var lot3 : GameObject;
var lot4 : GameObject;
var lot5 : GameObject;
var lot6 : GameObject;

var buildHere : GameObject;

var resourceLoadString1 : String;
var resourceLoadString2 : String;
var resourceLoadString3 : String;
var resourceLoadString4 : String;
var resourceLoadString5 : String;
var resourceLoadString6 : String;

var thisPos1 : Vector3 = new Vector3();
var thisPos2 : Vector3 = new Vector3();
var thisPos3 : Vector3 = new Vector3();
var thisPos4 : Vector3 = new Vector3();
var thisPos5 : Vector3 = new Vector3();
var thisPos6 : Vector3 = new Vector3();

var thisRot1 : Quaternion = new Quaternion();
var thisRot2 : Quaternion = new Quaternion();
var thisRot3 : Quaternion = new Quaternion();
var thisRot4 : Quaternion = new Quaternion();
var thisRot5 : Quaternion = new Quaternion();
var thisRot6 : Quaternion = new Quaternion();




function Start () {
//sets your building's position to the same coordinates as your lot
thisPos1 = lot1.transform.position;
thisPos2 = lot2.transform.position;
thisPos3 = lot3.transform.position;
thisPos4 = lot4.transform.position;
thisPos5 = lot5.transform.position;
thisPos6 = lot6.transform.position;
//this raises your building up a bit above the lot so you don't get z-fighting flickers
thisPos1[1] = thisPos1[1] + 0.45f;
thisPos2[1] = thisPos2[1] + 0.45f;
thisPos3[1] = thisPos3[1] + 0.45f;
thisPos4[1] = thisPos4[1] + 0.45f;
thisPos5[1] = thisPos5[1] + 0.45f;
thisPos6[1] = thisPos6[1] + 0.45f;

thisRot1 = lot1.transform.rotation;
thisRot2 = lot2.transform.rotation;
thisRot3 = lot3.transform.rotation;
thisRot4 = lot4.transform.rotation;
thisRot5 = lot5.transform.rotation;
thisRot6 = lot6.transform.rotation;

//this string should be your path through your Resources folder
resourceLoadString1 = "MoveConst/Construction Frame 1";
resourceLoadString2 = "MoveConst/Construction Frame 2";
resourceLoadString3 = "MoveConst/Construction Frame 3";
resourceLoadString4 = "MoveConst/Construction Frame 4";
resourceLoadString5 = "MoveConst/Construction Frame 5";
resourceLoadString6 = "MoveConst/Construction Frame 6";

buildHere = Instantiate(Resources.Load(resourceLoadString1), thisPos1, thisRot1) as GameObject;
buildHere = Instantiate(Resources.Load(resourceLoadString2), thisPos2, thisRot2) as GameObject;
buildHere = Instantiate(Resources.Load(resourceLoadString3), thisPos3, thisRot3) as GameObject;
buildHere = Instantiate(Resources.Load(resourceLoadString4), thisPos4, thisRot4) as GameObject;
buildHere = Instantiate(Resources.Load(resourceLoadString5), thisPos5, thisRot5) as GameObject;
buildHere = Instantiate(Resources.Load(resourceLoadString6), thisPos6, thisRot6) as GameObject;
}




______________________________________________________________

Reminders

  • Make sure to set your Resource.Load() paths correctly and 
  • Assign your Lots in the Inspector if you don't GameObject.Find() them.
__________________________________________________________


All blog posts by UnityGirl are inspired by my work with Brunelleschi: Age of Architects on the Aesop Games team. Check out our Crowd Funding page(s)!


Monday, September 29, 2014

Unity Tip : Dense Grass on Really Big Terrains


The challenge of making an open-world city is how very big the map needs to be. There are several ways to do this but I chose to go with about 4 Really Big terrains.
______________________________________________________________

Problem:
Now I can't get my grass close enough together to look realistic

Grass Density 1


Why?
  • Ground cover in Unity terrains is spaced via square terrain units
    • it can only have so many instances of a ground cover per square
  • Every terrain has the same number of square units

Therefore : When you make a very large terrain, your units and thus ground cover get spread out

______________________________________________________________

Solution:
The terrain can be tricked by using multiple types of ground cover, or copies of your favorite
  • Spread your favored grass/bush/flower as thickly as you can
  • Create a second grass/bush/flower and spread it over the same area. Twice as dense!
Grass Density 2


Now just repeat the process until you're satisfied. I like to mix two types and colors of grass for realism, but here's three for the nature enthusiasts.


______________________________________________________________


All blog posts by UnityGirl are inspired by my work with Brunelleschi: Age of Architects on the Aesop Games team. Check out our Crowd Funding page(s)!