понедельник, 14 декабря 2015 г.

Примитивы и скриптинг: что уже можно

Primitives, boolean operations, 3D-Coat, AngelScript
Добавил базовый набор примитивов: теперь в 3D-Coat их можно создавать в скриптах. Плюс, с ними уже можно кое-что делать: менять позицию на экране, масштабировать. Это немного, но заложена основа, а новый подход к скриптингу легко масштабируется и, надеюсь, проще для освоения (старые возможности - остались: написанные ранее скрипты будут работать). В версии 4.5.26 и выше это новое уже будет.

Код:
// глобальные переменные позволяют нам не заморачиваться
// с передачей параметров в методы, сделав т.о. код короче
const Vec3  TOWER_SHIFT( 0, 0, 200 );
const Vec3  FLOOR_SHIFT( 0, 200, 0 );
Vec3  tower = TOWER_SHIFT * (-4.5);
Vec3  floor( 0 );
Mesh  a, b, mesh;
// с помощью `builder` создаём разные меши
Builder  builder;
// используем `room` для формирования сцены
SculptRoom  room;


void main() {

    // подготавливаем сцену
    room.clear().toSurface();

    // капсула
    {
        // первый меш
        a = builder.capsule()
          // подготавливаем к строительству
          .startPosition( Vec3( 0 ) )
          .endPosition( Vec3( 40, 50, 60 ) )
          .startRadius( 30 )
          .endRadius( 50 )
          // плотность сетки
          .details( 0.1 )
          // строим
          .build();
        // второй меш
        b = builder.capsule()
          .startPosition( Vec3( 0 ) )
          .endPosition( Vec3( 20, 30, 40 ) )
          .startRadius( 20 )
          .endRadius( 30 )
          .position( Vec3( 20, 30, 40 ) )
          .details( 0.5 )
          .build();
        // рисуем меши `a` и `b`
        // см. реализацию draw() в конце листинга
        draw();
    }

    // конус
    {
        a = builder.cone()
          .radius( 50 )
          .height( 120 )
          .details( 0.1 )
          .build();
        b = builder.cone()
          .radius( 40 )
          .height( 80 )
          .position( Vec3( 10, 20, 30 ) )
          .details( 0.5 )
          .build();
        draw();
    }

    // кубоид
    {
        a = builder.cuboid()
          .side( Vec3( 100, 80, 60 ) )
          .details( 0.1 )
          .build();
        b = builder.cuboid()
          .side( Vec3( 30, 50, 70 ) )
          .position( Vec3( 20, 30, 40 ) )
          .details( 0.5 )
          .build();
        draw();
    }

    // цилиндр
    {
        a = builder.cylinder()
          .positionTop( Vec3( 80, 0, 0 ) )
          .positionBottom( Vec3( 0, 0, 0 ) )
          .radiusTop( 40 )
          .radiusBottom( 50 )
          .details( 0.1 )
          .build();
        b = builder.cylinder()
          .positionTop( Vec3( 70, 0, 10 ) )
          .positionBottom( Vec3( 0, 0, 0 ) )
          .radiusTop( 20 )
          .radiusBottom( 30 )
          .position( Vec3( 20, 30, 40 ) )
          .details( 0.5 )
          .build();
        draw();
    }

    // эллипсоид
    {
        a = builder.ellipsoid()
          .radius( Vec3( 80, 60, 40 ) )
          .details( 0.1 )
          .build();
        b = builder.ellipsoid()
          .radius( Vec3( 20, 40, 60 ) )
          .position( Vec3( 20, 30, 40 ) )
          .details( 0.5 )
          .build();
        draw();
    }

    // шестерёнка
    {
        a = builder.gear()
          .startPoint( Vec3( 0, 0, 0 ) )
          .endPoint( Vec3( 90, 90, 90 ) )
          .topRadius( 30 )
          .bottomRadius( 50 )
          .relativeHoleRadius( 0.3 )
          .depth( 0.5 )
          .sharpness( 0.2 )
          .teeth( 3 )
          .details( 0.1 )
          .build();
        b = builder.gear()
          .startPoint( Vec3( 20, 20, 20 ) )
          .endPoint( Vec3( 50, 50, 50 ) )
          .topRadius( 50 )
          .bottomRadius( 50 )
          .relativeHoleRadius( 0.3 )
          .depth( 0.2 )
          .sharpness( 1.0 )
          .teeth( 6 )
          .details( 0.5 )
          .build();
        draw();
    }

    // энгон
    {
        a = builder.ngon()
          .startPoint( Vec3( 0, 0, 0 ) )
          .endPoint( Vec3( 90, 90, 90 ) )
          .topRadius( 30 )
          .bottomRadius( 40 )
          .relativeHoleRadius( 0.3 )
          .teeth( 3 )
          .details( 0.1 )
          .build();
        b = builder.ngon()
          .startPoint( Vec3( 20, 20, 20 ) )
          .endPoint( Vec3( 50, 50, 50 ) )
          .topRadius( 50 )
          .bottomRadius( 50 )
          .relativeHoleRadius( 0.2 )
          .teeth( 6 )
          .details( 0.5 )
          .build();
        draw();
    }

    // труба
    {
        a = builder.tube()
          .startPoint( Vec3( 0, 0, 0 ) )
          .endPoint( Vec3( 30, 50, 70 ) )
          .topRadius( 30 )
          .bottomRadius( 40 )
          .relativeHoleRadius( 0.8 )
          .topScale( 2.0 )
          .bottomScale( 1.0 )
          .details( 0.1 )
          .build();
        b = builder.tube()
          .startPoint( Vec3( 10, 20, 30 ) )
          .endPoint( Vec3( 20, 40, 60 ) )
          .topRadius( 20 )
          .bottomRadius( 20 )
          .relativeHoleRadius( 0.2 )
          .topScale( 1.5 )
          .bottomScale( 3.0 )
          .details( 0.5 )
          .build();
        draw();
    }

    // сфера
    {
        a = builder.sphere()
          .radius( 70 )
          .details( 0.1 )
          .build();
        b = builder.sphere()
          .radius( 40 )
          .position( Vec3( 30, 40, 50 ) )
          .details( 0.5 )
          .build();
        draw();
    }
}




// выполняет булевы операции над мешами `a` и `b`
// и добавляет результат на сцену
void draw() {

    floor = Vec3( 0 );
    // объединение (add)
    mesh = a | b;
    mesh.tools().transform().position( tower + floor ).run();
    room += mesh;

    floor += FLOOR_SHIFT;
    // вычитание (subtract)
    mesh = a - b;
    mesh.tools().transform().position( tower + floor ).run();
    room += mesh;

    floor += FLOOR_SHIFT;
    // пересечение (intersect)
    mesh = a & b;
    mesh.tools().transform().position( tower + floor ).run();
    room += mesh;

    tower += TOWER_SHIFT;
}

Запустив скрипт в 3D-Coat, получаем такую картинку:


Обратите внимание на плотность сетки: она у фигур разная и сохраняется после булевых операций.

Код можно сократить, зная, что методы `MeshX::build()` и `ToolsX::run()` могут выступать функторами. Т.е. можем писать:
        ...
        a = builder.sphere()
          .radius( 70 )
          .details( 0.1 )
          ();
        ...
и
        ...
        mesh.tools().transform().position( tower + floor )();
        ...
с тем же результатом.

Комментариев нет: