Extra Work - VR Lightsaber

Note: Due to the fact that these can be longer gifs, they are all videos.

So, during Unit 2 I managed to get my hands on a HTC Vive, a Virtual Reality Headset. This is something I've been wanting for a long, long time. So, apart from just playing the games, I wanted to try my hand at making some too. The very first thing I made? Well, it just had to be a Lightsaber from star wars, didn't it?

First, before I did anything though - I needed to get the VR system actually set up. Specifically, picking up objects. With a bit of work, I managed to get it so I could pick up objects with the left trigger, and also hold objects with the pressure buttons. This way, I could temporary pick things up with the trigger, and hold onto things with the pressure button.

Now, I can actually get started on my lightsaber! To start with, I took my simple hold cube, turned it into a cylinder, and attached a glowing cylinder inside it. It's not much, but it works. I was then able to create a 'turn off/on' button, that extends the lightsaber with a timeline to it's full length, and reverse when set to off. This simple method allowed me to create the basics for a lightsaber! Oh, and to be sure, I made sure it turns off when dropped.


I then went and tried to create an iconic 'trail' that lightsabers have. When swung fast, they leave a bit of a trail, so I made one. This was made using a 'trail particle' which generates a line between two points based on a material. I created this glowing material that fades away, created two points at the base and tip of the blade, and put the trail particle inside the two. Oh, and I replaced the model with a real lightsaber. If you can tell what it is from, kudos to you.




I then went and set it so the lightsaber's trail is only active at a certain velocity - specifically, a velocity changed to a 'Vector Length' float. The result makes it look a lot like a lightsaber when swung. Ignore the rage induced bangs of an invisible object.




I'm going to skip ahead a bit, so I can introduce a few new things. The first, is that I now have a custom model, which I created in 3DS max. Next, I added a highlighting system that highlighted the object you would pick up. This was made through  post processing effects. Finally, you'll notice I can burn things, and leave a trail of decals - this wasn't an entirely original blueprint, and was based on one used for a similar idea in a non-vr project.



Now, that's the basics of the lightsaber! However, we've got some cool stuff to do now. I wanted to make force powers - specifically push, and grab. These were quite difficult to make.

The first one, Push, was the most troublesome. I spent a long time trying to figure out how the player should push things, and then I found the right way to do it. The idea is that the player pushes forward as s/he presses the trigger to use the force power - when s/he begins pressing the trigger, it records the positions of the controller in world space. When the player lets go, it records a second location. It then uses these locations for a line trace, and takes the direction of the line trace to spawn the collision box for the push! Voila!


The Grab system was a lot more simple - it was effectively spawning an invisible collision box, adding every physics object that's touching it to an array, record each objects positions relative to the collision box, and then detach each object and tell it to interp it's location to wherever its relative location was inside the collision box. Basically, this makes it so when the player moves the motion controller, which is what the box is attached to, the object goes to where it was relative to the box. Oh, and I added colour changing. Yay!





Since I was using Unreal Engines physics system, each object has a built in mass - I was able to figure out a way to effectively 'limit' the weight of the object being pushed. Basically, anything over a certain weight limit won't be pushed as well as objects under this limit. This was determined by taking a small base push value and multiplying it by the mass of the object. Then, I take the resulting force and 'clamp' it to a certain maximum, and then applying that value as force to the object. I was able to apply this to the grab mechanic, as well - The heavier the object is, the slower it moves towards the target location. This made moving around things with force powers quite fun!

Here's a comparison with the weight system and without it. Each size has a bigger or smaller weight.



Finally, we'll talk about the most frustrating part - Bullet Deflection. It may not sound like something so difficult, but I wanted it to feel right. Most games with lightsaber-esque weapons make you hold the weapon still in the path of the bullet. I wanted it to be different - I wanted you to be able to swing the lightsaber like a madman and still block bullets. So, I needed additional collision. The basics of the projectile deflection was simple: There's a built in 'projectile movement' component that allows for bouncing. Getting the extra collision, however, required a lot of trial and error.

If it was a perfect world, I would've been able to use the trail that I created as collision. The version of Unreal that I used, however, didn't have that. So I needed an alternative. After lots of experimentation, I came across a 'procedural mesh'. This was a dynamically created mesh made in blueprints or C++, and was able to have it's verticies and faces be updated in real time. This was the solution.

Basically, I created an array - an array of parameters. In each parameter were two vectors, one for the base of the blade, and one for the tip. I set it to update it and add each parameter to this array and delete the '0' array. This was the oldest array in question, and with how arrays work, everything falls down one spot and the parameter that was once labelled '1' is now the new '0'. This allowed me to have an array of the most recent positions of the lightsaber, which I could use for generating the procedural mesh. Tada!




I had found that this was extremely performance intensive with the number of parameters I was updating in real time - so instead, I turned that down so it used every third parameter in the array, meaning the collision box was more simplified, but also more efficient. Oh, and in the video above? I wasn't that good at it at the time. I got a lot better with practice, and it felt exactly as satisfying as I wanted it to be. It was great. I finally was able to feel like a Jedi in VR.

One day, perhaps, I may expand this little project into a full game. The only issue would be copyright, of course - so until I figure that out, I'll hold off on things. Hope you enjoyed! I certainly had a lot of fun making this.

Comments

Popular Posts