nstokes2 / ozz-animation

Automatically exported from code.google.com/p/ozz-animation
zlib License
0 stars 0 forks source link

Slightly off topic: SkinnedMesh question #8

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
I realise this is a slightly off topic question but I'm having trouble 
populating the information in SkinnedMesh to render a model (populating myself, 
not from a loaded .ozz model). My main reason for asking here is because I 
would like to fully understand the ozz exmaples rather than change them 
unrecognisably and forget about them - this helps me understand future releases 
too.

Currently I'm trying to render a flat plane square, but upon rendering it 
misses 3/4 of the vertices out. I am currently rendering using the Shader class 
in ozz, but changed to render GL_POINTS rather than GL_TRIANGLES. I populate 
the Vertices and Indices in the following way (NEXT is the same definition 
found in the ozz skinning job):

int x = 0; int y = 0;
            int vertCount = pRAWWidth * pRAWHeight;

            SkinnedMesh* renderMesh
                = new SkinnedMesh(vertCount, vertCount);

            // Fill up position buffer
            SkinnedMesh::Positions posBuffer = renderMesh->positions();
            float* out_position = posBuffer.data.begin;
            // .. And colour buffer
            SkinnedMesh::Colors colBuffer = renderMesh->colors();
            SkinnedMesh::Color* out_color = colBuffer.data.begin;
            // .. And normal buffer
            SkinnedMesh::Normals normBuffer = renderMesh->normals();
            float* out_normal = normBuffer.data.begin;

            for (y = 0; y < pRAWHeight; y += 1) {
                for (x = 0; x < pRAWWidth; x += 1) {
                    // Positions
                    out_position[0] = x;
                    out_position[1] = 0.f;
                    out_position[2] = y;
                    // Colors
                    //out_color->red = 0;
                    //out_color->green = 255;
                    //out_color->blue = 0;
                    //out_color->alpha = 255; // 1.f;
                    // Normals
                    //out_normal[0] = 0.f;
                    //out_normal[1] = 1.f;
                    //out_normal[2] = 0.f;

                    // Increment ptrs
                    out_position = NEXT(float*, out_position, posBuffer.stride);
                    out_color = NEXT(SkinnedMesh::Color*, out_color, colBuffer.stride);
                    out_normal = NEXT(float*, out_normal, normBuffer.stride);
                }
            }

            // .. And indices buffer
            SkinnedMesh::Indices indiBuffer = renderMesh->indices();
            uint16_t* out_indices = indiBuffer.data.begin;

            for (int i = 0; i < vertCount; i++) {
                out_indices[0] = i;
                out_indices = NEXT(uint16_t*, out_indices, indiBuffer.stride);
            }

Any help would be much apprechiated.

Original issue reported on code.google.com by ThomasBu...@gmail.com on 22 Jan 2015 at 11:14

GoogleCodeExporter commented 8 years ago
There's something strange with code you copy/pasted, because it looks to me 
that you're using ozz::sample::Renderer::Mesh, but you're talking about 
ozz::sample::SkinnedMesh. I might be a bit confused with all the changes going 
on, could you clarify what mesh type you're using?

Anyway, I don't see the issue in that code. I reproduced it in skin sample and 
got no issue either, as you can see on the attached screen shot.

You can find below the code I tested. It's very close to what you sent except 
the mesh type.

#define NEXT(_type, _current, _stride) \
  reinterpret_cast<_type>(reinterpret_cast<uintptr_t>(_current) + _stride)

    {
      int x = 0; int y = 0;
      int vertCount = 100 * 100;

      ozz::sample::Renderer::Mesh* renderMesh
              = new ozz::sample::Renderer::Mesh(vertCount, vertCount);

      // Fill up position buffer
      ozz::sample::Renderer::Mesh::Positions posBuffer = renderMesh->positions();
      float* out_position = posBuffer.data.begin;
      // .. And colour buffer
      ozz::sample::Renderer::Mesh::Colors colBuffer = renderMesh->colors();
      ozz::sample::Renderer::Mesh::Color* out_color = colBuffer.data.begin;
      // .. And normal buffer
      ozz::sample::Renderer::Mesh::Normals normBuffer = renderMesh->normals();
      float* out_normal = normBuffer.data.begin;

      for (y = 0; y < 100; y += 1) {
              for (x = 0; x < 100; x += 1) {
                      // Positions
                      out_position[0] = x;
                      out_position[1] = 0.f;
                      out_position[2] = y;
                      // Colors
                      out_color->red = 255;
                      out_color->green = 0;
                      out_color->blue = 0;
                      out_color->alpha = 255; // 1.f;
                      // Normals
                      //out_normal[0] = 0.f;
                      //out_normal[1] = 1.f;
                      //out_normal[2] = 0.f;

                      // Increment ptrs
                      out_position = NEXT(float*, out_position, posBuffer.stride);
                      out_color = NEXT(ozz::sample::Renderer::Mesh::Color*, out_color, colBuffer.stride);
                      out_normal = NEXT(float*, out_normal, normBuffer.stride);
              }
      }

      // .. And indices buffer
      ozz::sample::Renderer::Mesh::Indices indiBuffer = renderMesh->indices();
      uint16_t* out_indices = indiBuffer.data.begin;

      for (int i = 0; i < vertCount; i++) {
              out_indices[0] = i;
              out_indices = NEXT(uint16_t*, out_indices, indiBuffer.stride);
      }

    _renderer->DrawMesh(ozz::math::Float4x4::identity(), *renderMesh); 

Also I'd like to mention that ozz::sample::Renderer::Mesh will be removed in a 
next release. I'll either expose dynamic vertex buffers from the 
sample::Renderer interface, or use ozz::sample::SkinnedMesh (renamed to 
ozz::sample::Mesh). The idea behind that is to make skinning sample closer to a 
real world case. Hope it's not going to be too much of an issue.

Original comment by guillaum...@gmail.com on 22 Jan 2015 at 9:27

Attachments:

GoogleCodeExporter commented 8 years ago
Sorry, you're correct I am using ozz::sample::Renderer::Mesh (slightly renamed 
a few things for my own benefit - I was getting confused). 

I notice in the code sample above you're implementing my code sample with 100 x 
100 verts - that was something I hadn't tried. 

With 100 x 100 verts the code seems to work fine, but I'm dealing with larger 
values. Anything above ~300 stops working, and the values I have been using are 
1024x1024. I have attached images to demonstrate this. 

If you see the 400x400.png, I'm sure you will have already guessed this, but I 
am putting values of 400 width and 400 height into the code - the outcome 
should be square but it's actually a rectangle.

Original comment by ThomasBu...@gmail.com on 23 Jan 2015 at 8:44

Attachments:

GoogleCodeExporter commented 8 years ago
Aha! Slowly tracking the issue down! 

It appears that when the item is being rendered the value returned from 
ozz::Range::Size() appears to be wrong.

The following code taken from the ozz shader class is returning a drastically 
wrong value:
const GLsizei index_vbo_size = static_cast<GLsizei>(indices_buffer.data.Size());

Original comment by ThomasBu...@gmail.com on 23 Jan 2015 at 8:57

GoogleCodeExporter commented 8 years ago
indices_buffer.data.Size() returns the difference between the begin/end 
pointers. So for 400x400, buffer size will be 400*400*2 (because indices are 
uint16_t -> 2 bytes), which is 320000 bytes. What do you see in index_vbo_size?

Anyway the important thing there is that indices are uint16_t, which have a 
maximum value of 65535.
200x200 = 40000 < 65535 -> ok
400x400 = 160000 > 65535 -> overflow !!!

I'd say that for a 400x400 grid, you actually have a 400x164 points rendered.

Hope it helps,
Guillaume

Original comment by guillaum...@gmail.com on 23 Jan 2015 at 9:18

GoogleCodeExporter commented 8 years ago
Wow- Can't believe I hadn't noticed that.

Might be worth considering bumping that up to a uint32_t? - Limiting mesh's to 
an indicies count of 65k seems a bit restrictive, even if most models come in 
way under that count.

As always, thanks for the help

Original comment by ThomasBu...@gmail.com on 23 Jan 2015 at 11:32

GoogleCodeExporter commented 8 years ago
Switching to uint32_t does not mean you can use the full 32bits range. There 
are other limits that depend on your hardware/driver like the maximum index or 
maximum vertex count. You can querry the 2 with 
glGetIntegerv(GL_MAX_ELEMENTS_INDICES, ...) and 
glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, ...).
So in case of overflow I would rather split meshes, or draw in multiple draw 
calls.

Cheers,
Guillaume

Original comment by guillaum...@gmail.com on 24 Jan 2015 at 10:41

GoogleCodeExporter commented 8 years ago

Original comment by guillaum...@gmail.com on 25 Jan 2015 at 9:53