Kuribo64
Views: 19,850,236 Home | Forums | Uploader | Wiki | Object databases | IRC
Rules/FAQ | Memberlist | Calendar | Stats | Online users | Last posts | Search
03-28-24 09:14 AM
Guest:

0 users reading First Person View [v0.1 RELEASED] | 1 bot

Main - General SM64DS hacking - First Person View [v0.1 RELEASED] Hide post layouts | New reply


StarPants
Posted on 04-14-18 09:11 PM (rev. 2 of 06-02-18 06:01 PM) Link | #94066
Version 0.1 relesed!



Download: Patch + source code

-------------------------------------

ORIGINAL POST:

I thought it would be better to move this to its own thread so..

I'm currently working on a first person view hack. I will be posting my progress and/or problems here. I will also explain some details about what I exactly do to make this happen :)

Progress/Diary:

At first i did something like this (i don't remember the exact values):

#include "SM64DS_2.h"

void hook_020e50ac() {
CAMERA->pos = Vector3 {0x0_f, 0x0_f, 0x50000_f}.RotateYAndTranslate (PLAYER_ARR[0]->pos, PLAYER_ARR[0]->ang.y);
CAMERA->angle = PLAYER_ARR[0]->ang;
}

This however, made the camera go totally crazy because its position is apparently updated somewhere between my code and rendering. The game doesn't like it when the camera is in front of the player but looks away from the player.

Then i took a clean rom (patched with the editor though) and used no$gba's read/write breaks to find out where the camera's position is updated. I changed the instructions in the following addresses to "nop":

0203B710
0203B760
0203B1AC
0203B1C8
0203B1E8
0203B1F4
0205288C
020528A0
020528C4
020528D4
020528F8
02052908

After this the camera no longer moved, only rotated, as expected. As a side effect, any objects weren't visible to the camera, except player's shadow. Also, the players position on the minimap didn't match with the shadows position. The camera was pointing towards the shadow though. I have no idea why this happened since i only removed instructions that write to CAMERA->pos.

So, any ideas why all objects became invisible? Is removing instructions all around the game's code worth it or should i just find a better address to hook my code? Does anyone happen to know the address of the rendering function?

dy
Posted on 04-14-18 10:47 PM Link | #94067
Hey StarPants, it sounds like you're trying to put the camera in front of the player?

I haven't tested this, but I remember from looking at the Draw Distance function that if an object is behind the camera, it treats its distance as 0x7FFFFFFF (and so fails the draw distance check and isn't rendered). Maybe that's what's happening to the Player object here.

Try making the branch at 0x020110EC unconditional (or use the "Objects Always Visible" patch in SM64DSe's additional patches) - this will kill your frame rate, but if the Player becomes visible, now you know what's causing it. To fix, just check if r4 (object address) is the Player's address (the address stored at 0x0209F394), and if so make the relevant branch irrespective of draw distance.


PS: just read your post again - previously I think you were just having trouble with the Player object being invisible, is it now affecting all objects?

____________________

- ASM resource for customising behaviour of player/objects/levels
- NSMBe with direct overwrite feature

StarPants
Posted on 04-15-18 08:37 AM Link | #94074
Yeah all the objects were invisible, and the camera wasn't even in the players position yet. It was fixed in one place on purpose. I wanted to remove all the instructions that write to CAMERA->pos so that the games own code doesn't mess things up.

I'm not planning to put the camera in front of the player really. If I just did this

void hook_020e50ac() {
CAMERA->pos = PLAYER_ARR[0]->pos;
}

the camera would stare at players butt, which is not what I want. I want the camera as close to the players eyes as possible.

I'll try that "Objects Always Visible" patch to see if it changes anything.

dy
Posted on 04-16-18 12:20 PM (rev. 4 of 04-16-18 12:24 PM) Link | #94092
StarPants - how did you go with the Objects Always Visible patch?

I was playing around with camera settings and discovered 2 things:

1. You can create a quick and dirty "sort-of" first person view (actually 3rd person, but it will mostly follow the player) by going into the level editor > "CLPS" and:
(a) changing all the ViewID entries to 63 (so the camera always follows you rather than trying to move to any pre-defined camera angles)
(b) changing all the Camera Type entries to either 0 or 6 (0: camera rotates slowly to face in the same direction as the player, 6: camera only rotates when the player is moving)

2. While I was doing the above, I noticed 2 times when the camera would still do its own thing (must be hardcoded, there might be more scenarios too). In the Bowser boss battles, and just after you come through an intra-level door (one that takes you to another area in the same level, eg painting room doors). Just after you come through such a door, the camera gets really close and rotates really FAST to face whichever direction you're facing (eg, try coming through a door, then turning around without going back through the door).

If you could make the camera do that all the time, it'd probably give you a pretty good first/third person view mode.

Maybe you could try:
1. setting some breakpoints to work out what function is doing that fast camera rotation
2. breakpoint all the times the camera position/angle is adjusted - and click through to work out which is the last one that runs before the frame updates (eg, do it somewhere where there's a spinning coin or something)
3. create a hook somewhere after that which calls the function you found in #1

____________________

- ASM resource for customising behaviour of player/objects/levels
- NSMBe with direct overwrite feature

StarPants
Posted on 04-16-18 01:23 PM (rev. 2 of 04-16-18 01:25 PM) Link | #94093
Actually i didn't try the patch thing yet because

a) i found out that it was very probably one of the first three instructions in the previous list that was causing the invisibility of all objects (i suppose str is a safe instruction to remove, is that the case with stmia, stmib, streq, etc? (I don't know the ARM instruction set that well yet)

b) I changed my plan so that i will not delete any of the games own instructions, since that apparently makes things unstable. Instead, i will find out where the general rendering code is, and hook my code just before that. This way (hopefully) i can overwrite any changes to camera made by the original code.

I changed the camera behavior of all materials to "Normal" and camera-go-through to true to make things simpler.

I found out that touching to CAMERA->angle was causing most of my problems and i should use CAMERA->lookAt instead. It's not a unit vector that tells the cameras orientation as I stupidly first thought, but a point (vector from origin) the camera looks at.

My current approach for the code is to put the camera to the same place as the player's head bone, with an offset vector. This is because i want the camera to follow the player's head movements. For example, when eating with Yoshi, it would be stupid if the camera didn't go down with his head. I also want that when the player does flips, the camera flips too.

..and i completely forgot that such thing as views existed in this game lol. I might want to just delete them all :P

dy
Posted on 04-16-18 01:30 PM Link | #94094
No - stm instructions are 'store multiple', so that would be a problem if you were nop'ing those!

____________________

- ASM resource for customising behaviour of player/objects/levels
- NSMBe with direct overwrite feature

StarPants
Posted on 04-16-18 01:34 PM Link | #94095
Ok that explains a lot

dy
Posted on 04-16-18 02:46 PM Link | #94099
Also, what exactly did you do to get those memory addresses in your first post?

Some of them trigger whether or not the camera position/angle is changing. And the memory addresses that they write to are all over the place - I set a read breakpoint on some of the memory addresses they write to, and they don't seem to correlate with the camera position/angle...

Do you know the actual memory address where the camera angle/rotation is stored?

____________________

- ASM resource for customising behaviour of player/objects/levels
- NSMBe with direct overwrite feature

StarPants
Posted on 04-16-18 07:08 PM (rev. 3 of 04-16-18 07:41 PM) Link | #94109
Posted by dy
Also, what exactly did you do to get those memory addresses in your first post?

The first thing i did was printing the memory addresses of the x, y and z coordinates of the camera.

fpv.h:

#include "SM64DS_2.h"

extern "C"
{
/* This function is defined in print.s from ASM Hack Template v1,
possibly written by Fiachra or Dirbaio. */

void nocashPrint(const char* txt);
}

void HexPrint(unsigned int value, char *result);

fpv.cpp:

#include "FPV.h"

void HexPrint(unsigned int value, char *result) // This is also from the ASM hack template v1
{
byte i = 0;
byte current = 0xFF;
while (i < 8)
{
current = (byte)((value >> i * 4) & 0x0F);
result[7 - i] = (char)(current + ((current < 10) ? 48 : 55));
i++;
}
}

void hook_020e50ac()
{
char string[8];

HexPrint ((int)&(CAMERA->pos.x), string);
nocashPrint (string);

HexPrint ((int)&(CAMERA->pos.y), string);
nocashPrint (string);

HexPrint ((int)&(CAMERA->pos.z), string);
nocashPrint (string);
}

I don't know how much you know C++ but in this case & works as an address-of operator, which is pretty handy for our purposes imo.

Now it should repeatedly print three consecutive addresses to the TTY Debug window. In my case, they are 0218638C, 02186390 and 02186394. Use Desmume's RAM Watch and you'll see that the values in these addresses change accordingly to the cameras position. (Desmume can also display debug messages with its console but it can be glitchy) I think Desmume's RAM Watch is much better for certain things than No$gba's data window.

Then i made a membreak like this:
[0218638C..02186394]!!

This way, it breaks even if the new value is the same as the old one because there were two exclamation marks.

If you see no correlation between these membreaks and cameras position, make sure you have just one exclamation mark. Even then, you won't necessarily be able to see any changes since the position might be changing only 1/4096 fxu per frame. Also, the instructions in the addresses in the first post are not the only instructions that write to CAMERA->pos. For me, nop'ing them worked as i expected though. Surely there were some side effects but that was kinda expected too since i was nop'ing instructions i didn't exactly know. I guess i didn't expect a reduced instruction set computer to be able to write to multiple mem addresses at once.

By the way, any clue of the rendering code?

dy
Posted on 04-17-18 04:41 AM (rev. 4 of 04-17-18 05:22 AM) Link | #94113
Hey, that's pretty clever - I didn't think of that.

In the end I managed to find it by setting a breakpoint on INPUT_PERSISTENT (0x0209F49C) to see how the game handled rotating the camera when the L Button is pressed - the 2 relevant addresses were offset 0x80 and 0x8C of the camera object. That's when I realised you can use SM64DS_2.h to work it out, you just have to back-calculate it using sizes of known data types:

[thumbnail]

Knowing that will make research a bit easier going forward!! Be mindful that the camera object address changes for different levels though, so best way to get the 'pos' and ''lookAt" vectors is by getting the camera's object address (which is the address stored at 0x0209F318 according to symbols.x), then adding the relevant offset.


You did do something not so clever by the way... those instructions you nop'd aren't only used for updating the camera vectors (set a direct breakpoint for "0203B710" and look at 'r0' each time it's triggered, you'll see what I mean - it gets called a LOT to store things to all sorts of different addresses). No wonders everything was going haywire!! ?

Anyway, I think I've found a good place for you to hook your code. Try 0x0200DA04 (I found it by setting a write breakpoint on INV_VIEW_MATRIX_ASR_3 - it is written to in one of the standard matrix math routines, so I had to trace backwards a bit to find the function that was updating the view matrices). It is called once a frame, and after the camera vector gets updated (which makes sense, since it would be updating the view matrix based on where the camera is). (EDIT: 0x0200DA04 is the start of the function, but not sure if it's safe to hook there as it is saving r14 (LR) there. Maybe hook at 0x0200DA0C instead.)


Before you go to all the work of making a first person view tied to the player's head bone though, try the following. I made a quick patch to trick the game into thinking you are always holding the L Button.

test.s
nsub_0200A5B4:
b 0x0200A5F8

nsub_0200A618:
b 0x0200A628

nsub_0200A62C:
b 0x0200A640

nsub_0200A640:
ldr r1, [r8,#0x110]
add r0, r8, #0x100
ldrsh r1, [r1,#0x8E]
b 0x0200A650

nsub_0200A658:
add r1, r1, #0x8000
strh r1, [r0,#0x9E]
b 0x0200A660

Then go to one of the harder platforming levels (eg, Goomboss or Bowser) and see if you actually like the way the camera moves - I personally found it quite disorienting, because you turn so quickly when you're not moving and you can't use the mouse to look around like in FPS games. Also, try wall jumping. I imagine the effect will be even more pronounced in proper first person view, because the camera will move even faster. Can you imagine trying to control Luigi's helicopter jump??

____________________

- ASM resource for customising behaviour of player/objects/levels
- NSMBe with direct overwrite feature

StarPants
Posted on 04-19-18 08:44 PM Link | #94128
Thanks a lot for that address. When i was using the old address the cameras position changed once or twice during the opening cutscene but that doesn't happen anymore, which is good. The camera is now more overall stable, too. So, no need to nop anything anymore.

I also found it quite disorienting to play with "L pressed down" but believe me, it feels much better when the camera is up close because the camera will actually not move as quickly (I have tried it already). I know that wall jumping will be harder but that's ok. I don't really care that much if Luigi's backflips become impossible to control because they're too op anyway.

I've already succeeded with attaching the camera to the player's head bone. Here's the code if you want to try it out:

#include "SM64DS_2.h"

extern "C"
{
void nocashPrint(const char* txt);
}

void HexPrint(unsigned int value, char *result);

#include "FPV.h"

void HexPrint(unsigned int value, char *result) // Credits to Dirbaio or Fiachra for the printing code
{
byte i = 0;
byte current = 0xFF;
while (i < 8)
{
current = (byte)((value >> i * 4) & 0x0F);
result[7 - i] = (char)(current + ((current < 10) ? 48 : 55));
i++;
}
}

void hook_0200da0c()
{
constexpr u8 supposedlyYoshi = 3;

Matrix4x3* transform;
transform = PLAYER_ARR[0]->bodyModels[supposedlyYoshi]->data.transforms;

Vector3 playerXaxis = Vector3 {
PLAYER_ARR[0]->bodyModels[supposedlyYoshi]->mat4x3.r0c0,
PLAYER_ARR[0]->bodyModels[supposedlyYoshi]->mat4x3.r1c0,
PLAYER_ARR[0]->bodyModels[supposedlyYoshi]->mat4x3.r2c0
};
Vector3 playerYaxis = Vector3 {
PLAYER_ARR[0]->bodyModels[supposedlyYoshi]->mat4x3.r0c1,
PLAYER_ARR[0]->bodyModels[supposedlyYoshi]->mat4x3.r1c1,
PLAYER_ARR[0]->bodyModels[supposedlyYoshi]->mat4x3.r2c1
};
Vector3 playerZaxis = Vector3 {
PLAYER_ARR[0]->bodyModels[supposedlyYoshi]->mat4x3.r0c2,
PLAYER_ARR[0]->bodyModels[supposedlyYoshi]->mat4x3.r1c2,
PLAYER_ARR[0]->bodyModels[supposedlyYoshi]->mat4x3.r2c2
};

Vector3 x_axis = playerXaxis * transform[15].r0c0 // X and not Z axis because reasons
+ playerYaxis * transform[15].r1c0
+ playerZaxis * transform[15].r2c0;

Vector3 pos = playerXaxis * transform[15].r0c3
+ playerYaxis * transform[15].r1c3
+ playerZaxis * transform[15].r2c3;

CAMERA->pos = PLAYER_ARR[0]->pos + (pos << 3);
CAMERA->lookAt = CAMERA->pos + x_axis;

char* string;
HexPrint ((int)&x_axis, string);
nocashPrint (string);
}

This code only works with Yoshi. There isn't an offset vector yet so the camera is somewhere in the player's neck but that will be changed later. If you try it you'll know that attaching the camera to player's head bone isn't exactly optimal, but i have plans how this could be improved drastically.


I needed to be able to read bone matrices in order to attach the camera to the bone. It was kinda confusing that there aren't matrices in the Bone struct in SM64DS_2.h. I mean, here it is:

struct Bone
{
unsigned unk00;
unsigned unk04;
unsigned unk08;
Vector3 scale;
uint16_t unk18;
Vector3_16 rot;
Vector3 pos;
unsigned unk2c;
unsigned unk30;
};

I thought that one of those unknown variables could be a pointer to a matrix, but ended up never experimenting them in ram watch because I found a pointer to the bone matrix elsewhere. It was actually pointed by 'transforms' in the ModelComponents struct:

struct ModelComponents
{
char* modelFile;
Material* materials;
Bone* bones;
Matrix4x3* transforms;
char* unk10;

void UpdateBones(char* animFile, int frame);
void UpdateVertsUsingBones();
};

That's pretty weird i think. Maybe it points to the same place as one of the unknown variables in Bone struct but i dunno, haven't tried.

mibts
Posted on 04-23-18 06:00 AM Link | #94156
SM64DS likes to store the bones and their transforms in different places. Also, those unknown variables don't point to transforms.

____________________
Current hack: Excerpt from Super Mario 256

Any map on a flat torus can be colored with at most 7 colors.

StarPants
Posted on 04-23-18 06:58 AM Link | #94157
Ok thanks. Btw i absolutely love your header files

dy
Posted on 04-24-18 01:33 AM Link | #94173
Hey, just tried this - what an experience! I'm actually really impressed with how well you got it to follow Yoshi's head movements (a little too well haha - Yoshi needs to hold still!)

You are right though about it not being as disorienting when the camera's up close. You can try my "L button held down" code again with the CLPS CameraBehaviour set to 11 (the close up camera) - apart from not following the player when it jumps and not keeping up with spin jumps, I actually think it works quite well. It gives a similar feel to FPV in that it puts you in Yoshi's perspective and makes the world and objects look bigger (like they would to Yoshi), but makes it a bit easier to land jumps and you can also still see the character (which I quite like, but not sure about you).

Good work!

____________________

- ASM resource for customising behaviour of player/objects/levels
- NSMBe with direct overwrite feature

StarPants
Posted on 04-24-18 08:29 AM Link | #94175
Indeed, "L held down" feels better when the camera is closer. However, that's not what I want for this hack because this is kinda inspired by Kaze's sm64 first person and I want this to be similiar, only better and more enjoyable. Also, when the camera was more stable (when it didn't follow the head bone yet) jumping felt like I was playing a first person shooter and I like that.

I have plenty of tricks to stabilize the camera such as locking/reducing its orientation in relation to player's root bone while walking/running. I'm also going to limit player's turning speed because turning 180° in one frame is disorienting enough in third person. I'm starting to think that programming different camera behaviors for most common animation states might be worth it in order to make this more playable.

dy
Posted on 04-24-18 10:05 AM Link | #94177
Fair enough. Look forward to seeing the end result. Limiting turning speed sounds good. Only other thing that jumps to mind is to think about what to do during star cutscenes (like when you step on star switch or the star disappears) - I anticipate it might feel jarring if everything just freezes suddenly without a star camera. Good luck!

____________________

- ASM resource for customising behaviour of player/objects/levels
- NSMBe with direct overwrite feature

StarPants
Posted on 05-14-18 05:57 PM Link | #94309
Today I "unlocked" all characters! Well, that actually wasn't anything big but it wasn't that obvious at first that the current character was stored in the player's parameter 1.

Anyway, I now have a system that allows me to set different "settings" for different animation states, characters, etc. It also allows me to change the length of the offset vector. (not anything too fancy as it basically consists of an enum and a switch-case.)

The 8 bit long settings currently include:

- whether or not the camera's orientation follows the head bone in x direction
- whether or not the camera's orientation follows the head bone in y direction
- whether or not the camera's position follows the head bone in x direction
- whether or not the camera's position follows the head bone in y direction
- is camera looking at a horizontal angle
- is first person view used at all
- any combinations of the above (bitwise or is handy btw)

The camera is fixed to the player's root bone if everything is zero. Despite this, the default settings are the four first settings combined. (There are some intentional exceptions in the vector math but they aren't really necessary to mention)

The turning speed is limited, but turning 180° in place could work a little better.

I have set the best settings (in my opinion) to the most common states but there are still many states to do. I've been a bit busy the past weeks and setting the settings is quite time consuming. I'll release an alpha version of this with the source code once I do a few more states and fix some issues.

StarPants
Posted on 06-02-18 06:01 PM Link | #94506
I haven't done much progress since the last update because I've been working on other things, but I decided to finally upload the current version anyway. See the first post.


Main - General SM64DS hacking - First Person View [v0.1 RELEASED] Hide post layouts | New reply

Page rendered in 0.049 seconds. (2048KB of memory used)
MySQL - queries: 29, rows: 235/235, time: 0.009 seconds.
[powered by Acmlm] Acmlmboard 2.064 (2018-07-20)
© 2005-2008 Acmlm, Xkeeper, blackhole89 et al.