So here’s the basic premise of what I’m trying to do. I’m in the middle of making a Racing game, where 2D characters move around a 3D environment.
The player object is set up as a parent which consists of target object, the camera, and graphics component. The Parent object itself is assigned with a box collider, and rigidbody. and a simple controller script for the moment being. The graphics object is a basic quad object set up with a simple billboard script, which makes the object face towards the assigned camera relative to said cameras forward position.
public Camera m_Camera;
void Update()
{
transform.LookAt(transform.position + m_Camera.transform.rotation * Vector3.forward,
m_Camera.transform.rotation * Vector3.up);
}
What I want, is to create a player object that shows different sprites states depending on the angle the camera views it from. Sort of like what was done with Doom like the first video shown,
or in this case, Mario Kart 64.
Now I have a sample script, which I believe was used for enemy sprites, but is probably goes by the same principle.
int GetAngleIndex()
{
var dir = GetComponent<Camera>().transform.position - transform.parent.forward;
var enemyAngle = Mathf.Atan2(dir.z, dir.x) * Mathf.Rad2Deg;
if (enemyAngle < 0.0f)
enemyAngle += 360;
Debug.Log("Angle from the player is: " + enemyAngle);
if (enemyAngle >= 292.5f && enemyAngle < 337.5f)
return 8;
else if (enemyAngle >= 22.5f && enemyAngle < 67.5f)
return 2;
else if (enemyAngle >= 67.5f && enemyAngle < 112.5f)
return 3;
else if (enemyAngle >= 112.5f && enemyAngle < 157.5f)
return 4;
else if (enemyAngle >= 157.5f && enemyAngle < 202.5f)
return 5;
else if (enemyAngle >= 202.5f && enemyAngle < 247.5f)
return 6;
else if (enemyAngle >= 247.5f && enemyAngle < 292.5f)
return 7;
else if (enemyAngle >= 337.5f || enemyAngle < 22.5f)
return 1;
else return 0;
}
Still, If anyone has any questions to ask, advice to give out, or any critiques to give, I probably would appreciate the attention. There’s a lot I got to figure out.
I used to do this by having a model that contained all view directions. (A bit like the classic + shaped tree models.) The shader would then reject the views that were not needed. Indeed based on the angle between the forward direction of the camera and the normal of the view. (Using the view direction leads to some undesired results.)
The idea behind this is that it is more batch friendly and the GPU is fast enough to skip some extra pixels anyway. This might apply less directly to mobile hardware.
You can do the rejection using the cameras forward dir in the vertex shader by moving the vertex behind the camera. Way cheaper than pixel rejection, mobile friendly.
You’re rejecting each vertex individually, so you have to be sure the test you use to reject is the same for all vertices of a polygon, but by placing the polygon behind the camera it will get automatically rejected by the GPU during rasterization.
alright, so I’ve created a simple vertex shader to start things off. I just need to figure out where I edit it so that able to move the vertex behind my camera.
Alright, so I’ve read through every part of shaders introduction, and now I think a have a good idea on what I should do. It might not be exactly though, so feel free to correct me on thing mentioned.
So for my shader, it has to work with a sprite sheet, specifically it various units. For my character, there are twelve sprites being used for it, ten of which will be flip horizontally. In total that makes 22 images used for a three hundred sixty degree rotation around a player, and as “bgolus” said in the comments,
Using a vertex shader, If I program the units of my sprite sheets with
&
in way that similar to an animation transition, then maybe it might give the illusion of a 2d character with a 3d rotation. Basically, depending on the angle the graphics face the assigned camera from, it will show a different view of character.
POSITION in the appdata struct is just a vertex position from the mesh, and TEXCOORD0 is just the first UV map for that vertex.
The vertex shader takes that data and transforms the vertex positions into the screen space position (called clip space or projection space), and passing the texture coordinates on to the fragment shader (optionally transforming those too, in Unity’s case often using the scale and offset values you set on the material).
To move the position behind the camera after: o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
you can set: o.vertex.z = -1;
Except that won’t necessarily work properly in Unity 5.5 on Windows, or in OpenGL. You’ll actually need to do: #ifdef UNITY_REVERSED_Z
o.vertex.z = 1; // note, that’s not a negative #else
o.vertex.z = -o.vertex.w * 2.0; #endif
For the rest of it, like determining if it should be shown or not, you’ll need to have some decent understanding of vector math and dot products. I suggest reading some tutorials on cat like coding.
You’ll need to compare the camera’s forward vector to the surface normal and, depending on the angle hide or show it.
There’s also the task of creating the original mesh with the multiple planes and UVs setup for each of the rotations. And then you’ll have to deal with animation somehow.