Практика формирования видеоряда напрямую из 3D программ, созданных на Unity/Unreal/OpenSceneGraph для создания 3D-обучающих видеофильмов показала высокую эффективность такого подхода. Качество синтезируемой модели часто практически не уступает по фотореалистичности видео, созданному “классически”, т.е. традиционным рендерингом из программ 3dMax/Maya/Cinema и т.д.




При этом имеется возможность управления камерой в режиме реального времени, используя стандартные средства ввода-вывода / клавиатура-мышь. Для выполнения простых пролетов камеры, например по орбите с равномерным приближением или отдалением такой подход является достаточным и не требует каких либо дополнительных устройств управления. Однако при сложных движениях камеры требуется контролировать большее количество параметров движения и как следствие использование стандартных средств ввода-вывода становится или неудобным или недостаточным. VR также не всегда применим, особенно при больших размерах объекта и/или при быстрых перемещениях камеры.
На основе нашего опыта создания видеоряда из 3D программ было принято решение создать пульт управления виртуальной камерой, для эффективного управления движениями камеры, управлением масштабов времени и реализацией управления сценарием происходящего в 3D.
В качестве базы было выбрано оборудование, имеющееся “в запасе”, а именно:

Arduino Due — плата микроконтроллера на базе процессора Atmel SAM3X8E ARM Cortex-M3 (описание). Это первая плата Arduino на основе 32-битного микроконтроллера с ARM ядром. На ней имеется 54 цифровых вход/выхода (из них 12 можно задействовать под выходы ШИМ), 12 аналоговых входов, 4 UARTа (аппаратных последовательных порта), a генератор тактовой частоты 84 МГц, связь по USB с поддержкой OTG, 2 ЦАП (цифро-аналоговых преобразователя), 2 TWI, разъем питания, разъем SPI, разъем JTAG. Частота процессора (CPU) 84 МГц. 96 КБ ОЗУ. 512 КБ флеш-памяти для хранения программ. контроллер DMA, который разгружает центральный процессор от вып��лнения интенсивных операций с памятью.
Да, немного перебор, но она была под рукой.
TFT-дисплей на базе ILI9341 с тачскрином (320*240 65к цветов)

Энкодер с кнопкой, переменные резисторы, два модуля джойстиков, переключатели и кнопки с фиксацией и без фксации.
Фото устройства в процессе монтажа в корпусе.

Код написан в Arduino IDE, с использованием библиотек:
include “SPI.h”
include “Adafruit_GFX.h”
include “Adafruit_ILI9341.h”
include “Joystick.h”
Код программы приведен в конце статьи, а пока результат:



Внутренности после монтажа (клавиши еще не смонтированы)

Вот так операционная система определяет устройство (можно поменять конечно)

Ну и собственно тестирование.
Исходный код программы:
#include "SPI.h" #include "Adafruit_GFX.h" #include "Adafruit_ILI9341.h" #include "Joystick.h" #include <EncButton2.h> Joystick_ Joystick; /* Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_MULTI_AXIS, 32, 0, true, true, false, false, false, false, true, true, false, false, false); */ const int analogInPin1 = A0; const int analogInPin2 = A1; const int analogInPin3 = A2; const int analogInPin4 = A3; const int analogInPin5 = A4; const int analogInPin6 = A5; const int analogInPin7 = A6; // For the Adafruit shield, these are the default. #define TFT_RST 8 #define TFT_DC 9 #define TFT_CS 10 #define TFT_MISO 50 #define TFT_MOSI 51 #define TFT_SCK 52 // Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC //Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); // If using the breakout, change pins as desired Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCK, TFT_RST, TFT_MISO); EncButton2<EB_ENC> enc(INPUT, 45, 43); // просто энкодер // the setup function runs once when you press reset or power the board void setup() { //Serial.begin(9600); // Set Range Values Joystick.setXAxisRange(-127, 127); Joystick.setYAxisRange(-127, 127); Joystick.setZAxisRange(0, 255); Joystick.setRxAxisRange(255, 0); Joystick.setRyAxisRange(0, 255); Joystick.setRzAxisRange(255, 0); Joystick.setThrottleRange(0, 255); Joystick.setRudderRange(0, 255); Joystick.setAcceleratorRange(0, 255); Joystick.setBrakeRange(0, 255); Joystick.setSteeringRange(0, 255); Joystick.begin(false); pinMode(A0, INPUT_PULLUP); pinMode(A1, INPUT_PULLUP); pinMode(A2, INPUT_PULLUP); pinMode(A3, INPUT_PULLUP); pinMode(A4, INPUT_PULLUP); pinMode(A5, INPUT_PULLUP); pinMode(A6, INPUT_PULLUP); pinMode(A7, INPUT_PULLUP); pinMode(1, INPUT_PULLUP); pinMode(2, INPUT_PULLUP); pinMode(3, INPUT_PULLUP); pinMode(4, INPUT_PULLUP); pinMode(5, INPUT_PULLUP); //pinMode(13, OUTPUT); pinMode(LED_BUILTIN, OUTPUT); pinMode(47, INPUT); //butt0 encoder pinMode(45, INPUT); //encoder1 pinMode(43, INPUT); //encoder2 pinMode(38, INPUT); //butt1 pinMode(40, INPUT); //butt2 tft.begin(); // read diagnostics (optional but can help debug problems) uint8_t x = tft.readcommand8(ILI9341_RDMODE); //Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX); x = tft.readcommand8(ILI9341_RDMADCTL); //Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX); x = tft.readcommand8(ILI9341_RDPIXFMT); // Serial.print("Pixel Format: 0x"); Serial.println(x, HEX); x = tft.readcommand8(ILI9341_RDIMGFMT); // Serial.print("Image Format: 0x"); Serial.println(x, HEX); x = tft.readcommand8(ILI9341_RDSELFDIAG); // Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX); tft.setRotation(0); //0 1 2 3 tft.fillScreen(ILI9341_BLACK); //unsigned long start = micros(); tft.setCursor(0, 0); tft.setTextColor(ILI9341_WHITE); tft.setTextSize(2); tft.println("Lcontent.ru"); tft.setTextColor(ILI9341_BLUE); tft.println("Joy module v.1.0"); tft.setTextColor(ILI9341_RED); tft.println("by Maxim Gammer"); } int OLD_sensorValue1 = 0; int encoderValue=0; // the loop function runs over and over again forever void loop() { int sensorValue1 = 0; int outputValue1 = 0; int sensorValue2 = 0; int outputValue2 = 0; int sensorValue3 = 0; int outputValue3 = 0; int sensorValue4 = 0; int outputValue4 = 0; int sensorValue5 = 0; int outputValue5 = 0; int sensorValue6 = 0; int outputValue6 = 0; int sensorValue7 = 0; int outputValue7 = 0; sensorValue1 = analogRead(analogInPin1); sensorValue2 = analogRead(analogInPin2); sensorValue3 = analogRead(analogInPin3); sensorValue4 = analogRead(analogInPin4); sensorValue5 = analogRead(analogInPin5); sensorValue6 = analogRead(analogInPin6); sensorValue7 = analogRead(analogInPin7); // map it to the range of the analog out: outputValue1 = map(sensorValue1, 0, 1023, 0, 255); outputValue2 = map(sensorValue2, 0, 1023, 0, 255); outputValue3 = map(sensorValue3, 0, 1023, 0, 255); outputValue4 = map(sensorValue4, 0, 1023, 0, 255); outputValue5 = map(sensorValue5, 0, 1023, 0, 255); outputValue6 = map(sensorValue6, 0, 1023, 0, 255); outputValue7 = map(sensorValue7, 0, 1023, 0, 255); Joystick.setYAxis(outputValue1 - 128); Joystick.setXAxis(outputValue2 - 128); Joystick.setRxAxis(outputValue3); Joystick.setRyAxis(outputValue4); Joystick.setZAxis(outputValue5); Joystick.setRzAxis(outputValue6); Joystick.setThrottle(outputValue7); //Joystick.setRudder(255); Joystick.setRudder(255); Joystick.setAccelerator(255); Joystick.setBrake(255); Joystick.setSteering(255); int buttonState0 = digitalRead(47); Joystick.setButton(0, buttonState0); int buttonState1 = digitalRead(38); Joystick.setButton(1, buttonState1); int buttonState2 = digitalRead(40); Joystick.setButton(2, buttonState2); enc.tick(); // опрос происходит здесь if (enc.left()) { encoderValue = encoderValue+45; } if (enc.right()) { encoderValue = encoderValue-45; } if (encoderValue<=-45) { encoderValue=315; } else if (encoderValue>=360) { encoderValue=0; } int hatSwitch =0; Joystick.setHatSwitch(hatSwitch, -1); Joystick.setHatSwitch(hatSwitch, encoderValue); //0 45 90 135 180 225 270 315 Joystick.sendState(); //Serial.print("sensor = "); //Serial.println(sensorValue); /* char TX[20]; //tft.fillRect(0, 0, 40, 10, ILI9341_BLACK); // textbgcolor is protected in Adafruit_GFX.h tft.setTextSize(1); tft.setCursor(0, 0); tft.setTextColor(ILI9341_BLACK); sprintf(TX,"%4d", OLD_sensorValue1); tft.println(TX); OLD_sensorValue1 = sensorValue1; tft.setCursor(0, 0); tft.setTextColor(ILI9341_WHITE); sprintf(TX,"%4d", sensorValue1); tft.println(TX); //"Hello World!" delay(2); */ //digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level) //delay(1000); // wait for a second //digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW //delay(1000); // wait for a second }
