What format should I use for animated models?

Graphic based area of development (Graphics Processing Unit), including the Geometry Transform Engine (GTE), TIM, STR (MDEC), etc.
Post Reply
User avatar
ArthCarvalho
Active PSXDEV User
Active PSXDEV User
Posts: 45
Joined: Jan 29, 2016
I am a: Artist, Programmer
PlayStation Model: SCPH-103

What format should I use for animated models?

Post by ArthCarvalho » November 26th, 2019, 8:49 am

Hello everyone,

What is better? Should I create an animation format from the scratch or is using HMD a good option?
My objective is to have both hierarchical animation (each limb is made of separate meshes) and "skeletal" animation.

I do have an idea of how skeletal animation works and I could create my own format, but the most important thing is that it must be (relatively) fast so it doesn't take too much memory or CPU time. At least for my project, there should be about 3 to 4 (counting the player) complex animated objects on screen on a single frame at worst. (Since gameplay is divided by rooms and complex objects are not common on screen, for most part of other objects I probably can get away by simply rotating their models instead)

User avatar
Shadow
Verified
Admin / PSXDEV
Admin / PSXDEV
Posts: 2670
Joined: Dec 31, 2012
PlayStation Model: H2000/5502
Discord: Shadow^PSXDEV

Post by Shadow » November 26th, 2019, 12:22 pm

Best to start with the Sony HMD library to get an understanding of how it works, and if it's not good enough I'd then make your own :)
Development Console: SCPH-5502 with 8MB RAM, MM3 Modchip, PAL 60 Colour Modification (for NTSC), PSIO Switch Board, DB-9 breakout headers for both RGB and Serial output and an Xplorer with CAETLA 0.34.

PlayStation Development PC: Windows 98 SE, Pentium 3 at 400MHz, 128MB SDRAM, DTL-H2000, DTL-H2010, DTL-H201A, DTL-S2020 (with 4GB SCSI-2 HDD), 21" Sony G420, CD-R burner, 3.25" and 5.25" Floppy Diskette Drives, ZIP 100 Diskette Drive and an IBM Model M keyboard.

rama3
Verified
/// PSXDEV | ELITE ///
/// PSXDEV | ELITE ///
Posts: 510
Joined: Apr 16, 2017

Post by rama3 » November 26th, 2019, 10:38 pm

And if you think you need to limit CPU time spent, then tripple up that demand. The CPU is *slow* ;p

User avatar
Shadow
Verified
Admin / PSXDEV
Admin / PSXDEV
Posts: 2670
Joined: Dec 31, 2012
PlayStation Model: H2000/5502
Discord: Shadow^PSXDEV

Post by Shadow » November 27th, 2019, 1:17 am

rama3 wrote: November 26th, 2019, 10:38 pm ... the CPU is *slow* ;p
By today's standards, yes. Back in the early nineties, no :D
Development Console: SCPH-5502 with 8MB RAM, MM3 Modchip, PAL 60 Colour Modification (for NTSC), PSIO Switch Board, DB-9 breakout headers for both RGB and Serial output and an Xplorer with CAETLA 0.34.

PlayStation Development PC: Windows 98 SE, Pentium 3 at 400MHz, 128MB SDRAM, DTL-H2000, DTL-H2010, DTL-H201A, DTL-S2020 (with 4GB SCSI-2 HDD), 21" Sony G420, CD-R burner, 3.25" and 5.25" Floppy Diskette Drives, ZIP 100 Diskette Drive and an IBM Model M keyboard.

rama3
Verified
/// PSXDEV | ELITE ///
/// PSXDEV | ELITE ///
Posts: 510
Joined: Apr 16, 2017

Post by rama3 » November 27th, 2019, 1:40 am

No no, the GTE is fast and the GPU can deliver. But that CPU core for your basic game loop, that is a dog :p

User avatar
ArthCarvalho
Active PSXDEV User
Active PSXDEV User
Posts: 45
Joined: Jan 29, 2016
I am a: Artist, Programmer
PlayStation Model: SCPH-103

Post by ArthCarvalho » November 27th, 2019, 9:09 am

I'm just being cautious here, since I've never coded for low end machines, specially ones that are over 20 years old.
So I have no idea of how much CPU power I am using or how much it has available for me, so I'm threading on the cautious side. If I try to imagine the PlayStation CPU as any less powerful it'll be equivalent to the processor of a pocket calculator.

After reading the documentation I noticed that libhmd is dependent on libgs, since I'm not using libgs this pretty much rules out using HMD.

I made a dancing cube thing ouf of a box model and created a hierarchy transformation so it would wiggle using a sine function so I could test the performance of this on a real console later.
[BBvideo=560,315]https://www.youtube.com/watch?v=SrgE7Jahjvk[/BBvideo]

The code for it is like this:

Code: Select all

    // Wiggling Cube
    test_cube_obj.matrix = m_identity;
    temp_vec.vx = icos(temp_counter%4096)>>5;
    temp_vec.vy = 0;
    temp_vec.vz = 0;
    RotMatrix_gte(&temp_vec,&test_cube_obj.matrix);
    CompMatrixLV(&camera.view_matrix, &test_cube_obj.matrix, &test_cube_obj.matrix);
    gte_SetTransMatrix(&test_cube_obj.matrix);
    gte_SetRotMatrix(&test_cube_obj.matrix);
    packet_b_ptr = SGM_UpdateModel(&test_cube_model, packet_b_ptr, (u_long*)G.pOt);
    
    // Wiggling Cube 2
    temp_mat = test_cube_obj.matrix;
    temp_vec.vx = isin(temp_counter%4096)>>5;
    temp_vec.vy = 0;
    temp_vec.vz = 0;
    temp_vec_p.vx = 0;
    temp_vec_p.vy = 154;
    temp_vec_p.vz = 0;
    
    RotMatrix_gte(&temp_vec,&test_cube_obj.matrix);
    TransMatrix(&test_cube_obj.matrix,&temp_vec_p);
    CompMatrix(&temp_mat, &test_cube_obj.matrix, &test_cube_obj.matrix);
    temp_mat2 = test_cube_obj.matrix;
    gte_SetTransMatrix(&test_cube_obj.matrix);
    gte_SetRotMatrix(&test_cube_obj.matrix);
    packet_b_ptr = SGM_UpdateModel(&test_cube_model, packet_b_ptr, (u_long*)G.pOt);
    
    
    // Wiggling Cube the 3rd
    temp_vec.vx = icos(temp_counter%4096)>>4;
    temp_vec.vy = 0;
    temp_vec.vz = 0;
    temp_vec_p.vx = 0;
    temp_vec_p.vy = 154;
    temp_vec_p.vz = 154;
    
    RotMatrix_gte(&temp_vec,&test_cube_obj.matrix);
    TransMatrix(&test_cube_obj.matrix,&temp_vec_p);
    CompMatrix(&temp_mat, &test_cube_obj.matrix, &test_cube_obj.matrix);
    
    gte_SetTransMatrix(&test_cube_obj.matrix);
    gte_SetRotMatrix(&test_cube_obj.matrix);
    packet_b_ptr = SGM_UpdateModel(&test_cube_model, packet_b_ptr, (u_long*)G.pOt);
    
    // Wiggling Cube HD Remix ULTRA
    temp_vec.vx = icos(temp_counter%4096)>>3;
    temp_vec.vy = 0;
    temp_vec.vz = 0;
    temp_vec_p.vx = 0;
    temp_vec_p.vy = 154;
    temp_vec_p.vz = -154;
    
    RotMatrix_gte(&temp_vec,&test_cube_obj.matrix);
    TransMatrix(&test_cube_obj.matrix,&temp_vec_p);
    CompMatrix(&temp_mat, &test_cube_obj.matrix, &test_cube_obj.matrix);
    
    gte_SetTransMatrix(&test_cube_obj.matrix);
    gte_SetRotMatrix(&test_cube_obj.matrix);
    packet_b_ptr = SGM_UpdateModel(&test_cube_model, packet_b_ptr, (u_long*)G.pOt);
    
    // Wiggling Cube Origins
    temp_vec.vx = icos(temp_counter%4096)>>3;
    temp_vec.vy = 0;
    temp_vec.vz = 0;
    temp_vec_p.vx = 0;
    temp_vec_p.vy = 154;
    temp_vec_p.vz = 0;
    
    RotMatrix_gte(&temp_vec,&test_cube_obj.matrix);
    TransMatrix(&test_cube_obj.matrix,&temp_vec_p);
    CompMatrix(&temp_mat2, &test_cube_obj.matrix, &test_cube_obj.matrix);
    
    gte_SetTransMatrix(&test_cube_obj.matrix);
    gte_SetRotMatrix(&test_cube_obj.matrix);
    packet_b_ptr = SGM_UpdateModel(&test_cube_model, packet_b_ptr, (u_long*)G.pOt);
    
    // Wiggling Cube Returns
    temp_mat2 = test_cube_obj.matrix;
    temp_vec.vx = icos(temp_counter%4096)>>2;
    temp_vec.vy = 0;
    temp_vec.vz = 0;
    temp_vec_p.vx = 0;
    temp_vec_p.vy = 154;
    temp_vec_p.vz = 0;
    
    RotMatrix_gte(&temp_vec,&test_cube_obj.matrix);
    TransMatrix(&test_cube_obj.matrix,&temp_vec_p);
    CompMatrix(&temp_mat2, &test_cube_obj.matrix, &test_cube_obj.matrix);
    
    gte_SetTransMatrix(&test_cube_obj.matrix);
    gte_SetRotMatrix(&test_cube_obj.matrix);
    packet_b_ptr = SGM_UpdateModel(&test_cube_model, packet_b_ptr, (u_long*)G.pOt);

User avatar
NITROYUASH
Verified
Serious PSXDEV User
Serious PSXDEV User
Posts: 124
Joined: Jan 07, 2018
I am a: Game Designer
PlayStation Model: SCPH-5502
Location: Russian Federation
Contact:

Post by NITROYUASH » November 27th, 2019, 3:18 pm

Just one question.
Can we see what inside SGM_UpdateModel() function ? :)

User avatar
ArthCarvalho
Active PSXDEV User
Active PSXDEV User
Posts: 45
Joined: Jan 29, 2016
I am a: Artist, Programmer
PlayStation Model: SCPH-103

Post by ArthCarvalho » November 27th, 2019, 5:26 pm

It's a function that transforms vertices from a specific model and adds them to the ordering table.
Not optimized yet and messy due to constant format changes and idea changes and it's format specific.

I don't think it is worth looking at separately but here it is anyway:

Code: Select all

u_char * SGM_UpdateModel(SGM_MDL * model, u_char * packet_ptr, u_long * ot) {
  int i;
  
  SGM_FILE * data = model->file;
  SGM_DATAHEADER * dh = data->dh;
  
  u_short tpageid;
  u_short clutid;
  
  // Transformation Data
  long	p, otz, opz, flg;
	int temp, temp2, temp3;
	int	isfront;
  
  DIVPOLYGON4 divprop;
  
  POLY_GT4_VERTEX * vtx_src_gt4;
  POLY_GT4_TEX * tex_src_gt4;
  POLY_GT4_COLOR * col_src_gt4;
  
  POLY_GT3_VERTEX * vtx_src_gt3;
  POLY_GT3_TEX * tex_src_gt3;
  POLY_GT3_COLOR * col_src_gt3;
  
  POLY_GT4 * vtx_dest_gt4;
  POLY_GT3 * vtx_dest_gt3;
  POLY_G4 * vtx_dest_g4;
  POLY_G3 * vtx_dest_g3;
  
  u_char * packet = packet_ptr;
  
  divprop.pih = SCREEN_W;
  divprop.piv = SCREEN_H;
  divprop.ndiv = 1;
  
  vtx_dest_gt4 = (POLY_GT4*)packet;
  
  tpageid = getTPage(1, 0, 0,0);
  clutid = GetClut(0,256);
  
  vtx_src_gt4 = data->pgt4_vtx;
  
  for(i = 0; i < model->file->dh->poly_gt4_count; i++, vtx_src_gt4++) {
    // Initialize destination poly
    setPolyGT4(vtx_dest_gt4);
    
    // Transform destination poly
    gte_RotAverageNclip3(
			(SVECTOR*)&vtx_src_gt4->v0,
			(SVECTOR*)&vtx_src_gt4->v1,
			(SVECTOR*)&vtx_src_gt4->v2,
			(long *)&vtx_dest_gt4->x0, (long *)&vtx_dest_gt4->x1,
			(long *)&vtx_dest_gt4->x2, &p, &otz, &flg, &isfront);
    
    otz = otz >> 1;
    // Check side
    if(isfront <= 0) continue;
    
    // Only transform 4th vector if facing towards the view
    gte_RotTransPers((SVECTOR*)&vtx_src_gt4->v3,(long *)&vtx_dest_gt4->x3, &temp2, &temp3, &temp);
    
    // Clip quads that are offscreen
    if(quad_clip(&G.screen_rect,
              (DVECTOR*)&vtx_dest_gt4->x0,
              (DVECTOR*)&vtx_dest_gt4->x1,
              (DVECTOR*)&vtx_dest_gt4->x2,
              (DVECTOR*)&vtx_dest_gt4->x3)) continue;
              
    // If on screen, now process the rest of the primitive.
    tex_src_gt4 = &data->pgt4_uv[i];
    col_src_gt4 = &data->pgt4_col[i];
    // Set Vertex Colors
    memcpy(&vtx_dest_gt4->r0, &col_src_gt4->r0, sizeof(u_char) * 3);
    memcpy(&vtx_dest_gt4->r1, &col_src_gt4->r1, sizeof(u_char) * 3);
    memcpy(&vtx_dest_gt4->r2, &col_src_gt4->r2, sizeof(u_char) * 3);
    memcpy(&vtx_dest_gt4->r3, &col_src_gt4->r3, sizeof(u_char) * 3);
    // Set Texture Coordinates
    memcpy(&vtx_dest_gt4->u0, &tex_src_gt4->u0, sizeof(u_char) * 2);
    memcpy(&vtx_dest_gt4->u1, &tex_src_gt4->u1, sizeof(u_char) * 2);
    memcpy(&vtx_dest_gt4->u2, &tex_src_gt4->u2, sizeof(u_char) * 2);
    memcpy(&vtx_dest_gt4->u3, &tex_src_gt4->u3, sizeof(u_char) * 2);
    
    // Set CLUT
    vtx_dest_gt4->clut = clutid;
    // Set Texture Page
    vtx_dest_gt4->tpage = tpageid;
    
    if (otz > 0 && otz < OTSIZE)
    {
      // Check for subdivision
      if( otz < 600 ) {
        if(otz > 300) {
          divprop.ndiv = 1;
          debug_face_count += 8;
        } else {
          divprop.ndiv = 1;
          debug_face_count += 8;
        }
        debug_subdiv_count += 1;
        // Subdivide poly
        vtx_dest_gt4 = DivideGT4(
          (SVECTOR*)&vtx_src_gt4->v0, (SVECTOR*)&vtx_src_gt4->v1, (SVECTOR*)&vtx_src_gt4->v2, (SVECTOR*)&vtx_src_gt4->v3,
          (u_long*)&vtx_dest_gt4->u0, (u_long*)&vtx_dest_gt4->u1, (u_long*)&vtx_dest_gt4->u2, (u_long*)&vtx_dest_gt4->u3,
          (CVECTOR*)&vtx_dest_gt4->r0, (CVECTOR*)&vtx_dest_gt4->r1, (CVECTOR*)&vtx_dest_gt4->r2, (CVECTOR*)&vtx_dest_gt4->r3,
          vtx_dest_gt4, (u_long *)(ot+otz), &divprop);
      } else {
        // Add primitive to Ordering Table and advance pointer
        // to point to the next primitive to be processed.
        AddPrim(ot+otz, vtx_dest_gt4++);
        debug_face_count += 2;
      }
    }
  }
  
  vtx_dest_gt3 = (POLY_GT3*)vtx_dest_gt4;
  vtx_src_gt3 = data->pgt3_vtx;

  for(i = 0; i < model->file->dh->poly_gt3_count; i++, vtx_src_gt3++) {
    // Initialize destination poly
    setPolyGT3(vtx_dest_gt3);
    
    // Transform destination poly
    gte_RotAverageNclip3(
			(SVECTOR*)&vtx_src_gt3->v0,
			(SVECTOR*)&vtx_src_gt3->v1,
			(SVECTOR*)&vtx_src_gt3->v2,
			(long *)&vtx_dest_gt3->x0, (long *)&vtx_dest_gt3->x1,
			(long *)&vtx_dest_gt3->x2, &p, &otz, &flg, &isfront);
    otz = otz >> 1;
    // Check side
    if(isfront <= 0) continue;
    
    // Clip quads that are offscreen
    if(tri_clip(&G.screen_rect,
              (DVECTOR*)&vtx_dest_gt3->x0,
              (DVECTOR*)&vtx_dest_gt3->x1,
              (DVECTOR*)&vtx_dest_gt3->x2)) continue;
              
    // If on screen, now process the rest of the primitive.
    tex_src_gt3 = &data->pgt3_uv[i];
    col_src_gt3 = &data->pgt3_col[i];
    // Set Vertex Colors
    memcpy(&vtx_dest_gt3->r0, &col_src_gt3->r0, sizeof(u_char) * 3);
    memcpy(&vtx_dest_gt3->r1, &col_src_gt3->r1, sizeof(u_char) * 3);
    memcpy(&vtx_dest_gt3->r2, &col_src_gt3->r2, sizeof(u_char) * 3);
    // Set Texture Coordinates
    memcpy(&vtx_dest_gt3->u0, &tex_src_gt3->u0, sizeof(u_char) * 2);
    memcpy(&vtx_dest_gt3->u1, &tex_src_gt3->u1, sizeof(u_char) * 2);
    memcpy(&vtx_dest_gt3->u2, &tex_src_gt3->u2, sizeof(u_char) * 2);
    
    // Set CLUT
    vtx_dest_gt3->clut = clutid;
    // Set Texture Page
    vtx_dest_gt3->tpage = tpageid;
    
    if (otz > 0 && otz < OTSIZE)
    {
      // Add primitive to Ordering Table and advance pointer
      // to point to the next primitive to be processed.
      AddPrim(ot+otz, vtx_dest_gt3++);
      debug_face_count += 1;
    }
  }
  
  vtx_dest_g4 = (POLY_G4 *) vtx_dest_gt3;
  vtx_src_gt4 = data->pg4_vtx;
  
  for(i = 0; i < model->file->dh->poly_g4_count; i++, vtx_src_gt4++) {
  
    // Initialize destination poly
    setPolyG4(vtx_dest_g4);
    
    // Transform destination poly
    gte_RotAverageNclip3(
			(SVECTOR*)&vtx_src_gt4->v0,
			(SVECTOR*)&vtx_src_gt4->v1,
			(SVECTOR*)&vtx_src_gt4->v2,
			(long *)&vtx_dest_g4->x0, (long *)&vtx_dest_g4->x1,
			(long *)&vtx_dest_g4->x2, &p, &otz, &flg, &isfront);
    otz = otz >> 1;
    // Check side
    if(isfront <= 0) continue;
    
    // Only transform 4th vector if facing towards the view
    gte_RotTransPers((SVECTOR*)&vtx_src_gt4->v3,(long *)&vtx_dest_g4->x3, &temp2, &temp3, &temp);
    
    // Clip quads that are offscreen
    if(quad_clip(&G.screen_rect,
              (DVECTOR*)&vtx_dest_g4->x0,
              (DVECTOR*)&vtx_dest_g4->x1,
              (DVECTOR*)&vtx_dest_g4->x2,
              (DVECTOR*)&vtx_dest_g4->x3)) continue;
              
    // If on screen, now process the rest of the primitive.
    col_src_gt4 = &data->pg4_col[i];
    // Set Vertex Colors
    memcpy(&vtx_dest_g4->r0, &col_src_gt4->r0, sizeof(u_char) * 3);
    memcpy(&vtx_dest_g4->r1, &col_src_gt4->r1, sizeof(u_char) * 3);
    memcpy(&vtx_dest_g4->r2, &col_src_gt4->r2, sizeof(u_char) * 3);
    memcpy(&vtx_dest_g4->r3, &col_src_gt4->r3, sizeof(u_char) * 3);
        
    if (otz > 0 && otz < OTSIZE)
    {
      // Add primitive to Ordering Table and advance pointer
      // to point to the next primitive to be processed.
      AddPrim(ot+otz, vtx_dest_g4++);
      debug_face_count += 2;
    }
  }
  
  vtx_dest_g3 = (POLY_G3*)vtx_dest_g4;
  vtx_src_gt3 = data->pg3_vtx;

  for(i = 0; i < model->file->dh->poly_g3_count; i++, vtx_src_gt3++) {
    // Initialize destination poly
    setPolyG3(vtx_dest_g3);
    
    // Transform destination poly
    gte_RotAverageNclip3(
			(SVECTOR*)&vtx_src_gt3->v0,
			(SVECTOR*)&vtx_src_gt3->v1,
			(SVECTOR*)&vtx_src_gt3->v2,
			(long *)&vtx_dest_g3->x0, (long *)&vtx_dest_g3->x1,
			(long *)&vtx_dest_g3->x2, &p, &otz, &flg, &isfront);
    otz = otz >> 1;
    // Check side
    if(isfront <= 0) continue;
    
    // Clip quads that are offscreen
    if(tri_clip(&G.screen_rect,
              (DVECTOR*)&vtx_dest_g3->x0,
              (DVECTOR*)&vtx_dest_g3->x1,
              (DVECTOR*)&vtx_dest_g3->x2)) continue;
              
    // If on screen, now process the rest of the primitive.
    col_src_gt3 = &data->pg3_col[i];
    // Set Vertex Colors
    memcpy(&vtx_dest_g3->r0, &col_src_gt3->r0, sizeof(u_char) * 3);
    memcpy(&vtx_dest_g3->r1, &col_src_gt3->r1, sizeof(u_char) * 3);
    memcpy(&vtx_dest_g3->r2, &col_src_gt3->r2, sizeof(u_char) * 3);
    
    if (otz > 0 && otz < OTSIZE)
    {
      // Add primitive to Ordering Table and advance pointer
      // to point to the next primitive to be processed.
      AddPrim(ot+otz, vtx_dest_g3++);
      debug_face_count += 1;
    }
  }
  
  packet = (u_char *) vtx_dest_g3;
  // return the updated packet pointer
  return packet;
}
It initializes new polygons on the fly it can be used for instancing, like the wiggling boxes I made, they are the same model.

User avatar
NITROYUASH
Verified
Serious PSXDEV User
Serious PSXDEV User
Posts: 124
Joined: Jan 07, 2018
I am a: Game Designer
PlayStation Model: SCPH-5502
Location: Russian Federation
Contact:

Post by NITROYUASH » November 27th, 2019, 7:56 pm

Thanks for that source. It will help me when i will do some experiments with animation. c:

User avatar
Shadow
Verified
Admin / PSXDEV
Admin / PSXDEV
Posts: 2670
Joined: Dec 31, 2012
PlayStation Model: H2000/5502
Discord: Shadow^PSXDEV

Post by Shadow » November 29th, 2019, 3:02 am

That cube animation system is pretty neat. Just your 3D engine alone is better then 90% of all Net Yaroze games. lol.
Development Console: SCPH-5502 with 8MB RAM, MM3 Modchip, PAL 60 Colour Modification (for NTSC), PSIO Switch Board, DB-9 breakout headers for both RGB and Serial output and an Xplorer with CAETLA 0.34.

PlayStation Development PC: Windows 98 SE, Pentium 3 at 400MHz, 128MB SDRAM, DTL-H2000, DTL-H2010, DTL-H201A, DTL-S2020 (with 4GB SCSI-2 HDD), 21" Sony G420, CD-R burner, 3.25" and 5.25" Floppy Diskette Drives, ZIP 100 Diskette Drive and an IBM Model M keyboard.

User avatar
ArthCarvalho
Active PSXDEV User
Active PSXDEV User
Posts: 45
Joined: Jan 29, 2016
I am a: Artist, Programmer
PlayStation Model: SCPH-103

Post by ArthCarvalho » November 29th, 2019, 1:51 pm

Thanks! I hope I can get it optimized so it'll be truly usable.
I have an idea on how to implement "skeletal animation".
In modern games you'll use vertex skinning that is controlled by weights, this is definitely not feasible on hardware like the PS1, so the best option is a derivative of hierarchical animation (the one where models are made of individual parts) where you generate faces to connect the objects, for instance, suppose you have two cubes that make an "arm":
Image
Each box in hierarchical animation has its ends closed off so the mesh has no holes in it. It gives that classic early playstation title look.

But generating a closed of, linked mesh is basically free (except for drawing and memory costs) because you already have transformed the vertices in both objects, you just need to draw one that will connect between them:
Image
Image
Image
Image

Now the question is to get Blender to cooperate when exporting like this.
When exporting every part of the model that is part of a "bone" has to be transformed to the origin of the model, resulting in a mess of parts that starts from XYZ 0,0,0 and point in the direction of it's origin. But that's more about Blender than it is about the PS1.

HatMusic
Curious PSXDEV User
Curious PSXDEV User
Posts: 17
Joined: May 29, 2014

Post by HatMusic » November 30th, 2019, 3:30 am

ArthCarvalho wrote: November 29th, 2019, 1:51 pm ...the best option is a derivative of hierarchical animation (the one where models are made of individual parts) where you generate faces to connect the objects, for instance, suppose you have two cubes that make an "arm":
...
But generating a closed of, linked mesh is basically free (except for drawing and memory costs) because you already have transformed the vertices in both objects, you just need to draw one that will connect between them:
That is a genius idea! I hope you find a way to export them correctly.

User avatar
MrQuetch
Active PSXDEV User
Active PSXDEV User
Posts: 42
Joined: Apr 01, 2018
I am a: Programmer and artist.
Motto: You can accomplish anything.
Location: United States

Post by MrQuetch » February 19th, 2020, 8:28 am

I saw one of your videos earlier. I really love what you're doing with the PS1. I hope to get animated models at some point, too. This already gives a very firm foundation to getting animated models working.

Post Reply

Who is online

Users browsing this forum: No registered users and 3 guests