Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Не "ставятся" нормали
Форум .:3DCenter.ru:. > Пакеты 3D моделирования > 3ds Max > 3ds max SDK
Pancir
Всем привет, пишу импортер dsf формата от X-Plane 9
Столкнулся со странной проблемой, вроде "ставлю" нормали но в итоге мешь не сглаженный.... Толи макс переопределяет их, то ли я, что-то упустил... Пс когда писал на скрипте там нормали ставились нормально..... Правда так же пересчитывались, стоило только набросить едит мешь.....

CODE
TriObject *OBJMesh::BuildMesh(MeshDataT *MeshData) {
    mtri = CreateNewTriObject();
    Mesh mesh;


    int PrimitiveSize = (int)MeshData->size();
    int VertexSize = 0;
    int FaceSize = 0;
    for (int i = 0; i < PrimitiveSize; i++){ // Get amount of all Vertex and all Faces
        VertexSize += (int) MeshData->at(i).second.size();
        if (MeshData->at(i).first == 0) //TRI
            FaceSize += (int) MeshData->at(i).second.size()/3;
        if (MeshData->at(i).first == 2) //FAN
            FaceSize += (int) MeshData->at(i).second.size()-2;
    }

    mesh.setNumVerts (VertexSize);
    mesh.setNumTVerts(VertexSize);
    mesh.setNumFaces (FaceSize);
    mesh.setNumTVFaces (FaceSize);

    int vertindex = 0;
    int fvertindex = 0;
    int FanVertCorrection = 0;
    int faceindex = 0;
    for ( int i = 0; i < PrimitiveSize; i++) {
        for (int j = 0; j < MeshData->at(i).second.size(); j++) {
            mesh.setVert    (vertindex, MeshData->at(i).second.at(j).Position);
            mesh.setNormal    (vertindex, MeshData->at(i).second.at(j).Normal);
            mesh.setTVert    (vertindex, MeshData->at(i).second.at(j).Texture);
            vertindex++;
        }
        switch (MeshData->at(i).first) {
            case DSF_TRI:             //-- 012 234 567 8910 ......            
                for (int n = 0; n < MeshData->at(i).second.size() / 3; n++ ) {
                    mesh.faces[faceindex].setVerts(fvertindex+2,fvertindex+1,fvertindex);
                    mesh.faces[faceindex].setEdgeVisFlags(1,1,1);
                    mesh.tvFace[faceindex].setTVerts(fvertindex+2,fvertindex+1,fvertindex);
                    mesh.faces[faceindex].setSmGroup(1);

                    faceindex +=1;
                    fvertindex+=3;
                }
                break;
            case DSF_TRISTRIP:
                break;
            case DSF_TRIFAN: // --012 023  034 045 056......    
                FanVertCorrection = fvertindex; // Correction first vertex of FAN patch, this is need shift after any loop (after and before)
                for (int n = 0; n < MeshData->at(i).second.size()-2; n++ ) {
                    mesh.faces[faceindex].setVerts(fvertindex+2,fvertindex+1, FanVertCorrection);
                    mesh.faces[faceindex].setEdgeVisFlags(1,1,1);
                    mesh.tvFace[faceindex].setTVerts(fvertindex+2,fvertindex+1, FanVertCorrection);
                    mesh.faces[faceindex].setSmGroup(1);
                    faceindex +=1;
                    fvertindex +=1;
                }
                fvertindex +=2;
                break;
        }  
    }
    mtri->mesh = mesh;
    return this->mtri;
}
OnePride
нормалями не занимался, но в конце после всех изменений с мешем должно стоять mesh.InvalidateGeomCache(). Еще перед кэшем стоит попробовать написать ченить типа Mesh::buildNormals() или Mesh::buildRenderNormals()
OnePride
Ну и обращение mesh.faces разумно заменить на Face *faces = mesh.faces, и обращаться просто как faces[]. На решение проблемы не влияет, но работать будет пошустрее на толстых сценах... smile.gif
Pancir
Mesh::buildNormals()
крешит макс уже пробовал


mesh.InvalidateGeomCache()
ставил InvalidateTopologyCache(), на результат не влияло. в чем отличия между InvalidateGeomCache?
проверил с InvalidateGeomCache тоже ничего не измеилось..


Заметил что те же текстурные вершины и фэйсы пришлось делать "в ручную"
может с нормалями надо что то еще сделать? например фэйсу явно присвоить?
Я правда пробовал жестко вставить попробовать mesh.setFaceNormal (faceindex, Point3 (0.0,0.0,1.0));
но макс крешанулся опять (

про Face учту пасибки )
OnePride
InvalidateTopologyCache вызывается когда изменялись видимые грани и/или добавлялись новые точки и фейсы. InvalidateGeomCache более глобальная штука) Если ее не вызывать могут быть проблемы и с отображением, и с последующим обращением к мешу из других методов, что будет вызывать краш.

Если крашится buildNormals вероятно у тебя идет обращение к несуществующему элементу массива. Видимо есть несоответствие между заявленным количеством вершин/фейсов (с помощью setNumVerts и т.п.), и количеством определенных в коде функции. Неиспользованные вершины и фейсы вызывают краш. И вопрос такой - почему количество текстурных вершин равно количеству реальных? Если меш это два фейса с 4 вершинами и 1 общим ребром, то текстурных вершин может быть от 3 до 6, аналогично и для фейсов, возможно здесь есть косяк
Pancir
QUOTE
И вопрос такой - почему количество текстурных вершин равно количеству реальных? Если меш это два фейса с 4 вершинами и 1 общим ребром, то текстурных вершин может быть от 3 до 6, аналогично и для фейсов, возможно здесь есть косяк

специфика самого формата, который импорчу.....
1 вершина - 1 нормаль - 1 текстурная координата.....
фэйсы строятся как в коментах
//-- 012 234 567 8910 ......
// --012 023 034 045 056......

По подсчету вершин перепроверю еще раз.....
хотя как это сделать я хз, ибо сам алгоритм подсчета и постройки вершин - прозрачный, и ошибки в нем лично я не наблюдаю (( Вот с фэйсами может быть....
Lastjedi
buildNormals () нужно обязательно, а макс падает скорее всего по простой причине.
Смотри:
- сначала ты создаешь новый TriObject
Код
mtri = CreateNewTriObject();
Он уже содержит сетку TriObject::mesh
- однако потом, ты создаешь новый объект типа Mesh
Код
Mesh mesh;
Он существует только внутри твоей функции BuildMesh(...), и будет разрушен при выходе из нее.
- затем ты наполняешь именно этот временный объект данными, и копируешь его в созданный вначале TriObject. Однако, если посмотреть в SDK описание Mesh& Mesh::operator= (const Mesh &fromMesh), то там есть очень важное замечание:
Цитата
...This operator does not copy the rVerts array...
, т.е. данные о нормалях скопированы не будут! Они благополучно погибнут после выхода из функции. Соответственно, указания на наличие в объекте информации о нормалях станут неверными, что и проводит к падению макса.

Наверное имеет смысл не создавать отдельно объект mesh, а использовать ссылку на mesh из TriObject, исключив, таким образом, саму операцию копирования.
Pancir
Привет Павел.... я прям где то в глубине души надеялся, что ты зайдешь ))

QUOTE
Он уже содержит сетку TriObject::mesh
- однако потом, ты создаешь новый объект типа Mesh

Мде, это я из виду упустил..

А с ссылками и указателями я вечно путаюсь, тут мне другой человек помогал с ними, вроде пытались сделать как раз, что бы не было так как ты описываешь ))
Вообщем сделал так..... но нормалей снова нету ( пробовал вставить содержимое функции прям в "ноде", что бы гарантированно избежать проблем..... один фиг с нормалями косяк.....

CODE
void ImportNode::CreateTerr(DSFTerrCaption *DSFTerrCapt,  MeshDataT *MeshData) {

    ImpNode *mnode = this->iFace->CreateNode();

    if (mnode){
        OBJMesh *mesh = new OBJMesh ();
        mnode->Reference(mesh->BuildMesh(MeshData));
        delete (mesh);
        mnode->SetTransform(0,this->tm);
        this->iFace->AddNodeToScene(mnode);

        char tempChar[255];
        sprintf(tempChar, "%u", DSFTerrCapt->Type);
        SetNodeName( TSTR (NAME_PREFIX) + TSTR ("TERR_") + TSTR (tempChar));

        //this->iP->MakeNameUnique(this->NodeName);
        mnode->SetName(this->NodeName);

        // Get access to the actual node for the next part
        INode *minode = mnode->GetINode();

        minode->SetUserPropInt ( TSTR(NAME_PREFIX) + TSTR("TERR_") + TSTR("DEPTHS") ,DSFTerrCapt->Depths); // Depths
        minode->SetUserPropInt ( TSTR(NAME_PREFIX) + TSTR("TERR_") + TSTR("TYPE"),DSFTerrCapt->Type); // Type
        minode->SetUserPropInt ( TSTR(NAME_PREFIX) + TSTR("TERR_") + TSTR("FLAG"), DSFTerrCapt->Flags);// Flag
        minode->SetUserPropFloat ( TSTR(NAME_PREFIX) + TSTR("TERR_") + TSTR("LODNear"), DSFTerrCapt->LODNear); // Lodnear
        minode->SetUserPropFloat ( TSTR(NAME_PREFIX) + TSTR("TERR_") + TSTR("LODFar"), DSFTerrCapt->LODFar); // Lodfar
    }
}


CODE
class OBJMesh {
public:
    
    TriObject *BuildMesh (MeshDataT *MeshData);
    TriObject *mtri;
    //Mesh mesh;

    OBJMesh ();
    ~OBJMesh ();
};


CODE
TriObject *OBJMesh::BuildMesh(MeshDataT *MeshData) {
    mtri = CreateNewTriObject();

    int PrimitiveSize = (int)MeshData->size();
    int VertexSize = 0;
    int FaceSize = 0;
    for (int i = 0; i < PrimitiveSize; i++){ // Get amount of all Vertex and all Faces
        VertexSize += (int) MeshData->at(i).second.size();
        if (MeshData->at(i).first == 0) //TRI
            FaceSize += (int) MeshData->at(i).second.size()/3;
        if (MeshData->at(i).first == 2) //FAN
            FaceSize += (int) MeshData->at(i).second.size()-2;
    }

    mtri->mesh.setNumVerts (VertexSize);
    mtri->mesh.setNumTVerts(VertexSize);
    mtri->mesh.setNumFaces (FaceSize);
    mtri->mesh.setNumTVFaces (FaceSize);

    int vertindex = 0;
    int fvertindex = 0;
    int FanVertCorrection = 0;
    int faceindex = 0;
    for ( int i = 0; i < PrimitiveSize; i++) {
        for (int j = 0; j < MeshData->at(i).second.size(); j++) {
            mtri->mesh.setVert    (vertindex, MeshData->at(i).second.at(j).Position);
            mtri->mesh.setNormal    (vertindex, MeshData->at(i).second.at(j).Normal);
            mtri->mesh.setTVert    (vertindex, MeshData->at(i).second.at(j).Texture);
            vertindex++;
        }
        switch (MeshData->at(i).first) {
            case DSF_TRI:             //-- 012 234 567 8910 ......            
                for (int n = 0; n < MeshData->at(i).second.size() / 3; n++ ) {
                    mtri->mesh.faces[faceindex].setVerts(fvertindex+2,fvertindex+1,fvertindex);
                    mtri->mesh.faces[faceindex].setEdgeVisFlags(1,1,1);
                    mtri->mesh.tvFace[faceindex].setTVerts(fvertindex+2,fvertindex+1,fvertindex);
                    //mtri->mesh.faces[faceindex].setSmGroup(1);
                    faceindex +=1;
                    fvertindex+=3;
                }
                break;
            case DSF_TRISTRIP:
                break;
            case DSF_TRIFAN: // --012 023  034 045 056......    
                FanVertCorrection = fvertindex; // Correction first vertex of FAN patch, this is need shift after any loop (after and before)
                for (int n = 0; n < MeshData->at(i).second.size()-2; n++ ) {
                    mtri->mesh.faces[faceindex].setVerts(fvertindex+2,fvertindex+1, FanVertCorrection);
                    mtri->mesh.faces[faceindex].setEdgeVisFlags(1,1,1);
                    mtri->mesh.tvFace[faceindex].setTVerts(fvertindex+2,fvertindex+1, FanVertCorrection);
                    //mtri->mesh.faces[faceindex].setSmGroup(1);
                    faceindex +=1;
                    fvertindex +=1;
                }
                fvertindex +=2;
                break;
        }  
    }
    mtri->mesh.buildNormals ();
    mtri->mesh.InvalidateGeomCache();  
    return this->mtri;
}
OnePride
Попробуй просто загрузить меш без нормалей, если все ок, то попробуй изменить пару нормалей и вызвать buildnormals, должно все получиться.
Lastjedi
В приведенном коде ошибки пока не нахожу. Не очень понял назначение класса OBJMesh.
Имеет смысл проверить корректность чтения нормалей из файла, единичность векторов этих нормалей и систему координат в которой они заданы.
Если не сложно, выложи максовский файл с импортированным объектом. Хочется посмотреть, на нормали сразу после импорта.

Небольшое дополнение...
Меня терзают смутные сомнения... smile.gif

Попробуй вместо
Код
mtri->mesh.InvalidateGeomCache();
поставить
Код
mtri->mesh.buildBoundingBox();
mtri->mesh.InvalidateEdgeList();

Очень уж InvalidateGeomCache крутой. Он ко всему прочему чистит еще и кэш нормалей... Ни к чему это.
Pancir
QUOTE
Не очень понял назначение класса OBJMesh

Логически разделил, с нодой работаем "тут" а мешь пусть "там" строится ))
хотя наверное надо было просто функцию в классе нода сделать )) вообщем хз о чем я думал в тот момент ))...

QUOTE
Имеет смысл проверить корректность чтения нормалей из файла, единичность векторов этих нормалей и систему координат в которой они заданы.

Да нормали там хитрые, там всего 2 координаты x и z (z не высота, высота Y которой нету) y вычисляется, я уже догадываюсь как, но пока эти вычисления не провожу, взял Y за 1 и сделал нормализацию.... Вообщем странно то что вообще нет реакции на числа нормалей, сейчас по фигу насколько они правильные, ( с другой стороны в скрипте такой расклад работал, я там даже нормализацию не делал, и кусков там больше было, это тут на С++ я объединяю однотипные, а там не ))

CODE
    if (DSFTerrCapt.Depths > 3){ // Set Normal
        Point3 NNorm  (triCoord.at(3), triCoord.at(4), 1.0);
        NNorm = Normalize (NNorm);
        DSFPatchCoord.Normal = NNorm;
    } else {
        DSFPatchCoord.Normal = Point3 (0.0, 0.0, 1.0);
    }


когда через дебаг смотрел, числа до меша доходят, так же с такими данными нормали я пробовал делать импорт через максскрипт, результат в норме , но...........

это то как мешь выглядит при импорте сриптом
http://s53.radikal.ru/i142/1112/4a/83b14caf0530.jpg

это тот же мешь, только сверху накинул модификатор едит мешь
http://s005.radikal.ru/i211/1112/ba/f8f8538db6eb.jpg

CODE
mtri->mesh.buildBoundingBox();
mtri->mesh.InvalidateEdgeList();

(( не помогло


Пс почему так важны нормали? в выложенном файле видно, что мешь состоит из кусков, и если не сделать нормали то придется это все аттачить и сглаживать, и потом разбивать при экспорте, а каждый кусок имеет свои не автоматические (т.е задаются ручками) параметры....

http://file.qip.ru/file/haaaxSpd/5537.html


QUOTE
Попробуй просто загрузить меш без нормалей, если все ок, то попробуй изменить пару нормалей и вызвать buildnormals, должно все получиться.

Тут разве, что в ручную надо построить кусок меша и смотреть, ибо импорт идет с бинарника, и там мешь куска земли, размером в 1 градус широты и долготы....
А вообще надо правда построить 2 треугольника в максе, снять с них данные нормали и координат вертексов, и попробовать хардкорно построить и глянуть чего выйдет.....
Pancir
Такс был произведен эксперимент...

CODE
TriObject *OBJMesh::BuildMesh(MeshDataT *MeshData) {
    mtri = CreateNewTriObject();

        mtri->mesh.setNumVerts (4);
        mtri->mesh.setNumFaces (2);
        //-----------------------------------------
        mtri->mesh.setVert    (0, Point3(50.0,50.0,-25.0));
        mtri->mesh.setNormal(0, Point3(0.707107,0.0,0.707107));

        mtri->mesh.setVert    (1, Point3(0.0,100.0,25.0));
        mtri->mesh.setNormal(1, Point3(0.0,0.0,1.0));

        mtri->mesh.setVert    (2, Point3(0.0,0.0,25.0));
        mtri->mesh.setNormal(2, Point3(0.0,0.0,1.0));

        mtri->mesh.setVert    (3, Point3(-50.0,50.0,-25.0));
        mtri->mesh.setNormal(3, Point3(-0.707107,0.0,0.707107));

        mtri->mesh.faces[0].setVerts(0,1,2);
        mtri->mesh.faces[0].setEdgeVisFlags(1,1,1);

        mtri->mesh.faces[1].setVerts(2,1,3);
        mtri->mesh.faces[1].setEdgeVisFlags(1,1,1);

        //mtri->mesh.setFaceNormal (0,Point3(0.707107,0.0,0.707107));
        //mtri->mesh.setFaceNormal (1,Point3(-0.707107,0.0,0.707107));
        //-----------------------------------------
        mtri->mesh.buildNormals ();
        mtri->mesh.buildBoundingBox();
        mtri->mesh.InvalidateEdgeList();
        return this->mtri;
}


хотел попробовать прописать нормали фэйсам тоже
//mtri->mesh.setFaceNormal (0,Point3(0.707107,0.0,0.707107));
//mtri->mesh.setFaceNormal (1,Point3(-0.707107,0.0,0.707107));
но крешь у макса на это ((

Вообщем при таком раскладе нормали так же не ставятся
а вот сам объект, нормали вершин на сгибе должны быть 0 0 1




Вообщем этот эксперимент говорит о том, что где-то, что-то упущено (какая то деталь). Возможно фэйсам также надо ставить нормали, например создать текстурные вертексы не достаточно, нужно еще и и текстурные фэйсы делать, возможно с нормалями нечто похожее.... Интересно почему макс крешится на setFaceNormal?
OnePride
Зайдем с другой стороны, а к чему такая необходимость в импорте нормалей, когда макс их автоматически считает в случае присвоения фейсам группы сглаживания? Тем более что это карта земли, я не думаю что в ней кто-то от руки нормали выставлял) Более того, покопавшись в хелпе сдк и примерах, пришло понимание о глубине извращений с представлением нормалей в самом максе и тонкой связи между "рендер" нормалями и "просто" нормалями. Далее, setFaceNormal определяет одну единственную нормаль для фейса - это не та нормаль, которую нужно изменять по отношению к плоскости фейса. Если нужно манипулировать сглаживанием, то нормалей у фейса всегда 3, и они определены для каждой вершины. В случае, если у фейсов одна общая вершина, то для этой вершины для каждого фейса и для каждой группы сглаживания хранится своя нормаль. Я не знаю как словами это объяснить понятнее, но, если вкратце, во все это вникать не нужно )))))))))))

Код
TriObject *mtri = CreateNewTriObject();
Mesh *mesh = &mtri->mesh;

mesh->setNumVerts (4);
mesh->setNumFaces (2);
//-----------------------------------------
mesh->setVert    (0, Point3(50.0,50.0,-25.0));
mesh->setVert    (1, Point3(0.0,100.0,25.0));
mesh->setVert    (2, Point3(0.0,0.0,25.0));
mesh->setVert    (3, Point3(-50.0,50.0,-25.0));

mesh->faces[0].setVerts(0,1,2);
mesh->faces[0].setEdgeVisFlags(1,1,1);
mesh->faces[0].setSmGroup(1);

mesh->faces[1].setVerts(2,1,3);
mesh->faces[1].setEdgeVisFlags(1,1,1);
mesh->faces[1].setSmGroup(1);


mesh->buildNormals();
mesh->buildBoundingBox();
mesh->InvalidateEdgeList();


Если сильно хочется заюзать setFaceNormal, то нужно закоментить setSmGroup, и setFaceNormal выполнять после buildNormals, тогда нормаль изменится, другое дело что при рендере используются другие нормали, и после рендера нормаль во вьюпорте собъется на дефолтную... как связано отображение и обновление рендер нормалей и простых нормалей пока не разбирался...
Lastjedi
Уф...

Я разобрался. В SDK, как всегда, имеет место бардак, но тем интереснее искать решения.

Подробно опишу завтра утром. Сейчас уже не могу.
Но нормали назначаются как им положено.

А насчет групп сглаживания - они не работают между разными элементами сетки и разными объектами, а объединять - не всегда возможно...
Pancir
Если удастся сделать нормали при импорте, и ВАЖНО! и если набросить после этого модификатор например мешь, он не пересчитает все нормали (едит поли пересчитает точно проверил), тогда это облегчит экспорт. Ниже опишу. Если же при любой манипуляции с объектом нормали пересчитаются, тогда смысл делать их на стадии импорта нет никакого....

А теперь о том почему я так к ним прицепился..... Если качал и смотрел мешь, то там видно, что мешь состоит из кусков, которые даже могут накладываться друг на друга, более того не просто могут, а так и делают.... Что бы "восстановить" единым куском "главный" мешь.... т.е правильно с атачить куски, надо постараться.... а об программном таком соединении речи вообще быть не может, ввиду отсутствия логической информации о кусках.... Получается что если после импорта не привести мешь к определенному виду, то очевидно что с нормалями будут проблемы при экспорте.....
На крайний случай я подумал о том, что придется конечно в итоге собирать "главный" мешь (главный это основной мешь, а на него уже эти нашлёпки из кусков кладутся) аттачить как положено, сглаживать, писать инфу о его кусках на уровне id поликов и т.д..... И при экспорте для кусков нашлепок, брать нормали уже с главного меша....... Можно было бы вообще делать эти куски заново при экспорте, но куда писать информацию о полигонах? только если в userprop, так же я еще не до конца понимаю этот формат который импорчу.. + полигоны могу перекрещиваться , т.е один и тот же полигон может иметь например 3 свойства, как в максе это указать? с помощью id уже не прокатит... разве, что делать нэйм селекты....
Вообщем если бы не нормали во всей это истории..... то все бы можно было сделать прозрачно.... в плане экспорта и подготовки модели, но чую я макс подложит все таки свинью с их пересчетами ((
А так же уже присутствует доля интереса, чего они все таки не делаются ))
OnePride
Цитата(Pancir @ 30/12/2011, 23:44) *
А так же уже присутствует доля интереса, чего они все таки не делаются ))
да, стало определенно интересно laugh.gif ищемс решение дальше, авось и Lastjedi нас образумит.
В сдк есть пример maxsdk\howto\import_export\objimp\ по импорту obj формата, там меш строится точно так же как тут и описывали, но с нормалями чего-то явно не хватает, ибо они всеравно в итоге сбиваются...
Pancir
Да смотрел я там примеры, есть еще пример по имп/эксп - dxfio. Правда там так написано, что код читать затруднительно.....
Lastjedi
Итак, доброе утро.

Примеры действительно не работают. Но это не очень удивительно, т.к., например objimp не менялся с 1994 года, а вот работа с нормалями очень сильно менялась, причем несколько раз. В частности с 2002 года (Discreet 3dsmax 6) появился класс MeshNormalSpec, который предназначен именно для управления нормалями. Причем в SDK до сих пор написано "They are used for viewport display, but not for rendering.", но это не правда! Нормали заданные через этот класс прекрасно учитываются при рендеринге. Именно этот класс используется при редактировании нормалей модификатором Edit Normals

Итак, схема работы следующая:

Сначала формируем сетку объекта, не задавая при этом никаких нормалей:
Код
TriObject* TestObject = CreateNewTriObject ();

if (!TestObject) return FALSE;

Mesh& TestObjectMesh = TestObject->GetMesh ();

TestObjectMesh.setNumVerts (4);
TestObjectMesh.setNumFaces (2);

TestObjectMesh.setVert (0, Point3 (50.0f, 50.0f, -25.0f));
TestObjectMesh.setVert (1, Point3 (0.0f, 100.0f, 25.0f));
TestObjectMesh.setVert (2, Point3 (0.0f, 0.0f, 25.0f));
TestObjectMesh.setVert (3, Point3 (-50.0f, 50.0f, -25.0f));

TestObjectMesh.faces[0].setVerts (0, 1, 2);
TestObjectMesh.faces[0].setEdgeVisFlags (1, 1, 1);

TestObjectMesh.faces[1].setVerts (2, 1, 3);
TestObjectMesh.faces[1].setEdgeVisFlags (1, 1, 1);

Затем указываем, что для данной сетки будут использоваться явно заданные нормали:
Код
TestObjectMesh.SpecifyNormals ();

Теперь можно задать значения нормалей:
Код
MeshNormalSpec* MeshSpecifiedNormals = TestObjectMesh.GetSpecifiedNormals ();
if (MeshSpecifiedNormals)
{
    MeshSpecifiedNormals->CheckNormals ();

    MeshSpecifiedNormals->SetNormal (0, 0, Point3 (0.707107f, 0.0f, 0.707107f));
    MeshSpecifiedNormals->SetNormal (0, 1, Point3 (0.0f, 0.0f, 1.0f));
    MeshSpecifiedNormals->SetNormal (0, 2, Point3 (0.0f, 0.0f, 1.0f));

    MeshSpecifiedNormals->SetNormal (1, 0, Point3 (0.0f, 0.0f, 1.0f));
    MeshSpecifiedNormals->SetNormal (1, 1, Point3 (0.0f, 0.0f, 1.0f));
    MeshSpecifiedNormals->SetNormal (1, 2, Point3 (-0.707107f, 0.0f, 0.707107f));
}
SetNormal (int face, int corner, Point3& normal) задет нормаль для указанного угла заданного фейса. Класс MeshNormalSpec предоставляет весьма широкий набор инструментов для управления нормалями, но для данной задачи и этого достаточно.

Заканчиваем как и раньше:
Код
TestObjectMesh.buildBoundingBox ();
TestObjectMesh.InvalidateEdgeList ();
За исключением buildNormals. Вреда от него не будет, но и смысла - тоже. Аналог buildNormals будет вызван автоматически при обращении к MeshSpecifiedNormals->CheckNormals ();.

Модификатор Edit Mesh заданные нормали сохраняет. Edit Poly - естественно разрушает, т.к. создает новый объект вместо исходного TriObject.
Pancir
да уж, интересно почему мне этот класс в хелпе ни разу не попался?sad.gif и упоминание о нем (

Паш спасибо тебе большое..... проверю это все в новом году smile.gif

С Наступающим всех! drinks.gif smile.gif
OnePride
Вчера таки разбирался с MeshNormalSpec, но у меня он крашился при обращении к любому методу... оказалось всего-навсего не хватало строки TestObjectMesh.SpecifyNormals (), при чем функция в сдк не документирована biggrin.gif Вот эта фраза "They are used for viewport display, but not for rendering." просто отлично ввела в заблуждение dry.gif В голове уже рисовались лютые схемы связей между типами нормалей...

вощим Всех с наступающим! laugh.gif

Pancir
Такс ну, что товарищи ))
Благодарю всех кто проявил желание помочь )) проблема решена, нормали строятся.... хелп касаемо этого момента невероятно "полон" )) что "радует", отдельное спасибо автостолу за это ))

Отдельное Спасибо Павлу за то, что потратил на меня время и разобрался с этим всем....

Ложка дегтя во всей это истории с нормалями это то, что импортится стало раза в 3 дольше ( Попытался постройку нормали встроить сразу после постройки фэйса, но увы так работать у мня не захотело, так что "отдельным потоком" строю, как в примере Павла..
Lastjedi
По поводу быстродействия, скорее всего работает медленно из-за того, что функция SetNormal - высокоуровневая. При ее вызове выполняется много дополнительных действий.
Могу предложить заменить блок назначения нормалей новым (низкоуровневым):
Код
MeshNormalSpec* MeshSpecifiedNormals = TestObjectMesh.GetSpecifiedNormals ();
if (MeshSpecifiedNormals)
{
    MeshSpecifiedNormals->SetNumFaces (2);
    MeshSpecifiedNormals->SetNumNormals (6);

    MeshNormalFace* MeshNormalFaceArray = MeshSpecifiedNormals->GetFaceArray ();
    if (MeshNormalFaceArray)
    {
        Point3* SpecifiedNormalsArray = MeshSpecifiedNormals->GetNormalArray ();
        if (SpecifiedNormalsArray)
        {
            int* NormalIDArray;
            int NormalID = -1;
            int FaceID = -1;

            NormalIDArray = MeshNormalFaceArray[++FaceID].GetNormalIDArray ();
            SpecifiedNormalsArray[++NormalID].Set (0.707107f, 0.0f, 0.707107f);
            *NormalIDArray = NormalID;
            SpecifiedNormalsArray[++NormalID].Set (0.0f, 0.0f, 1.0f);
            *(++NormalIDArray) = NormalID;
            SpecifiedNormalsArray[++NormalID].Set (0.0f, 0.0f, 1.0f);
            *(++NormalIDArray) = NormalID;
            MeshNormalFaceArray[FaceID].SpecifyAll ();

            NormalIDArray = MeshNormalFaceArray[++FaceID].GetNormalIDArray ();
            SpecifiedNormalsArray[++NormalID].Set (0.0f, 0.0f, 1.0f);
            *NormalIDArray = NormalID;
            SpecifiedNormalsArray[++NormalID].Set (0.0f, 0.0f, 1.0f);
            *(++NormalIDArray) = NormalID;
            SpecifiedNormalsArray[++NormalID].Set (-0.707107f, 0.0f, 0.707107f);
            *(++NormalIDArray) = NormalID;
            MeshNormalFaceArray[FaceID].SpecifyAll ();

            MeshSpecifiedNormals->SetAllExplicit ();
        }
    }
}

С таким кодом, я думаю, время импорта будет гораздо меньше.
Pancir
не получилось запустить этот код, "провал" уже тут :
CODE
MeshNormalSpec* meshNorm = mtri->mesh.GetSpecifiedNormals();

По скорости хоть и дольше с нормалями, но еще приемлемо так, что оставлю пока так как работает, т.е первый вариант.... Еще много чего по мимо нормалей делать.....

Lastjedi
А перед
Код
MeshNormalSpec* meshNorm = mtri->mesh.GetSpecifiedNormals();
есть строчка
Код
mtri->mesh.SpecifyNormals ();
?
В этой части скрипт не отличается от предыдущего.
Очень советую все-таки заменить код... Он реально быстрее, да и вообще правильнее, если нужно задать нормали сразу для всей сетки.
Pancir
CODE
mtri->mesh.SpecifyNormals ();

Не было )) щас поставил словил крешь, значит заработало..... а крешь скорее все всего из-за не правильного подсчета количества нормалей..... там конечно новый алгоритм для нормалей на этот кусок кода нужен...... поэкспериментирую....

Сейчас застопорился на новой проблеме, не могу параметры с point хелпера зацепить, уже ~8 часов рою хелп и исходники, видать опыта не хватает все таки ( или опять там автостолы начудили.... ибо по стандартным объектам все понятно, и даже есть пример на даммик, но вот с поинтом косяк у меня... нужно ему задать параметры, ну там размер и т.д

CODE
bool ImportNode::CreateMainPoint (vector<pair<string, string>>    mainProp,
                                  vector<string>                tertDef,
                                  vector<string>                objtDef,
                                  vector<string>                polyDef,
                                  vector<string>                netwDef)
{ //Create Point (base object for DSF)

    HelperObject *pobj = (HelperObject*)this->iP->CreateInstance(HELPER_CLASS_ID, Class_ID(POINTHELP_CLASS_ID,0));
    if (!pobj) return false;

    IParamArray *pointParam = pobj->GetParamBlock();
    pointParam->SetValue(pointobj_size, TimeValue(0), 100,0f);


    INode *pnode = this->iP->CreateObjectNode(pobj);
    if (!pnode) return false;

    // Write Properties of DSF to ObjPoint Properties....
    this->SetDefToObj(mainProp, "PROP_", pnode);
    // Write TerrainDef of DSF to ObjPoint Properties....
    this->SetDefToObj(tertDef, "TERT_", pnode);
    // Write ObjectDef of DSF to ObjPoint Properties....
    this->SetDefToObj(objtDef, "OBJT_", pnode);
    // Write PolygonDef of DSF to ObjPoint Properties....
    this->SetDefToObj(polyDef, "POLY_", pnode);
    // Write NetworkDef of DSF to ObjPoint Properties....
    this->SetDefToObj(netwDef, "NETW_", pnode);
    // Save this node in class for child link
    this->mainNode = pnode;

    TSTR tempTstr;
    // Set MAIN name "MAIN_33/55"
    tempTstr = NAME_PREFIX;
    tempTstr += "MAIN_";
    tempTstr += TSTR(mainProp.at(0).second.c_str()); //Lon start
    tempTstr += "/";
    tempTstr += TSTR(mainProp.at(3).second.c_str()); //Lat start
    SetNodeName (tempTstr);

    pnode->SetWireColor(this->PointWireColor);
    pnode->SetNodeTM(0,this->tm);
    //this->iP->MakeNameUnique(this->NodeName);
    pnode->SetName(this->NodeName);
        this->iP->RedrawViews(this->iP->GetTime());
    return true;
}


на SetValue получаю крешь
pointobj_size это енум есть, там остальные параметры тоже прописаны, этот 0.
Point вообще какой то заколдованный в максе )) я еще помню с ним словил проблемы в другом плагине, там правда все проще было, надо было всего лишь его класс узнать (в хелпе его не было )) через скрипт узнавал по наводки VG) smile.gif
OnePride
Моя функция для тестового вывода точек, матрица - это трансформация нода, в системе координат которого ставим точку. Единичная матрица для мировой системы координат.

Код
void ShowPoint (Point3 *p, Matrix3 m_base, float size){
    static Interface *ip = GetCOREInterface();
    static TimeValue t;
    static DWORD clr = Color(1.0f,215/255.0f,0.0f).toRGB();
    t = ip->GetTime();
    Object *obj = (Object*)ip->CreateInstance(HELPER_CLASS_ID, Class_ID(POINTHELP_CLASS_ID,0));
    obj->GetParamBlockByID(pointobj_params)->SetValue(pointobj_size, t, size);
    INode *node = ip->CreateObjectNode(obj);
    node->SetWireColor(clr);
    
    Matrix3 m = node->GetNodeTM(ip->GetTime());    
    m.SetTranslate(*p);
    m *= m_base;
    node->SetNodeTM(t,m);
    return;
}
Pancir
OnePride
Пасибки эта строчка меня спасла ))
Чувствовал, что надо в сторону ID копать
Только не понимаю в чем у меня проблема с поиском решений? хелпом пользоваться не умею? опыта не хватает? Просто действительно долго искал решение, а например это pointobj_params мне вообще нигде не попалось... (вопрос полу риторический smile.gif)

CODE
pobj->GetParamBlockByID(pointobj_params)->SetValue(pointobj_size, TimeValue(0), 2000.0f);
OnePride
Если ты уже знал название параметра, то можно было прогуглить папку сдк по слову *pointobj_size* и посмотреть где и как идет обращение к нему)
Pancir
ну да, это уже ближе к проблеме с опытом )))
Как раз хотел узнать как можно искать в целой папке по txt, cpp и h внутренностям?smile.gif
OnePride
TotalCommander - Alt-F7 указываешь маску файла, и указываешь ниже маску что искать, да и в винде собсна можно, поидее, тоже искать по содержимому файла
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.