Пример #1
0
void Scene::buildLight(Json::Value light) {
    lights.push_back(new Light(
                         getVec4(light["center"]),
                         getVec4(light["ambient"]),
                         getVec4(light["diffuse"]),
                         getVec4(light["specular"]),
                         getVec4(light.get("direction",light["center"])),
                         light.get("angle",180).asFloat()));
}
Пример #2
0
ray Mouse::getRay(const Camera & camera, float win_width, float win_height)
{
    ray myRay;
    
    float x = (2.0f * *mouseX) / win_width - 1.0f;
    float y = 1.0f - (2.0f * *mouseY) / win_height;
    float z = -1.0f;
    
    vec rayNds = getVec(x, y, z);
    float rayClip[] = {rayNds.x, rayNds.y, z, 1.0};
    
    float rayEye[4];
    float tempInverse[16];
    float rayWorld[4];
    
    matInverse(&tempInverse[0]);
    matMultVec4fUtil(rayEye, rayClip, &tempInverse[0]);
    
    rayEye[2] = z;
    rayEye[3] = 0.0;
    
    matMultVec4fUtil(rayWorld, rayEye, &tempInverse[0]);
    vec4 rayWor = getVec4(rayWorld[0], rayWorld[1], rayWorld[2], rayWorld[3]);
    
    // don't forget to normalise the vector at some point
    rayWor = vec4Normalize(rayWor);
    
    myRay.origin.x = camera.position.x;
    myRay.origin.y = camera.position.y;
    myRay.origin.z = camera.position.z;
    myRay.direction.x = rayWor.x;
    myRay.direction.y = rayWor.y;
    myRay.direction.z = rayWor.z;
    myRay.direction.w = rayWor.w;
    
    return myRay;
}
Пример #3
0
bool Model::loadCollada(std::string filename){
    //Load the collada xml file
    rapidxml::file<> xmlFile(filename.c_str());
    rapidxml::xml_document<> doc;
    doc.parse<0>(xmlFile.data());
    
    bool zup = std::string(doc.first_node()->first_node("asset")->first_node("up_axis")->value()) == "Z_UP";
    
    //Load textures
    rapidxml::xml_node<> *images = doc.first_node()->first_node("library_images");
    if(images->first_node("image") == 0){
        Logger::error << "Couldn't load model: file contains no texture data." << std::endl;
        return false;
    }
    std::map<std::string, unsigned int> textures;
    for(rapidxml::xml_node<> *image = images->first_node("image"); image != 0; image = image->next_sibling("image")){
        textures.insert(std::pair<std::string, unsigned int>(image->first_attribute("id")->value(), loadTextureFromPNG(filename.substr(0, filename.find_last_of("\\/")+1) + image->first_node("init_from")->value())));
    }
    
    
    //Load effects
    //TODO: only supports common profiles using phong techniques
    rapidxml::xml_node<> *effectsNode = doc.first_node()->first_node("library_effects");
    if(effectsNode->first_node("effect") == 0){
        Logger::error << "Couldn't load model: file contains no effects data." << std::endl;
        return false;
    }
    std::map<std::string, Material> effects;
    for(rapidxml::xml_node<> *effect = effectsNode->first_node("effect"); effect != 0; effect = effect->next_sibling("effect")){
        rapidxml::xml_node<> *profile = effect->first_node("profile_COMMON");
        if(profile != 0){
            rapidxml::xml_node<> *technique = profile->first_node("technique");
            Material mat;
            rapidxml::xml_node<> *phong = technique->first_node("phong");
            if(phong != 0){                
                if(phong->first_node("emission") != 0){
                    mat.emission = getVec4(phong->first_node("emission")->first_node("color"));
                }
                if(phong->first_node("ambient") != 0){
                    mat.ambient = getVec4(phong->first_node("ambient")->first_node("color"));
                }
                if(phong->first_node("diffuse") != 0){
                    if(phong->first_node("diffuse")->first_node("color") != 0){
                        mat.diffuse = getVec4(phong->first_node("diffuse")->first_node("color"));
                    }
                    if(phong->first_node("diffuse")->first_node("texture") != 0){
                        mat.diffuseTexture = textures.at(searchByAttribute(profile, "sid", 
                                searchByAttribute(profile, "sid", phong->first_node("diffuse")->first_node("texture")->first_attribute("texture")->value(), "newparam")
                                ->first_node("sampler2D")->first_node("source")->value()
                                , "newparam")->first_node("surface")->first_node("init_from")->value());
                    }
                }
                if(phong->first_node("specular") != 0){
                    if(phong->first_node("specular")->first_node("color") != 0){
                        mat.specular = getVec4(phong->first_node("specular")->first_node("color"));
                    }
                    if(phong->first_node("specular")->first_node("texture") != 0){
                        mat.specularTexture = textures.at(searchByAttribute(profile, "sid", 
                                searchByAttribute(profile, "sid", phong->first_node("specular")->first_node("texture")->first_attribute("texture")->value(), "newparam")
                                ->first_node("sampler2D")->first_node("source")->value()
                                , "newparam")->first_node("surface")->first_node("init_from")->value());
                    }
                }
                if(phong->first_node("shininess") != 0){
                    mat.shininess = std::stof(phong->first_node("shininess")->first_node("float")->value());
                }
            } else {
                Logger::error << "Couldn't load model: material doesn't use the phong technique." << std::endl;
                return false;
            }
            if(technique->first_node("extra") != 0 && technique->first_node("extra")->first_node("technique")->first_node("bump") != 0){
                mat.bumpmapTexture = textures.at(searchByAttribute(profile, "sid", 
                                searchByAttribute(profile, "sid", technique->first_node("extra")->first_node("technique")->first_node("bump")->first_node("texture")->first_attribute("texture")->value(), "newparam")
                                ->first_node("sampler2D")->first_node("source")->value()
                                , "newparam")->first_node("surface")->first_node("init_from")->value());
            }
            effects.insert(std::pair<std::string, Material>(effect->first_attribute("id")->value(), mat));
        } else {
            Logger::error << "Couldn't load model: material doesn't have a profile_COMMON tag." << std::endl;
            return false;
        }
    }
    
    
    //Load materials
    //TODO: make them overridable (collada spec))
    rapidxml::xml_node<> *materialsNode = doc.first_node()->first_node("library_materials");
    if(materialsNode->first_node("material") == 0){
        Logger::error << "Couldn't load model: file contains no material data." << std::endl;
        return false;
    }
    std::map<std::string, Material> materials;
    for(rapidxml::xml_node<> *material = materialsNode->first_node("material"); material != 0; material = material->next_sibling("material")){
        materials.insert(std::pair<std::string, Material>(material->first_attribute("id")->value(), effects.at(std::string(material->first_node("instance_effect")->first_attribute("url")->value()).substr(1))));
    }
    
    
    //Load geometry
    std::map<std::string, Mesh> meshes;
    rapidxml::xml_node<> *geometries = doc.first_node()->first_node("library_geometries");
    if(geometries->first_node("geometry") == 0){
        Logger::error << "Couldn't load model: file contains no geometry data." << std::endl;
        return false;
    }
    for(rapidxml::xml_node<> *geometry = geometries->first_node("geometry"); geometry != 0; geometry = geometry->next_sibling("geometry")){
        Mesh mesh;        
        rapidxml::xml_node<> *meshNode = geometry->first_node("mesh");
        if(meshNode == 0){
            Logger::error << "Couldn't load model: The loader can only load geometry of type \"mesh\" (geometry with name: " << geometry->first_attribute("name")->value() << ")." << std::endl;
            return false;
        }
        if(meshNode->first_node("polylist") == 0){
            Logger::error << "Couldn't load model: The loader can only load meshes that use polylists. (geometry with name: " << geometry->first_attribute("name")->value() << ")." << std::endl;
            return false;
        }
        
        //TODO: allow for multiple data types
        //<name, <stride, data>>
        std::map<std::string, std::pair<unsigned int, std::vector<float>>> sources;
        GLenum dataType;
        for(rapidxml::xml_node<> *source = meshNode->first_node("source"); source != 0; source = source->next_sibling("source")){
            std::vector<float> container;
            dataType = readData(&container, source);
            if(dataType == GL_NONE){
                return false;
            }
            sources.insert(std::pair<std::string, std::pair<unsigned int, std::vector<float>>>(source->first_attribute("id")->value(), std::pair<unsigned int, std::vector<float>>(std::stoi(source->first_node("technique_common")->first_node("accessor")->first_attribute("stride")->value()), container)));
        }
        
        //TODO: same data vertex merging (aka indexing)
        for(rapidxml::xml_node<> *polylist = meshNode->first_node("polylist"); polylist != 0; polylist = polylist->next_sibling("polylist")){
            std::vector<float> openglData;
            std::vector<unsigned int> indices;
            std::vector<std::string> tempContainer;
            std::vector<int> colladaIndices;        
            split(polylist->first_node("p")->value(), " ", &tempContainer);
            for(std::string s : tempContainer){
                colladaIndices.push_back(std::stoi(s));
            }
            std::vector<float> vertexData;
            float vertexOffset;
            float vertexStride;
            std::vector<float> normalData;
            float normalOffset;
            float normalStride;
            std::vector<float> uvData;
            float uvOffset;
            float uvStride;
            
            std::pair<unsigned int, std::vector<float>> pair;
            for(rapidxml::xml_node<> *input = polylist->first_node("input"); input != 0; input = input->next_sibling("input")){
                std::string semantic(input->first_attribute("semantic")->value());
                if(semantic == "VERTEX"){
                    pair = sources.at(std::string(meshNode->first_node("vertices")->first_node("input")->first_attribute("source")->value()).substr(1));
                    vertexData = pair.second;
                    vertexOffset = std::stoi(input->first_attribute("offset")->value());
                    vertexStride = pair.first;
                } else if(semantic == "NORMAL"){
                    pair = sources.at(std::string(input->first_attribute("source")->value()).substr(1));
                    normalData = pair.second;
                    normalOffset = std::stoi(input->first_attribute("offset")->value());
                    normalStride = pair.first;
                } else if(semantic == "TEXCOORD"){
                    pair = sources.at(std::string(input->first_attribute("source")->value()).substr(1));
                    uvData = pair.second;
                    uvOffset = std::stoi(input->first_attribute("offset")->value());
                    uvStride = pair.first;
                } else {
                    Logger::error << "Unknown input semantic: " << semantic << std::endl;
                    return 0;
                }
            }            
            PolyGroup poly;
            poly.elements = std::stoi(polylist->first_attribute("count")->value())*3;
            
            //Generate vertices
            for(unsigned int i = 0; i < poly.elements; i++){
                openglData.push_back(vertexData.at(colladaIndices.at(i*3+vertexOffset)*vertexStride));
                if(zup){
                    openglData.push_back(vertexData.at(colladaIndices.at(i*3+vertexOffset)*vertexStride+2));
                    openglData.push_back(-vertexData.at(colladaIndices.at(i*3+vertexOffset)*vertexStride+1));
                } else {
                    openglData.push_back(vertexData.at(colladaIndices.at(i*3+vertexOffset)*vertexStride+1));
                    openglData.push_back(vertexData.at(colladaIndices.at(i*3+vertexOffset)*vertexStride+2));
                }

                openglData.push_back(normalData.at(colladaIndices.at(i*3+normalOffset)*normalStride));
                if(zup){
                    openglData.push_back(normalData.at(colladaIndices.at(i*3+normalOffset)*normalStride+2));
                    openglData.push_back(-normalData.at(colladaIndices.at(i*3+normalOffset)*normalStride+1));
                } else {
                    openglData.push_back(normalData.at(colladaIndices.at(i*3+normalOffset)*normalStride+1));
                    openglData.push_back(normalData.at(colladaIndices.at(i*3+normalOffset)*normalStride+2));
                }

                openglData.push_back(uvData.at(colladaIndices.at(i*3+uvOffset)*uvStride));
                //collada stores the uv data the other way around. how silly.
                openglData.push_back(1.0f - uvData.at(colladaIndices.at(i*3+uvOffset)*uvStride+1));

                //temp index
                indices.push_back(i);
            }
            poly.vaoid = sendToOpengl(openglData, indices);
            poly.material = materials.at(polylist->first_attribute("material")->value());
            mesh.addPolyGroup(poly);
        }
        meshes.insert(std::pair<std::string, Mesh>(geometry->first_attribute("id")->value(), mesh));
        //this->meshes.insert(std::pair<std::string, std::pair<glm::mat4, Mesh>>(std::string(geometry->first_attribute("id")->value()).substr(1), std::pair<glm::mat4, Mesh>(glm::mat4(1.0f), mesh)));
    }
    
    //Load scene
    rapidxml::xml_node<> *scenes = doc.first_node()->first_node("library_visual_scenes");
    if(scenes->first_node("visual_scene") == 0){
        Logger::error << "Couldn't load model: file contains no scene data." << std::endl;
        return false;
    } else {
        rapidxml::xml_node<> *scene = scenes->first_node("visual_scene");
        for(rapidxml::xml_node<> *node = scene->first_node("node"); node != 0; node = node->next_sibling("node")){
            if(node->first_node("instance_geometry") != 0){
                std::vector<float> matrix;
                std::vector<std::string> tempContainer;
                glm::mat4 mat4 = glm::mat4(1.0f);
                if(node->first_node("matrix") == 0){
                    split(node->first_node("translate")->value(), " ", &tempContainer);
                    mat4 = glm::translate(mat4, glm::vec3(std::stof(tempContainer[0]), std::stof(tempContainer[2]), -std::stof(tempContainer[1])));
                    tempContainer.clear();
                    split(searchByAttribute(node, "sid", "rotationX", "rotate")->value(), " ", &tempContainer);
                    mat4 = glm::rotate(mat4, glm::radians(std::stof(tempContainer[3])), glm::vec3(1.0f, 0.0f, 0.0f));
                    tempContainer.clear();
                    split(searchByAttribute(node, "sid", "rotationZ", "rotate")->value(), " ", &tempContainer);
                    mat4 = glm::rotate(mat4, glm::radians(std::stof(tempContainer[3])), glm::vec3(0.0f, 1.0f, 0.0f));
                    tempContainer.clear();
                    split(searchByAttribute(node, "sid", "rotationY", "rotate")->value(), " ", &tempContainer);
                    mat4 = glm::rotate(mat4, glm::radians(std::stof(tempContainer[3])), glm::vec3(0.0f, 0.0f, -1.0f));
                    tempContainer.clear();
                    split(node->first_node("scale")->value(), " ", &tempContainer);
                    mat4 = glm::scale(mat4, glm::vec3(std::stof(tempContainer[0]), std::stof(tempContainer[2]), std::stof(tempContainer[1])));
                    //mat4 = glm::mat4(1.0f);
                } else {
                    split(node->first_node("matrix")->value(), " ", &tempContainer);
                    for(std::string s : tempContainer){
                        matrix.push_back(std::stof(s));
                    }
                    glm::mat4 mat4 = glm::make_mat4(matrix.data());
                    if(std::string(doc.first_node()->first_node("asset")->first_node("up_axis")->value()) == "Z_UP"){
                        mat4 = convertToRightHandedCoords(mat4);
                    }
                }
                this->meshes.insert(std::pair<std::string,std::pair<glm::mat4, Mesh>>(
                        node->first_attribute("id")->value(),
                        std::pair<glm::mat4, Mesh>(
                            mat4,
                            meshes.at(std::string(node->first_node("instance_geometry")->first_attribute("url")->value()).substr(1)))));
            }
        }
    }
    rapidjson::Document animDoc;
    if(readJsonFile(filename.substr(0, filename.find_last_of("/")+1) + "animation.json", animDoc)){
        rapidxml::xml_node<> *animations = doc.first_node()->first_node("library_animations");
        if(animations->first_node("animation") != 0){
            std::map<std::string, std::vector< std::pair<float, glm::vec3> > > locationKeyframes;
            std::map<std::string, std::vector< std::pair<float, glm::vec3> > > rotationKeyframes;
            for(rapidxml::xml_node<> *animNode = animations->first_node("animation"); animNode != 0; animNode = animNode->next_sibling("animation")){
                std::vector<float> inputContainer;
                readData(&inputContainer, searchByAttribute(
                        animNode,
                        "id",
                        std::string(searchByAttribute(
                            animNode->first_node("sampler"),
                            "semantic",
                            "INPUT",
                            "input"
                        )->first_attribute("source")->value()).substr(1),
                        "source"));
                std::vector<float> outputContainer;
                readData(&outputContainer, searchByAttribute(
                        animNode,
                        "id",
                        std::string(searchByAttribute(
                            animNode->first_node("sampler"),
                            "semantic",
                            "OUTPUT",
                            "input"
                        )->first_attribute("source")->value()).substr(1),
                        "source"));/*
                std::vector< std::pair<float, glm::vec3> > keyframes;
                for(int i = 0; i < inputContainer.size(); i++){
                    keyframes.push_back(std::pair<float, glm::vec3>(inputContainer.at(i), outputContainer.at(i)));
                }*/
                std::string target = animNode->first_node("channel")->first_attribute("target")->value();
                std::string meshName = target.substr(0, target.find_first_of("/"));
                if(target.substr(target.find_first_of("/")+1, target.find_first_of(".")-target.find_first_of("/")-2) == "rotation"){
                    if(!rotationKeyframes.count(meshName)){
                        rotationKeyframes.insert(std::pair<std::string, std::vector< std::pair<float, glm::vec3> > >(meshName, std::vector< std::pair<float, glm::vec3> >()));
                    }
                    for(int i = 0; i < inputContainer.size(); i++){
                        if(rotationKeyframes.at(meshName).size() <= i){
                            rotationKeyframes.at(meshName).push_back(std::pair<float, glm::vec3>(inputContainer.at(i), glm::vec3(0.0f, 0.0f, 0.0f)));
                        }
                        if(target.substr(target.find_first_of("/")+1, target.find_first_of(".")-target.find_first_of("/")-1) == "rotationX"){
                            rotationKeyframes.at(meshName).at(i).second.x = outputContainer.at(i);
                        } else if(target.substr(target.find_first_of("/")+1, target.find_first_of(".")-target.find_first_of("/")-1) == "rotationY"){
                            rotationKeyframes.at(meshName).at(i).second.y = outputContainer.at(i);
                        } else if(target.substr(target.find_first_of("/")+1, target.find_first_of(".")-target.find_first_of("/")-1) == "rotationZ"){
                            rotationKeyframes.at(meshName).at(i).second.z = outputContainer.at(i);
                        }
                    }
                } else if(target.substr(target.find_first_of("/")+1, target.find_first_of(".")) == "location"){
                    if(locationKeyframes.count(meshName)){
                        locationKeyframes.insert(std::pair<std::string, std::vector< std::pair<float, glm::vec3> > >(meshName, std::vector< std::pair<float, glm::vec3> >()));
                    }
                    for(int i = 0; i < inputContainer.size(); i++){
                        if(locationKeyframes.at(meshName).size() <= i){
                            locationKeyframes.at(meshName).push_back(std::pair<float, glm::vec3>(inputContainer.at(i), glm::vec3(0.0f, 0.0f, 0.0f)));
                        }
                        if(target.substr(target.find_first_of(".")+1) == "X"){
                            locationKeyframes.at(meshName).at(i).second.x = outputContainer.at(i);
                        } else if(target.substr(target.find_first_of(".")+1) == "Y"){
                            locationKeyframes.at(meshName).at(i).second.y = outputContainer.at(i);
                        } else if(target.substr(target.find_first_of(".")+1) == "Z"){
                            locationKeyframes.at(meshName).at(i).second.z = outputContainer.at(i);
                        }
                    }
                } else {
                    Logger::info << "unknown animation target: " << target << std::endl;
                }
            }
            for (rapidjson::SizeType i = 0; i < animDoc.Size(); i++) {
                Animation animation;
                rapidjson::Value& animjson = animDoc[i];
                animation.mesh = animjson["mesh"].GetString();
                int start = animjson["startKeyframe"].GetInt();
                int end = animjson["endKeyframe"].GetInt();
                for(int j = start; j <= end; j++){
                    glm::mat4 mat4 = this->meshes.at(animation.mesh).first;
                    glm::vec3 rotation = rotationKeyframes.count(animation.mesh) ? rotationKeyframes.at(animation.mesh).at(j).second : glm::vec3(0.0f, 0.0f, 0.0f);
                    glm::vec3 translation = locationKeyframes.count(animation.mesh) ? locationKeyframes.at(animation.mesh).at(j).second : glm::vec3(0.0f, 0.0f, 0.0f);
                    if(zup){
                        mat4 = glm::translate(mat4, glm::vec3(translation.x, translation.z, -translation.y));
                        mat4 = glm::rotate(mat4, glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f));
                        mat4 = glm::rotate(mat4, glm::radians(rotation.z), glm::vec3(0.0f, 1.0f, 0.0f));
                        mat4 = glm::rotate(mat4, glm::radians(rotation.y), glm::vec3(0.0f, 0.0f, -1.0f));
                    } else {
                        mat4 = glm::translate(mat4, glm::vec3(translation.x, translation.y, translation.z));
                        mat4 = glm::rotate(mat4, glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f));
                        mat4 = glm::rotate(mat4, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f));
                        mat4 = glm::rotate(mat4, glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f));
                    }
                    animation.keyframes.push_back(std::make_pair(rotationKeyframes.at(animation.mesh).at(j).first, mat4));
                }
                this->animations.insert(std::make_pair(animjson["name"].GetString(), animation));
            }
        }
    }
    return true;
}
Пример #4
0
Model* Scene::buildModel(Json::Value model) {
    string type = model["class"].asString();
    Model *retModel;
    // menger
    if(type.compare("Menger") == 0) {
        vec3 center = getVec3(model.get("center", "[0,0,0]"));
        printVec("center",center);
        float radius = model.get("radius", "1.0").asFloat();
        int subdivs = model.get("subdivisions", "2").asInt();
        retModel = new Menger(center, radius, subdivs);
    }
    // sphere
    else if(type.compare("Sphere") == 0) {
        Sphere *sphere;
        if(!model.isMember("ambient")) {
            sphere = new Sphere(
                model["radius"].asFloat(),
                model["subdivs"].asInt(),
                lights.size());
        } else {
            sphere = new Sphere(
                model["radius"].asFloat(),
                model["subdivs"].asInt(),
                lights.size(),
                getVec4(model.get("ambient","[1,0,1,1]")),
                getVec4(model.get("diffuse","[1,0.8,0,1]")),
                getVec4(model.get("specular","[1,0,1,1]")));
        }
        vector<Light*>::iterator it;
        int light = 0;
        for(it = lights.begin(); it != lights.end(); it++) {
            sphere->setLight((*it), light++);
        }
        retModel = sphere;
    } else if(type.compare("TexTri") == 0) {
        retModel = new TexTri(model["texture"].asString().c_str());
        printf("created textri\n");
    } else if(type.compare("ObjModel") == 0) {
        ObjModel *obj = new ObjModel(model["objfile"].asString().c_str(),
                                     lights.size(),
                                     getVec4(model.get("ambient","[1,1,1,1]")),
                                     getVec4(model.get("diffuse","[1,1,1,1]")),
                                     getVec4(model.get("specular","[1,1,1,1]")));
        vector<Light*>::iterator it;
        int light = 0;
        for(it = lights.begin(); it != lights.end(); it++) {
            obj->setLight((*it), light++);
        }
        retModel = obj;
    } else if(type.compare("Tesseract") == 0) {
        Tesseract *tess = new Tesseract( lights.size() );
        vector<Light*>::iterator it;
        int light = 0;
        for(it = lights.begin(); it != lights.end(); it++) {
            tess->setLight((*it), light++);
        }
        retModel = tess;
    } else if(type.compare("Particles") == 0) {
        Particles *part = new Particles( model.get("number",50).asInt() );
        retModel = part;
    }

    // map model if it has an id
    if(model.isMember("id")) {
        string id = model["id"].asString();
        nodes[id] = retModel;
        idModels[id] = retModel;
    }
    return retModel;
}