Changeset 184

Show
Ignore:
Timestamp:
05/31/10 13:28:34 (2 years ago)
Author:
JoeCoder
Message:

Improved support for the older collada 1.3 format (has a few things incorrect instead of crashing).
Fixed a bug that caused Geometry.optimize to leave more vertices than needed.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/src/tests/integration/main.d

    r183 r184  
    154154         
    155155        // Create a textured plane 
    156         Geometry geometry = Geometry.createPlane(16, 16); 
     156        Geometry geometry = Geometry.createPlane(4, 4); 
    157157        Texture texture = Texture(ResourceManager.texture("space/rocky2.jpg")); 
    158158        Texture normal = Texture(ResourceManager.texture("space/rocky2-normal.jpg")); 
     
    213213        //beast.setAngularVelocity(Vec3f(0, .5, 0)); 
    214214         
    215         // For testing sprites 
    216         plane = scene.addChild(new ModelNode(geometry)); 
    217         plane.setPosition(Vec3f(0, -10, 0)); 
    218         plane.setRotation(Vec3f(-PI/2, 0, 0)); 
    219         plane.setScale(Vec3f(10)); 
    220  
    221          
    222215        // Lights 
    223216        auto rotater = addChild(new ModelNode()); 
     
    225218        auto light1 = rotater.addChild(new LightNode()); 
    226219        light1.setPosition(Vec3f(10, 0, 0)); 
    227         //light1.setAngularVelocity(Vec3f(0, 10, 0)); // TODO: This seems to make it gradually move? 
     220        //light1.setAngularVelocity(Vec3f(0, 10, 0)); 
    228221        light1.diffuse = "white"; 
    229         light1.setLightRadius(30);         
     222        light1.setLightRadius(80);         
    230223        //light1.spotExponent = 3; 
    231224        //light1.spotAngle = 80 * 3.1415/180; 
  • trunk/src/yage/resource/collada.d

    r183 r184  
    104104            if (mesh.hasChild("polylist")) 
    105105                polyList = mesh.getChild("polylist"); 
     106            else if (mesh.hasChild("triangles")) 
     107                polyList = mesh.getChild("triangles"); 
    106108            else 
    107                 polyList = mesh.getChild("triangles"); 
     109                polyList = mesh.getChild("polygons"); // collada 1.3? 
    108110             
    109111            // Inputs are the cordinates that the triangles index into. 
     
    121123            {                    
    122124                inputs[i].name = inputNode.getAttribute("semantic"); 
     125                char[] offset = inputNode.hasAttribute("offset") ? inputNode.getAttribute("offset") : inputNode.getAttribute("idx");                 
    123126                try { 
    124                     inputs[i].offset = Xml.parseNumber!(int)(inputNode.getAttribute("offset")); 
     127                    inputs[i].offset = Xml.parseNumber!(int)(offset); 
    125128                } catch (ConversionException e) 
    126129                {   throw new XmlException(e.toString()); 
    127130                } 
    128                  
     131                    
    129132                if (inputs[i].name=="VERTEX") // VERTEX type requires another level of indirection to get to proper node. 
    130133                {   char[] verticesId = inputNode.getAttribute("source");                
     
    135138                // Get values 
    136139                char[] sourceId = inputNode.getAttribute("source");  
    137                 inputs[i].data = getDataFromSourceId(sourceId, inputs[i].components);                    
    138             }                
    139             int[] indices = Xml.parseNumberList!(int)(polyList.getChild("p").value); 
     140                inputs[i].data = getDataFromSourceId(sourceId, inputs[i].components); 
     141            } 
     142            int[] indices; 
     143            foreach (p; polyList.getChildren("p")) 
     144                indices ~= Xml.parseNumberList!(int)(p.value); 
    140145            int[] vcounts; 
    141146            if (polyList.hasChild("vcount")) 
     
    172177                    float[] data = new float[indices.length*c/indicesPerVertex]; 
    173178                    for (int i=0; i<indices.length; i+=indicesPerVertex) 
    174                     {   int index = indices[i + input.offset]*c; // TODO: This creates duplicate vertices on shared triangle edges 
     179                    {   int index = indices[i + input.offset]*c; // This creates duplicate vertices on shared triangle edges, Geometry.optimize takes care of it later 
    175180                        int j = i/indicesPerVertex*c; 
    176181                        data[j..j+c] = input.data[index..index+c]; 
     
    186191                    else 
    187192                        assert(0); 
    188                     
     193                 
    189194                    // Flip the y texture coordinate for OpenGL. 
    190195                    foreach (inout texCoord; cast(Vec2f[])result.getAttribute(Geometry.TEXCOORDS0)) 
    191196                        texCoord.y = -texCoord.y; 
     197                     
    192198                } 
     199                 
    193200                 
    194201                // Build triangles 
     
    229236                result.meshes = [mesh]; 
    230237                 
    231                 if (!calledByGetMerged) 
    232                 {   result.optimize(); 
    233                  
    234                     //If phong shading is used, generate binormals. 
    235                     if (material.getPass().autoShader == MaterialPass.AutoShader.PHONG) 
    236                         result.setAttribute(Geometry.TEXCOORDS1, result.createTangentVectors()); 
    237                 } 
    238              
    239                  
    240238                return result; 
    241239            }                
     
    244242         
    245243        // Merge meshes into a single geometry 
    246         Geometry result = meshes[0]
     244        Geometry result = meshes.length ? meshes[0] : null
    247245        if (meshes.length > 1) 
    248             result = Geometry.merge(meshes);             
     246            result = Geometry.merge(meshes); 
     247         
     248        if (!calledByGetMerged) 
     249        {   result.optimize(); 
     250         
     251            //If phong shading is used, generate binormals. 
     252            foreach (mesh; result.meshes) 
     253                if (mesh.material.getPass().autoShader == MaterialPass.AutoShader.PHONG) 
     254                {   result.setAttribute(Geometry.TEXCOORDS1, result.createTangentVectors()); 
     255                    break; 
     256                } 
     257        } 
    249258         
    250259        delete meshes;  // garbage from old mesh sub-data 
    251         geometries[id] = result; // cache for next request          
     260        geometries[id] = result; // cache for next request 
    252261        return result; 
    253262    } 
     
    280289        MaterialPass pass = result.techniques[0].passes[0]; 
    281290         
    282         Node instanceEffect = Xml.getNodeById(doc, id).getChild("instance_effect"); // TODO: instance_effect can have child nodes that specify parameters 
    283         Node effectNode = Xml.getNodeById(doc, instanceEffect.getAttribute("url")); 
    284         Node profileCommon = effectNode.getChild("profile_COMMON"); // TODO: profile_GLSL 
    285         Node technique = profileCommon.getChild("technique"); 
     291        Node technique; 
     292        Node materialNode = Xml.getNodeById(doc, id); 
     293        if (materialNode.hasChild("instance_effect")) 
     294        {   Node instanceEffect = Xml.getNodeById(doc, id).getChild("instance_effect"); // TODO: instance_effect can have child nodes that specify parameters 
     295            Node effectNode = Xml.getNodeById(doc, instanceEffect.getAttribute("url")); 
     296            Node profileCommon = effectNode.getChild("profile_COMMON"); // TODO: profile_GLSL 
     297            technique = profileCommon.getChild("technique"); 
     298        } else // Collada 1.3 
     299        {       technique = materialNode.getChild("shader").getChild("technique"); 
     300        } 
    286301         
    287302        Node shadingType = technique.getChild(); // in profile_COMMON, it can be newparam, image, blinn, constant, lambert, phong, or extra. 
     
    312327            }   } 
    313328             
     329            if (!param.getChildren().length) 
     330                continue; 
     331             
    314332            Node child = param.getChild();               
    315333            GPUTexture texture; 
     
    323341                    pass.setDiffuseTexture(Texture(texture)); // may be null 
    324342                    break; 
    325                 case "bump": 
     343                case "bump": // Bump map extension used by Okino, http://www.okino.com/conv/exp_collada_extensions.htm 
    326344                    getColorOrTexture(child, pass.diffuse, texture); 
    327345                    pass.setNormalSpecularTexture(Texture(texture)); // may be null 
     
    350368                default: 
    351369                    break; 
    352                 // TODO: Get normal from extra tag, see: http://www.okino.com/conv/exp_collada_extensions.htm 
    353370            } 
    354371             
     
    381398    { 
    382399        Geometry[] geometries; 
    383         Matrix[] geometryTransforms; 
     400        Matrix[] geometryTransforms; // A transformation matrix for each geometry found. 
    384401         
    385402        // Get the up direction (unfinished) 
     
    391408         
    392409        // Loop through the scenes and load all the geometry nodes they reference. 
    393         scope Node[] visual_scenes = Node(doc.elements).getChild("library_visual_scenes").getChildren("visual_scene"); 
    394          
    395         foreach (visual_scene; visual_scenes) // loop through scenes 
     410        Node[] scenes; 
     411        Node root = Node(doc.elements); 
     412        if (root.hasChild("library_visual_scenes")) 
     413            scenes = root.getChild("library_visual_scenes").getChildren("visual_scene"); 
     414        else // collada 1.3 
     415            scenes = root.getChildren("scene"); 
     416         
     417        foreach (visual_scene; scenes) // loop through scenes 
    396418        { 
    397             scope Node[] nodes = visual_scene.getChildren("node"); 
    398             foreach (node; nodes) // loop through nodes in a scene 
     419            void traverseSceneNodes(Node node) 
    399420            { 
    400                 if (!node.hasChild("instance_geometry")) 
    401                     continue; 
    402                  
    403                 Node instance_geometry = node.getChild("instance_geometry"); 
    404                  
    405                 char[] geometryId = instance_geometry.getAttribute("url"); // TODO: Multiple instance geometry? 
    406                 Geometry geometry = getGeometryById(geometryId, true); 
    407                  
    408                 // Get transformation matrix for this instance of the geometry. 
    409                 Matrix matrix; 
    410                 foreach (transform; node.getChildren()) 
    411                 {   if (transform.name=="translate") 
    412                         matrix.setPosition(Vec3f(Xml.parseNumberList!(float)(transform.value))); 
    413                     else if (transform.name=="rotate") 
    414                     {   float[] values = Xml.parseNumberList!(float)(transform.value); 
    415                         assert(values.length==4); 
    416                         Vec3f(values[3]*tango.math.Math.PI/180, values[0], values[1], values[2]); // load from axis-angle                            
    417                     }  
    418                     else if (transform.name=="scale")                        
    419                         matrix.setScalePreservingRotation(Vec3f(Xml.parseNumberList!(float)(transform.value))); 
     421                Node instance_geometry; 
     422                if (node.hasChild("instance_geometry")) 
     423                    instance_geometry = node.getChild("instance_geometry"); 
     424                else if (node.hasChild("instance")) // Collada 1.3 
     425                    instance_geometry = node.getChild("instance"); 
     426                 
     427                if (instance_geometry.node) 
     428                {                        
     429                    char[] geometryId = instance_geometry.getAttribute("url"); // TODO: Multiple instance geometry? 
     430                    Geometry geometry = getGeometryById(geometryId, true); 
     431                    if (geometry) 
     432                    { 
     433                        // Get transformation matrix for this instance of the geometry. 
     434                        Matrix matrix; 
     435                        foreach (transform; node.getChildren()) 
     436                        {   if (transform.name=="translate") 
     437                                matrix.move(Vec3f(Xml.parseNumberList!(float)(transform.value))); 
     438                            else if (transform.name=="rotate") 
     439                            {   float[] values = Xml.parseNumberList!(float)(transform.value); 
     440                                assert(values.length==4); 
     441                                matrix = matrix.rotate(Vec3f(values[3]*tango.math.Math.PI/180, values[0], values[1], values[2])); // load from axis-angle                            
     442                            }  
     443                            else if (transform.name=="scale")                        
     444                                matrix.setScalePreservingRotation(Vec3f(Xml.parseNumberList!(float)(transform.value))); 
     445                            else if (transform.name=="matrix") // collada 1.3 
     446                            {   matrix = Matrix(Xml.parseNumberList!(float)(transform.value)); 
     447                                 
     448                            } 
     449                        } 
     450                        geometryTransforms ~= matrix * upTransform; 
     451                         
     452                        // TODO: Sometimes intance_geometry has xml children specifying a material (or other things as well?) 
     453                         
     454                        geometries~= geometry; 
     455                    } 
    420456                } 
    421                 geometryTransforms ~= matrix * upTransform; 
    422                  
    423                 // TODO: Sometimes intance_geometry has xml children specifying a material (or other things as well?) 
    424                  
    425                 geometries~= geometry; 
    426         }   } 
     457                 
     458                foreach (child; node.getChildren("node")) // loop through nodes in a scene 
     459                    traverseSceneNodes(child); 
     460            } 
     461             
     462            traverseSceneNodes(visual_scene); 
     463        } 
    427464         
    428465        // Transform geometry instances by their transformation matrix 
     
    446483        delete geometries; 
    447484         
    448          
    449         //Timer a = new Timer(true); 
    450          
     485        //foreach (mesh; result.meshes) 
     486        // Log.trace(mesh.getTriangles().length);       
     487        //Log.trace(result.getAttribute(Geometry.VERTICES).length); 
    451488        result.optimize(); 
    452489         
     
    510547    // See: https://collada.org/mediawiki/index.php/Using_accessors 
    511548    private float[] getDataFromSourceId(char[] id, out ushort components) 
    512     {   Node sourceAccesor = Xml.getNodeById(doc, id).getChild("technique_common").getChild("accessor"); // TODO: Read stride, offset, etc. 
    513         scope Node[] params = sourceAccesor.getChildren("param"); 
     549    {    
     550         
     551         
     552        Node source = Xml.getNodeById(doc, id);      
     553        Node sourceAccessor; 
     554        if (source.hasChild("technique_common")) 
     555            sourceAccessor = source.getChild("technique_common").getChild("accessor"); // TODO: Read stride, offset, etc. 
     556        else // collada 1.3 
     557            sourceAccessor = source.getChild("technique").getChild("accessor"); // TODO: Read stride, offset, etc. 
     558        scope Node[] params = sourceAccessor.getChildren("param"); 
    514559        components = params.length; 
    515         char[] sourceFloatArrayId = sourceAccesor.getAttribute("source"); 
    516         char[] sourceFloatArray = Xml.getNodeById(doc, sourceFloatArrayId).value
    517         return Xml.parseNumberList!(float)(sourceFloatArray); 
     560        char[] sourceFloatArrayId = sourceAccessor.getAttribute("source"); 
     561        Node sourceFloatArray = Xml.getNodeById(doc, sourceFloatArrayId)
     562        return Xml.parseNumberList!(float)(sourceFloatArray.value); 
    518563    } 
    519564     
  • trunk/src/yage/resource/geometry.d

    r183 r184  
    88 
    99import tango.math.Math; 
     10import yage.core.format; 
    1011import yage.core.math.vector; 
    1112import yage.resource.manager; 
     
    255256    void optimize() 
    256257    { 
     258        debug { 
     259            int length =  getVertexBuffer(Geometry.VERTICES).length; 
     260            foreach (name, attribute; attributes) 
     261            {   assert(attribute.length == length, format("%s is only of length %s, but vertices are of length %s", name, attribute.length, length)); 
     262            } 
     263             
     264        } 
     265         
    257266        // Merge duplicate vertices 
    258267        VertexBuffer vb = attributes[Geometry.VERTICES]; 
     
    312321         
    313322        // Move data 
    314         foreach (inout attribute; attributes) 
     323        foreach (name, inout attribute; attributes) 
    315324        { 
    316325            int c2 = attribute.components; 
    317326            float[] oldData = cast(float[])attribute.data; 
    318             float[] data = new float[remap.length];          
    319              
     327            float[] data = new float[remapReverse.length*c2];            
    320328            foreach (to, from; remapReverse) // Too bad doing this in-place fails for some models            
     329            {   //Log.trace("%s %s %s %s", data.length, to*c2+c2, oldData.length, from*c2+c2); 
    321330                data[to*c2..to*c2+c2] = oldData[from*c2..from*c2+c2];    
     331            } 
    322332             
    323333            attribute.data = data;