Horde3D

Next-Generation Graphics Engine
It is currently 27.04.2024, 12:44

All times are UTC + 1 hour




Post new topic Reply to topic  [ 12 posts ] 
Author Message
PostPosted: 03.12.2008, 21:14 
Offline

Joined: 10.04.2008, 09:13
Posts: 86
I'm writing a converter for AC3D ".ac" file format directly to Horde3D's ".geo" and ".xml" formats.
I'm running into a problem concerning texture coordinates. In the AC3D format texture coordinates
are defined per face vertex and in the .geo format they seem to be defined per vertex.

How do I go about converting this, should I add arbitrary vertices to the mesh, remap all indices etc?


Top
 Profile  
Reply with quote  
PostPosted: 03.12.2008, 23:24 
Offline

Joined: 22.11.2007, 17:05
Posts: 707
Location: Boston, MA
jimbo wrote:
I'm writing a converter for AC3D ".ac" file format directly to Horde3D's ".geo" and ".xml" formats.
I'm running into a problem concerning texture coordinates. In the AC3D format texture coordinates
are defined per face vertex and in the .geo format they seem to be defined per vertex.

How do I go about converting this, should I add arbitrary vertices to the mesh, remap all indices etc?
Yes, and the process is often called 'vertex welding', in case you want to google it. The same operation is required for wavefront .obj files.

_________________
Tristam MacDonald - [swiftcoding]


Top
 Profile  
Reply with quote  
PostPosted: 07.12.2008, 14:44 
Offline

Joined: 10.04.2008, 09:13
Posts: 86
Thanks, I've made a first version of the converter with a demo project which can be downloaded
here: http://corrado.bsdwebhosting.com/~jimbo/ac3dtest.zip

The converter is written in Perl, so you need something like http://strawberryperl.com/ to run it.

There are a few questions I have:

For unwelding I'm adding vertices that have different texture coordinates. For the cube this means it now has 29
vertices instead of 8. Ofcourse unwelding completely would make the cube 36 vertices.
But then there are the normals, which are also per vertex. So does this mean:

- I can use optimized unwelding for smooth normals?
- I need to completely unweld for normals with sharp edges, because no normal can be shared?

I hope this makes any sense.


Top
 Profile  
Reply with quote  
PostPosted: 07.12.2008, 14:52 
Offline

Joined: 22.11.2007, 17:05
Posts: 707
Location: Boston, MA
jimbo wrote:
For unwelding I'm adding vertices that have different texture coordinates. For the cube this means it now has 29
vertices instead of 8. Ofcourse unwelding completely would make the cube 36 vertices.
But then there are the normals, which are also per vertex. So does this mean:

- I can use optimized unwelding for smooth normals?
- I need to completely unweld for normals with sharp edges, because no normal can be shared?
Ja, that is about right. For hard edges, you need unique normals on either side, so you need to have duplicate vertices, while for smooth edges it doesn't matter.

Some model formats record information about hard edges separately, but if not, you need to do an angle-check for each vertex (and in each direction).

_________________
Tristam MacDonald - [swiftcoding]


Top
 Profile  
Reply with quote  
PostPosted: 09.12.2008, 21:28 
Offline

Joined: 10.04.2008, 09:13
Posts: 86
Okay, I've updated the converter (v0.2); features are now:

- Converts multiple objects/groups to Horde3D .geo format.
- Creates material files for textures.
- Calculates normals/tangents/bitangents for smooth and hard surfaces.
- Support for parallax normal maps.

I've included a Windows executable made from the Perl source so anyone can test it.
I think the normals could be a bit better for the ball which should be smooth.
A demo application is provided.

http://corrado.bsdwebhosting.com/~jimbo ... orde3d.zip


Top
 Profile  
Reply with quote  
PostPosted: 13.12.2008, 00:01 
Offline

Joined: 10.04.2008, 09:13
Posts: 86
v0.4: http://corrado.bsdwebhosting.com/~jimbo/ac3d2horde3d.zip

I made a bunch of changes in v0.4, first all vertices are unwelded, then normals are calculated and vertices are welded again. I succesfully converted a scene with 140.000 vertices and it looks good with the standard.shader. But there still is a problem with parallax mapping. I have normal maps for all models, but when loading them with the parallax shader things look bad:

Image

I think the calc_vertex_normals() function is correct, but I don't understand why this visual garbage happens.


Top
 Profile  
Reply with quote  
PostPosted: 13.12.2008, 01:41 
Offline
Engine Developer

Joined: 10.09.2006, 15:52
Posts: 1217
Maybe it is a problem with the tangent space calculation?

More generally speaking, I think it is great that we get exporters for more and more DCC packages. So thanks a lot for your efforts jimbo! The only issue I see is that all the exporters need to do a lot of code duplication, for example for calculating the tangent space basis or optimizing the vertices for better cache usage. Furthermore, they need to be updated if the Horde formats should change. One way out of that dilemma could be to have a very simple intermediate format that the DCC exporter outputs and that is processed by ColladaConv. So updates and improvements just need to be implemented at one place, namely in ColladaConv.

Here is a quick idea for such an intermediate format, inspired by the famous OBJ format. It is no specification and probably something is missing.

Code:
# Comment

MATERIAL "id"               # Material definition with unique name
tex      "semantic" "image"      # Texture semantic (e.g. diffuse, normal, specular) to file mapping


# Mesh with name, transformation matrix and optional parent
MESH "name"/tm0/tm1/tm2/tm3/tm4/tm5/tm6/tm7/tm8/tm9/tm10/tm11/tm12/tm13/tm14/tm15/["parent"]
v      x/y/z               # Vertex position
vt0      u/v               # Vertex texture coordinate set 0
vt1      u/v               # Vertex texture coordinate set 1 (optional, but must match vt0 if defined)
vn      x/y/z               # Vertex normal
vs      "joint"/weight ["joint"/weight]
usemtl   "ref_mtl_id"                 # Bind a material for the following faces
f       v/vt/vn/vs v/vt/vn/vs v/vt/vn/vs   # Face indexing vertex data
defmorph "name"               # Morph target definition for mesh
mv       x/y/z               # Vertex position
mvn      x/y/z               # Vertex normal
m       v/mv/mvn            # Morph-Vertex


# Joint with name, parent, inverse bind matrix and transformation
JOINT "name"/"parent"/bm0/bm1/bm2/bm3/bm4/bm5/bm6/bm7/bm8/bm9/bm10/bm11/bm12/bm13/bm14/bm15/tm0/tm1/tm2/tm3/tm4/tm5/tm6/tm7/tm8/tm9/tm10/tm11/tm12/tm13/tm14/tm15


Top
 Profile  
Reply with quote  
PostPosted: 13.12.2008, 16:46 
Offline

Joined: 16.01.2008, 00:24
Posts: 73
Location: Canada/Quebec
jimbo wrote:
v0.4: http://corrado.bsdwebhosting.com/~jimbo/ac3d2horde3d.zip

I made a bunch of changes in v0.4, first all vertices are unwelded, then normals are calculated and vertices are welded again. I succesfully converted a scene with 140.000 vertices and it looks good with the standard.shader. But there still is a problem with parallax mapping. I have normal maps for all models, but when loading them with the parallax shader things look bad:

Image

I think the calc_vertex_normals() function is correct, but I don't understand why this visual garbage happens.



Do you have the height map in the alpha channel? This could be the problem, since the normal map only is not enough for the parallax shader.


Top
 Profile  
Reply with quote  
PostPosted: 14.12.2008, 20:57 
Offline

Joined: 10.04.2008, 09:13
Posts: 86
I'm a bit stuck on this, my normals/tangents/bitangents calculation works as follows:

- Unweld the model completely (no indices point to the same vertex).
- Create a map of indices with the same vertex.
- Calculate normals/tangents/bitangents for each face and add to all matching indices from the map
- Weld all vertices with same coordinates, texture coordinates and normals.

Still parallax doesn't look correct (even if I skip welding). If I disable smoothing things look a bit better, but
not correct either.

I've made a little demo to demonstrate the problem:

http://corrado.bsdwebhosting.com/~jimbo/trouble.zip

Also I've added the same model converted to .obj then to Collada, and then with colladaconv to horde3d, which looks correct.

The problem part must be in these functions:

Code:
# find vertices with same coordinates, this is for normal smoothing, return of list of matching indices
sub find_same_vertices {
    my $object      = shift;
    my $indices_map = shift;
    my $index       = shift;

    my $vertex = $object->{numvert}->[$index];

    return @{ $indices_map->{ $vertex->as_string } };
}

# create map of indices with same vertices
sub make_indices_map {
    my $object = shift;

    my %indices_map;

    foreach my $surface ( @{ $object->{numsurf} } ) {

        # only average out smooth vertex normals
        next if ( $surface->{SURF}->{shading} ne 'smooth' );
        foreach my $ref ( @{ $surface->{refs} } ) {
            my $v = $object->{numvert}->[ $ref->{index} ];
            push @{ $indices_map{ $v->as_string } }, $ref->{index};
        }
    }

    return \%indices_map;
}

sub calc_vertex_normals {
    my $object = shift;

    warn "calculating normals: $object->{name}\n";

    my @normals;
    my @tangents;
    my @bitangents;

    my $indices_map = make_indices_map($object);

    foreach my $surface ( @{ $object->{numsurf} } ) {

        my $index0 = $surface->{refs}->[0]->{index};
        my $index1 = $surface->{refs}->[1]->{index};
        my $index2 = $surface->{refs}->[2]->{index};

        my $v0 = $object->{numvert}->[$index0];
        my $v1 = $object->{numvert}->[$index1];
        my $v2 = $object->{numvert}->[$index2];

        my $d0 = $v1 - $v0;
        my $d1 = $v2 - $v0;
        my $v  = ( $d0 x $d1 )->normalized;

        #
        #  Calculate the normal,tangent and bitangent for this face and add it
        #  to the running sum of normals for each of the
        #  vertices involved
        #

        my $Edge0uv = uv_sub( $surface->{refs}->[1], $surface->{refs}->[0] );
        my $Edge1uv = uv_sub( $surface->{refs}->[2], $surface->{refs}->[0] );

        my $cp = $Edge0uv->{u} * $Edge1uv->{v} - $Edge1uv->{u} * $Edge0uv->{v};
        my $r  = 0;
        if ( $cp != 0 ) {
            $r = 1.0 / $cp;
        }

        my $tangent   = ( $d0 * $Edge1uv->{v} - $d1 * $Edge0uv->{v} ) * $r;
        my $bitangent = ( $d1 * $Edge0uv->{u} - $d0 * $Edge1uv->{u} ) * $r;

        my @indices;
        push @indices, find_same_vertices( $object, $indices_map, $index0 );
        push @indices, find_same_vertices( $object, $indices_map, $index1 );
        push @indices, find_same_vertices( $object, $indices_map, $index2 );
        foreach my $index (@indices) {
            $normals[$index]    ||= vec3();
            $tangents[$index]   ||= vec3();
            $bitangents[$index] ||= vec3();

            $normals[$index]    += $v;
            $tangents[$index]   += $tangent;
            $bitangents[$index] += $bitangent;
        }
    }

    #  Normalize and fixup the vertex normal vectors, tangents en bitangents
    my $numVerts = int( @{ $object->{numvert} } );
    for ( my $j = 0 ; $j < $numVerts ; $j++ ) {
        my $n = $normals[$j]->normalized;
        my $t = $tangents[$j];

        # orthogonalize
        $tangents[$j] = ( $t - $n * ( $n * $t ) )->normalized;
        $normals[$j] = $n;

        if ( ( $n x $t ) * $bitangents[$j] < 0 ) {
            $bitangents[$j] = ( $n * -1 ) x $t;
        }
        else {
            $bitangents[$j] = $n x $t;
        }
    }

    $object->{normals}    = \@normals;
    $object->{tangents}   = \@tangents;
    $object->{bitangents} = \@bitangents;
}


Top
 Profile  
Reply with quote  
PostPosted: 20.05.2009, 08:00 
Offline

Joined: 10.04.2008, 09:13
Posts: 86
Just to let you know all fixed and done, download release here:

http://www.horde3d.org/forums/viewtopic.php?f=6&t=748


Top
 Profile  
Reply with quote  
PostPosted: 20.05.2009, 08:57 
Offline
Tool Developer

Joined: 13.11.2007, 11:07
Posts: 1150
Location: Germany
Thanks again. I added a link to the wiki. Feel free to add additional information.


Top
 Profile  
Reply with quote  
PostPosted: 24.05.2009, 20:48 
Offline
Engine Developer

Joined: 10.09.2006, 15:52
Posts: 1217
Good work, jimbo. It is great to have better support for less expensive modelling packages.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 12 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 35 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group