About camera in field file.

  • Thread starter Thread starter Akari
  • Start date Start date
Status
Not open for further replies.
A

Akari

Guest
Could someone post source of programm that load camera matrix. I get confused with it.
 
Could someone post source of programm that load camera matrix. I get confused with it.
I believe this was discused when the walk map was being worked on in technical no?
Camera and walkmesh via Reunion
It doesn't seem to be there anymore (sigh) there was a huge long thing on the walk mesh information.  Someone had a nice viewer for it (unless that was you Akari :D)
 
Could someone post source of programm that load camera matrix. I get confused with it.
I believe this was discused when the walk map was being worked on in technical no?
Camera and walkmesh via Reunion
It doesn't seem to be there anymore (sigh) there was a huge long thing on the walk mesh information.  Someone had a nice viewer for it (unless that was you Akari :D)
I found description of sector 2 in this post https://www.ff7catalog.com/threads/1832/ as well as Kero programm that loads it. I has problems with signs of vectors... and maybe with something else. Just looking at code that loads this thing makes things much more clear.
 
Hiya,

If you're not averse to using glu then a simple gluLookAt is much easier. I've some code here if it helps but it's mostly the same as Kero's. For camera setup I've used the same internal structure except for floats for camera axes & instantiated an object from it:

Code: [Select]
Code:
cFieldCam.vy.x = -cFieldCam.vy.x;cFieldCam.vy.y = -cFieldCam.vy.y;cFieldCam.vy.z = -cFieldCam.vy.z;cFieldCam.oy = -cFieldCam.oy;cFieldCam.vx.x /= 4096.0f; cFieldCam.vx.y /= 4096.0f; cFieldCam.vx.z /= 4096.0f;cFieldCam.vy.x /= 4096.0f; cFieldCam.vy.y /= 4096.0f; cFieldCam.vy.z /= 4096.0f;cFieldCam.vz.x /= 4096.0f; cFieldCam.vz.y /= 4096.0f; cFieldCam.vz.z /= 4096.0f;tx = -(cFieldCam.ox*cFieldCam.vx.x + cFieldCam.oy*cFieldCam.vy.x + cFieldCam.oz*cFieldCam.vz.x);ty = -(cFieldCam.ox*cFieldCam.vx.y + cFieldCam.oy*cFieldCam.vy.y + cFieldCam.oz*cFieldCam.vz.y);tz = -(cFieldCam.ox*cFieldCam.vx.z + cFieldCam.oy*cFieldCam.vy.z + cFieldCam.oz*cFieldCam.vz.z);
You can compact those lines if you want, this just makes it a bit clearer. Then the display code is simply:

Code: [Select]
Code:
glScalef(-1.0, 1.0, 1.0);gluLookAt(tx, tz, ty, cFieldCam.vz.x, cFieldCam.vz.y, cFieldCam.vz.z, 0.0, 1.0, 0.0);
As you can see the z and y are flipped as per walkmesh vertices. I also find I have to scale the x-axis to flip the mesh as a whole, otherwise it renders the wrong way round but YMMV I guess as it could be something I've done wrong elsewhere.

Hope it helps.
 
Last edited:
Synergy Blades, could you post struct and code that reads values from file (the walkmesh and camera). My error might be in there.

Here s mine

Code: [Select]
Code:
voidDatFile::GetWalkMesh(TotalGeometry &walkmesh){    u32 offset_to_walkmesh = 0x1C + GetU32LE(0x04) - GetU32LE(0x00);    Geometry geometry;    geometry.TexEnabled = false;    u32 number_of_poly = GetU32LE(offset_to_walkmesh);    int start = offset_to_walkmesh + 0x04;    for (u32 i = 0; i < number_of_poly; ++i)    {        Vertex v[3];        v[0].p.x = -static_cast<s16>(GetU16LE(start + 0x00));        v[0].p.z =  static_cast<s16>(GetU16LE(start + 0x02));        v[0].p.y =  static_cast<s16>(GetU16LE(start + 0x04));        v[0].c.r = 1.0f; v[0].c.g = 0.0f; v[0].c.b = 0.0f; v[0].c.a = 1.0f;        v[1].p.x = -static_cast<s16>(GetU16LE(start + 0x08));        v[1].p.z =  static_cast<s16>(GetU16LE(start + 0x0A));        v[1].p.y =  static_cast<s16>(GetU16LE(start + 0x0C));        v[1].c.r = 1.0f; v[1].c.g = 0.0f; v[1].c.b = 0.0f; v[1].c.a = 1.0f;        v[2].p.x = -static_cast<s16>(GetU16LE(start + 0x10));        v[2].p.z =  static_cast<s16>(GetU16LE(start + 0x12));        v[2].p.y =  static_cast<s16>(GetU16LE(start + 0x14));        v[2].c.r = 1.0f; v[2].c.g = 0.0f; v[2].c.b = 0.0f; v[2].c.a = 1.0f;        geometry.AddTriangle(v);        // go to the next triangle        start += 0x18;    }    walkmesh.GeometryVector.push_back(geometry);}
Code: [Select]
Code:
voidDatFile::GetCameraMatrix(Matrix &camera){    u32 offset_to_camera = 0x1C + GetU32LE(0x0C) - GetU32LE(0x00);    // get camera matrix (3 vectors)    float vxx = static_cast<float>( static_cast<s16>(GetU16LE(offset_to_camera + 0x00))) / 4096.0f;    float vxy = static_cast<float>( static_cast<s16>(GetU16LE(offset_to_camera + 0x04))) / 4096.0f;    float vxz = static_cast<float>( static_cast<s16>(GetU16LE(offset_to_camera + 0x02))) / 4096.0f;    float vyx = static_cast<float>(-static_cast<s16>(GetU16LE(offset_to_camera + 0x06))) / 4096.0f;    float vyy = static_cast<float>(-static_cast<s16>(GetU16LE(offset_to_camera + 0x0A))) / 4096.0f;    float vyz = static_cast<float>(-static_cast<s16>(GetU16LE(offset_to_camera + 0x08))) / 4096.0f;    float vzx = static_cast<float>( static_cast<s16>(GetU16LE(offset_to_camera + 0x0C))) / 4096.0f;    float vzy = static_cast<float>( static_cast<s16>(GetU16LE(offset_to_camera + 0x10))) / 4096.0f;    float vzz = static_cast<float>( static_cast<s16>(GetU16LE(offset_to_camera + 0x0E))) / 4096.0f;    Matrix mat(vxx, vyx, vzx, 0,               vxy, vyy, vzy, 0,               vxz, vyz, vzz, 0,               0,   0,   0,   1);    // get camera position in world    s16 ox  =  static_cast<s16>(GetU16LE(offset_to_camera + 0x14));    s16 oy  = -static_cast<s16>(GetU16LE(offset_to_camera + 0x16));    s16 oz  =  static_cast<s16>(GetU16LE(offset_to_camera + 0x18));    float tx = -(ox * vxx + oy * vyx + oz * vzx);    float ty = -(ox * vxy + oy * vyy + oz * vzy);    float tz = -(ox * vxz + oy * vyz + oz * vzz);//    Matrix mat2;//    MatrixTranslation(mat2, -tx, -ty, -tz);//    printf("%f %f %f", tx, ty, tz);//    MatrixMultiply(camera, mat, mat2);    camera = LookAt(tx, ty, tz, vzx, vzy, vzz, 0, 1, 0);}
 
Sure. The only thing I can spot just browsing your code seems to be your camera space coords are using S16s, not S32s.

Code: [Select]
Code:
template <class type>struct WalkVertex{ type x, z, y, r; };template <class type>struct Camera{ Vertex<type>  vx, vy, vz; S16  repeat; S32  ox, oy, oz; S32  blank; S16  size;};...struct FF_CAMERA{ U32 nSectionLength; Camera<short> cCamera; // Repeat data - this is not always here so read section length first to ascertain how much to read in! S32 unknown1; Camera<short> cRepeatCamera;};...struct FF_WALKMESH{ U32 nSectionLength; U32 nSectors; vector< WalkVertex<S16> > cVertexList; vector<U16> cEdgeList;};
I've templated the camera so can instantiate a float camera for the later calculations more easily.

File read:

Code: [Select]
Code:
 // * SECTION TWO: Camera; get section length first as it varies in.seekg(cMemory->sHeader.pSections[1], ifstream::beg); in.read((char *)&cMemory->s2, sizeof(U32)); // - Now read in section based on section length, not struct size in.seekg(cMemory->sHeader.pSections[1], ifstream::beg); in.read((char *)&cMemory->s2, cMemory->s2.nSectionLength+4);... // * SECTION FIVE: Walkmesh in.seekg(cMemory->sHeader.pSections[4], ifstream::beg); in.read((char *)&cMemory->s5, 8); // - Vertex list WalkVertex<S16> cVert; for(int i = 0; i < (int)cMemory->s5.nSectors * 3; i++) {  in.read((char *)&cVert, sizeof(WalkVertex<S16>));  cMemory->s5.cVertexList.push_back(cVert); } // - Edges list U16 cAccess; for(int i = 0; i < (int)cMemory->s5.nSectors * 3; i++) {  in.read((char *)&cAccess, sizeof(U16));  cMemory->s5.cEdgeList.push_back(cAccess); }
The camera section length does actually vary, being one of two different lengths from file to file. For example, uutai1 has the 'section repeat' (length 0x4C) whereas church does not (length 0x26). Kero marked it down as not important but in testing I found that replacing the repeated data on uutai1 with blanks really messes it up - shrunken walkmesh and characters  (though I'm not sure if doing the same with the first set of data also messes the camera up, but I suspect not considering some fields don't need this extra data, but I will look into it further).
 
Last edited:
It seems that "gluLookAt(tx, tz, ty, cFieldCam.vz.x, cFieldCam.vz.y, cFieldCam.vz.z, 0.0, 1.0, 0.0);" is wrong because " cFieldCam.vz.x, cFieldCam.vz.y, cFieldCam.vz.z" (where you looking at) is not coords but just ortonormal vector and it always near center of world matrix. But a lot of meshes are not placed in center of the world.
 
Not to detract from the camera conversation. but it would be helpful to have some code to "overlay" the walkmesh over the background. This could be to detect alignment issues after most of the camera stuff is sorted out.

Keep in mind that some scenes have a "warped" projection. (The stairs in Shinra)


Here's an example of an "overlay" debug system from Sierra's AGI engine.
http://www.juhaterho.fi/agi/priority-explanation/

Keep in mind this is 2D, but helps track what's infront of who and where to do what.
 
Akari: isn't that sort of the point, that where the camera is pointing is down the z-axis - into the world? In which case the point where you want the camera to "look at" is anywhere along the z-axis? If the camera wasn't pointing at any point down the z-axis then surely the camera z-axis itself would be incorrect.

Halkun: fair point, this is the next thing I was looking at, but there's many factors that need to be taken into account; camera zoom (as Kero mentions, the camera covers the whole walkmesh, so it needs to be 'zoomed' to match the background), the Range in section 8 where the character can go off-center, and exactly where to place the image to align with the mesh. Also, what sort of warping are we talking about? I get the following walkmesh;

stairs.jpg


Interestingly the transition from stair-to-stair is not handled by a gateway in the usual fashion between fields on blinst_1 (there is no gateway where the top red arrow is, that's an added extra one) but rather, as far as I can tell, in the script for the field file; also the number of stairs on the mesh does not match the background image.
 
Last edited:
Akari: isn't that sort of the point, that where the camera is pointing is down the z-axis - into the world? In which case the point where you want the camera to "look at" is anywhere along the z-axis? If the camera wasn't pointing at any point down the z-axis then surely the camera z-axis itself would be incorrect.
XYZ vectors are normalized vectors that sets camera position. Z vector set direction, but not the point in worldspace.

camera = LookAt(tx, ty, tz, tx + vzx, ty + vzy, tz + vzz, /*vyx, vyy, vyz*/ 0, 1, 0);

This is correct and works in most backgrounds... not in all of them though =(

Try lo load "data/FIELD/MD1STIN.DAT". This one is placed somewhere in 200, 200, 40000
 
Hmm.. good point. Infact even the orthographic view I'm using is way, way off for that one. I calculated it just using the min/max x/z values for the walkmesh and setting the glOrtho accordingly...

ortho.JPG


Works fine for all others :? Could it be a stray walkmesh value that causes the bounding box to be off? Really not sure, but that wouldn't explain the camera.
 
Last edited:
Ah yes, now I remember from code long ago... field files with the same 'issue' that I have previously encountered:

ancnt2, ancnt3, ancnt4.

Though they are not as bad as in md1stin they are still 'off'. Might want to take a look at these in conjunction with md1stin and see if there's a common cause.
 
l'm on PSP
Hard to type.
look at fieldscript. May contain SCR2* and other camera opcodes.
Sony! why no keyboard on PSP?

===EDIT===
Midgar station is correct ^_^
it is position before camera swoops down during opening movie.
(at instant colordepth drops and guards are overlaid on movie)
fieldscript starts @ movie beginning, not end.
work on debug rooms 1st.
eaiser, they are.
 
Last edited:
l'm on PSP
Hard to type.
look at fieldscript. May contain SCR2* and other camera opcodes.
Sony! why no keyboard on PSP?
Best. Post. Ever.

it is position before camera swoops down during opening movie.
Ahah! Nice one, good thinking Batman. Debug rooms... fair enough, but their walkmeshes aren't that interesting  :-P By the way I've a script query - will PM you.
 
Thanks, I'm on a "real Computer" for the moment.

The camera can be changed in the script itself. The probelm is I don't know where the camera paths are. The actual engine is desigened to allow movies to be skipped. (You execute a SPECIAL opcode, I think subfunction 0xFE) to disable movies. When engaged, Map 74 (Midgar Station) will jump to the inital action of the charcters jumping off the train and kicking the guards.
 
Do you have a DS? Opera DS is coming out in Japan this month, and the touchscreen makes a much better keyboard than buttons and a D-pad.

also the number of stairs on the mesh does not match the background image.
Is that the part of the game right before sector 7 collapses? It seems to me that since it switches to an entirely different field for the top, it doesn't matter as long as there's a warp to that field. Unless I'm misunderstanding your point, then ignore me... :)
 
Do you have a DS? Opera DS is coming out in Japan this month, and the touchscreen makes a much better keyboard than buttons and a D-pad.

also the number of stairs on the mesh does not match the background image.
Is that the part of the game right before sector 7 collapses? It seems to me that since it switches to an entirely different field for the top, it doesn't matter as long as there's a warp to that field. Unless I'm misunderstanding your point, then ignore me... :)
Actually it's post Sector 7's demise because its from the Shinra building stair climb from heck.

Halkun, camera angles can be changed within the script? Dang! that might explain a few things.  Especially certain field areas where you move about the camera angle must change some.  Interesting.  For the Ps1 variant the script is already available (so to speak).  The field script must accept some input to skip a movie, I wonder if one can find the 'play movie' event and then find the end camera point from the opcode.
 
Yatta!!!1 Everything working. =)
Not trying to view second camera, but first is working everywhere.

ANCNT1
ANCNT1.gif


ANCNT4
ANCNT4.gif


CONDOR2
CONDOR2.gif


MD1STIN
MD1STIN.gif


MDS7
MDS7.gif


STARTMAP
STARTMAP.gif


Just as I say - camera = LookAt(tx, ty, tz, tx + vzx, ty + vzy, tz + vzz, vyx, vyy, vyz); - is true. Although I optimized this a little.

new camera reading
Code: [Select]
Code:
voidDatFile::GetCameraMatrix(Matrix &camera){    u32 offset_to_camera = 0x1C + GetU32LE(0x0C) - GetU32LE(0x00);    // get camera matrix (3 vectors)    float vxx = static_cast<float>(-static_cast<s16>(GetU16LE(offset_to_camera + 0x00))) / 4096.0f;    float vxy = static_cast<float>(-static_cast<s16>(GetU16LE(offset_to_camera + 0x04))) / 4096.0f;    float vxz = static_cast<float>(-static_cast<s16>(GetU16LE(offset_to_camera + 0x02))) / 4096.0f;    float vyx = static_cast<float>(-static_cast<s16>(GetU16LE(offset_to_camera + 0x06))) / 4096.0f;    float vyy = static_cast<float>(-static_cast<s16>(GetU16LE(offset_to_camera + 0x0A))) / 4096.0f;    float vyz = static_cast<float>(-static_cast<s16>(GetU16LE(offset_to_camera + 0x08))) / 4096.0f;    float vzx = static_cast<float>(-static_cast<s16>(GetU16LE(offset_to_camera + 0x0C))) / 4096.0f;    float vzy = static_cast<float>(-static_cast<s16>(GetU16LE(offset_to_camera + 0x10))) / 4096.0f;    float vzz = static_cast<float>(-static_cast<s16>(GetU16LE(offset_to_camera + 0x0E))) / 4096.0f;    // get camera position in world    s32 ox  = -static_cast<s32>(GetU32LE(offset_to_camera + 0x14));    s32 oy  = -static_cast<s32>(GetU32LE(offset_to_camera + 0x18));    s32 oz  = -static_cast<s32>(GetU32LE(offset_to_camera + 0x1C));    float tx = -(ox * vxx + oy * vyx + oz * vzx);    float ty = -(ox * vxy + oy * vyy + oz * vzy);    float tz = -(ox * vxz + oy * vyz + oz * vzz);    Matrix mat(-vxx, vyx, vzx, 0,               -vxy, vyy, vzy, 0,               -vxz, vyz, vzz, 0,               0,   0,   0,   1);    Matrix mat2;    MatrixTranslation(mat2, -tx, -ty, -tz);    MatrixMultiply(camera, mat, mat2);}
 
Looking good, is STARTMAP the debug room? It looks like it from the camera angle.
 
Status
Not open for further replies.
Back
Top