| 03-20-2006, 05:16 AM | #1 |
Camera Height in WC3 Coding When dealing with Camera heights, we first have to establish a baseline of what exactly we're working with here. So lets go over the basic elements that deal with camera height in WC3. The Camera The camera can be visualized as two parts. The source, and the target. As we will soon discover, these names are somewhat reversed. How We See Things: The source is where you are as the viewer, the floating eye so to speak, the camera itself. The target is where the camera is pointing to. How They Actually Are (In the code/engine/whatever): The source is where the camera is, but this location is generated automatically and is almost irrelevant to the engine, the source is a function of the target when Distance, Angle of Attack, Rotation, ZOffset, etc are applied to it. The target is the actual camera object, the target is what moves on the X, Y and Z axis and is the start of all calculations having to do with the camera. Important Values: Rotation 0 = Looking East Rotation 90 = Looking North Angle of Attack 0 = Horizontal View Angle of Attack 90 = Vertical View Facing the Sky Angle of Attack -90 = Vertical View Facing the Ground Distance to Target 100 = The minimum distance to target, any value lower will automatically be made 100, including negative values. (So you can't use -100) Height Offset 0 = No change to the Source Height Offset 100 = The source is 100 units higher after all rotation/angle/distance calculations are done Constraints: As mentioned in the previous section, there is a constraint on the Distance To Target value for a camera. What this means is that you can't have the target and source be the same point, they must be at least 100 units apart. Camera Bounds: The target cannot move outside the camera bounds. I am specifically refering to the target and not the source. The camera bounds are outlined by blue lines in the Scenario -> Map Size and Camera Bounds... window. Target Location Z: We mentioned earlier that the target moves on the X, Y and Z axis. This doesn't make sense to anyone who's played a game of WC3 because we all know the target never moves up and down, that is covered by the rotation and distance values, then adjusted by the height offset values. So why did we mention the Z Axis? After a bit of research I figured out that the Z Axis for the camera's target has a height map which isn't actually flat. In fact there's a Z Correction height map that blizzard automatically generates for its camera target to follow, the way this height map looks is difficult to describe but it could be imitated if every terrain up or down that you made in the editor was about 1/5th as high/low and about 3 times as wide. It's almost like every change makes much smaller but much wider ripples in the camera map, causing it to go up as it approaches mountains even though it is still on flat terrain. So, what ends up happening is that whenever you set the camera Source to a specific height, it will always be a bit off by the ammount your target is raised or lowered on the camera height map. Constantly Adjusted Camera: Making a camera that constantly changes location/angle/distance is relatively easy, but here are some tips that I found useful. Initialization - Start with a function which puts the camera in the initial right place at the start of the map. The Event - I've found using Every 0.10 seconds has worked well for me. The Actions - With the event set to 0.10 seconds, this gives us a window within which we must move the camera, we could move it instantly but that would make it look choppy. It is much more visually pleasing to tell WC3 to take that time it has in the event interval to move the camera, hence we simply set the duration on all of our pans and set values to 0.10 creating a smooth feel to the camera update. Adjusting for the Camera Height Map: Althought it seems like it would be a pain to figure out what the height map is, and how to adjust for it, the solution is surprisingly simple and clean. It's origin lies in the GetCameraEyePositionZ() function. Quite simply, this function gives you the exact height of the camera Source. What this means is that it gives you the camera height After the camera height map has already been applied. Meaning we can simply adjust the camera to compensate for the height map at every itteration. Consider a Constantly Adjusted Camera with the following initial settings. Target - A Footman (The variable for which will be gg_unit_hfoo_0000 for this example) X,Y Location - Tied to a unit, pans to the Footman's location. Z Height - We want the camera to at all times be at the Footman's head level, 150 units behind him, looking at the back of his skull. Rotation - Equal to the facing of the Footman. Consider now a completely flat map, and hence a completely flat camera height map. The Z portion of our camera update function would look as follows: Code:
call SetCameraFieldForPlayer( Player(0), CAMERA_FIELD_ZOFFSET, GetLocationZ( GetUnitLoc(gg_unit_hfoo_0000) + 150, 0.10 ) This way, the target of the camera is always at height 0, but the unit height may change (here we make the assumption that the unit height may change, but the camera height map won't for the purposes of this example) so we use Camera Z Offset to move the camera up to the height of the unit, then up another 150 units to the Footman's head. Were we to use GetCameraEyePositionZ, our camera source's height would be exactly what we need it to be, the Footman's Height + 150. Now consider the same example except we're standing next to a mountain and the camera height map under our feet is +10 units. So, as soon as our camera pans to this location, the target of our camera goes up 10 units, so our source does as well. If we were to now set the camera offset to the Footman's Height + 150, we would be 10 units too high. The Solution. We now have to start thinking in itterations of the Z Adjustment of the camera. Lets consider two itterations, the first on flat ground with no camera height adjustment, the second on flat ground with a camera height adjustment of +10. Itteration 1: Unit Height = 0 Camera Height = 150 Camera Z Offset = 150 Itteration 2: Unit Height = 0 Camera Height = 160 Camera Z Offset = 150 What do we now do to fix our Camera height. Very simple, we take the height our camera is supposed to be at, take where it is currently at then simply change the Camera Z Offset to fix the problem for us. Our itterations will now look like this: Itteration 1: Unit Height = 0 Camera Height Adjustment = 0 Camera Height = 150 Camera Z Offset = 150 Itteration 2: *Camera pans to new location of Footman* Camera Height Adjustment = 10 Camera Height = 160 Code:
call SetCameraFieldForPlayer( Player(0), CAMERA_FIELD_ZOFFSET, GetCameraField( CAMERA_FIELD_ZOFFSET ) + ( GetLocationZ(GetUnitLoc(gg_unit_hfoo_0000)) + 150 - GetCameraEyePositionZ() ), udg_CamInterval ) Pseudo Code: Code:
SetCameraField( Z Offset, Z Offset + ( FootmanHeight + 150 - Camera Height ) ) Unit Height = 0 Camera Height Adjustment = 10 Camera Height = 150 Camera Z Offset = 140 Now lets see what happened. In itteration one, our height was 150, and our offset was 150. Then our camera panned, and the start of itteration two happened. At the start of itteration two is where our Z-Adjustment happens. We take the old offset, and add to it any difference between our actual height, and the height of our camera. This difference represents how much our camera changed due to forces other than ZOffset and the Unit height, therefore the only difference could be caused by the camera height map, since we've already accomdated for the camera height map in our old location we now adjust it by the difference between this point and the old one, rather than the total value of the height map. The Whole Process: -Location changes -Camera Height Changes due to Location Change -Custom Script checks how much the camera changed, and how much it should have changed -Custom Script adjusts CamZOffset to accomdate for the difference |
