Zusammenfassung
Sechs Künstler wurden eingeladen, in VR zu malen, zu gestalten und zu formen. Dies ist die wie wir ihre Sitzungen aufzeichnen, die Daten umwandeln und in Echtzeit mit Webbrowsern.
https://g.co/VirtualArtSessions
Was für eine Zeit zum Leben! Mit der Einführung von Virtual Reality werden neue und unerforschte Möglichkeiten entdeckt. Tilt Brush Mit dem auf HTC Vive verfügbaren Google-Produkt können Sie drei räumlichen Raum ein. Als wir Tilt Brush zum ersten Mal ausprobieren, Zeichnung mit Controllern mit Bewegungsverfolgung, die mit dem Vorhandensein eines Raum mit Superkräften“ Sie bleiben bestehen; gibt es wirklich kein Erlebnis, wie die Möglichkeit, in den leeren Raum um Sie herum zu zeichnen.
Das Data Arts-Team bei Google stand vor der Herausforderung, im Web, wo Tilt Brush nicht unterstützt. die noch nicht funktionieren. Zu diesem Zweck holte das Team einen Bildhauer, einen Illustrator, Konzeptdesigner, Modekünstlerin, Installationskünstlerin und Straßenkünstlerin um in diesem neuen Medium Kunstwerke in ihrem eigenen Stil zu kreieren.
Zeichnungen in Virtual Reality aufzeichnen
Die in Unity integrierte Tilt Brush-Software ist eine Desktop-Anwendung,
nutzt VR im Raummaß, um deine Kopfposition zu erfassen (Head-Moded Display oder HMD)
und die Controller in beiden Händen. Das in Tilt Brush erstellte Kunstwerk stammt von
standardmäßig als .tilt
-Datei exportiert. Um diese Erfahrung im Web zu ermöglichen,
erkannte, dass wir mehr als nur
Artwork-Daten benötigen. Wir haben eng mit der
Das Tilt Brush-Team kann Tilt Brush so ändern, dass auch Rückgängig- und Löschvorgänge exportiert werden.
Kopf und Hand des Künstlers 90 Mal pro Sekunde positioniert.
Beim Zeichnen nimmt Tilt Brush die Position und den Winkel des Controllers ein und konvertiert zu einem „Stroke“ (Strich) zu machen. Ein Beispiel hier. Wir haben Plug-ins geschrieben, die diese Striche extrahiert und als Rohdaten im JSON-Format ausgegeben werden.
{
"metadata": {
"BrushIndex": [
"d229d335-c334-495a-a801-660ac8a87360"
]
},
"actions": [
{
"type": "STROKE",
"time": 12854,
"data": {
"id": 0,
"brush": 0,
"b_size": 0.081906750798225,
"color": [
0.69848710298538,
0.39136275649071,
0.211316883564
],
"points": [
[
{
"t": 12854,
"p": 0.25791856646538,
"pos": [
[
1.9832634925842,
17.915264129639,
8.6014995574951
],
[
-0.32014992833138,
0.82291424274445,
-0.41208130121231,
-0.22473378479481
]
]
}, ...many more points
]
]
}
}, ... many more actions
]
}
Das obige Snippet umreißt das Format des JSON-Formats zum Skizzieren.
Hier wird jeder Strich als Aktion mit dem Typ „STROKE“ gespeichert. Zusätzlich zu Wir wollten zeigen, dass ein Künstler Fehler macht und seine mitten in der Skizze. Daher war es wichtig, „DELETE“ zu speichern, Aktionen, die als Aktionen für den gesamten Strich rückgängig machen.
Für jede Kontur werden grundlegende Informationen gespeichert, also Pinselart, Pinselgröße, Farbe "RGB".
Schließlich wird jeder Scheitelpunkt des Strichs
herausgespeichert, einschließlich der Position,
Winkel, Zeit und die Druckstärke des Controllers (angegeben als p
)
an jedem Punkt).
Beachten Sie, dass die Rotation eine 4-Komponenten-Quaternion ist. Das ist später wichtig, rendern wir die Striche heraus, um eine kardanische Sperre zu vermeiden.
Skizzen mit WebGL wiedergeben
Um die Skizzen in einem Webbrowser anzuzeigen, haben wir THREE.js geschrieben und Geometriegenerierungscode geschrieben, der was Tilt Brush unter der Haube macht.
Tilt Brush erstellt in Echtzeit auf Grundlage der Hand des Nutzers Dreiecke. Bewegung ist, ist die gesamte Skizze bereits "fertig". bis zu dem Zeitpunkt, zu dem wir sie im Web. Dadurch können wir einen Großteil der Echtzeitberechnung umgehen die Geometrie beim Laden.
Jedes Paar von Eckpunkten in einem Strich ergibt einen Richtungsvektor (die blauen Linien).
Verbinden der einzelnen Punkte wie oben gezeigt (moveVector
im Code-Snippet unten).
Jeder Punkt enthält auch eine Ausrichtung, eine Quaternion, die für die
Winkel des Controllers anzeigen. Um einen dreieckigen Streifen zu erzeugen, iterieren wir über die einzelnen
Diese Punkte erzeugen Normalen, die senkrecht zur Richtung verlaufen
Ausrichtung des Controllers.
Die Berechnung des Dreiecksstreifens für die einzelnen Striche ist nahezu identisch zum Code in Tilt Brush hinzufügen:
const V_UP = new THREE.Vector3( 0, 1, 0 );
const V_FORWARD = new THREE.Vector3( 0, 0, 1 );
function computeSurfaceFrame( previousRight, moveVector, orientation ){
const pointerF = V_FORWARD.clone().applyQuaternion( orientation );
const pointerU = V_UP.clone().applyQuaternion( orientation );
const crossF = pointerF.clone().cross( moveVector );
const crossU = pointerU.clone().cross( moveVector );
const right1 = inDirectionOf( previousRight, crossF );
const right2 = inDirectionOf( previousRight, crossU );
right2.multiplyScalar( Math.abs( pointerF.dot( moveVector ) ) );
const newRight = ( right1.clone().add( right2 ) ).normalize();
const normal = moveVector.clone().cross( newRight );
return { newRight, normal };
}
function inDirectionOf( desired, v ){
return v.dot( desired ) >= 0 ? v.clone() : v.clone().multiplyScalar(-1);
}
Wenn die Strichrichtung und -ausrichtung kombiniert werden, mathematisch mehrdeutige Ergebnisse; mehrere Normalen abgeleitet werden, führt oft zu einer „Drehung“ in der Geometrie.
Bei der Iteration über die Punkte eines Strichs behalten wir ein „bevorzugtes Recht“ bei
Vektor hinzu und übergeben Sie dies an die Funktion computeSurfaceFrame()
. Diese Funktion
gibt uns eine Normalität, aus der wir ein Quad im Quad-Streifen ableiten können, basierend auf
die Strichrichtung (vom letzten Punkt zum aktuellen Punkt)
Ausrichtung des Controllers (eine Quaternion). Noch wichtiger ist, dass Sie auch
ein neues „Rechtswunsch“ Vektoren für den nächsten
Berechnungssatz an.
Nach der Erzeugung von Quadraten basierend auf den Kontrollpunkten der einzelnen Striche zusammenfassen wir durch Interpolieren ihrer Ecken von einem Quad zum nächsten.
function fuseQuads( lastVerts, nextVerts) {
const vTopPos = lastVerts[1].clone().add( nextVerts[0] ).multiplyScalar( 0.5
);
const vBottomPos = lastVerts[5].clone().add( nextVerts[2] ).multiplyScalar(
0.5 );
lastVerts[1].copy( vTopPos );
lastVerts[4].copy( vTopPos );
lastVerts[5].copy( vBottomPos );
nextVerts[0].copy( vTopPos );
nextVerts[2].copy( vBottomPos );
nextVerts[3].copy( vBottomPos );
}
Jedes Quad enthält außerdem UVs, die im nächsten Schritt generiert werden. Einige Pinsel verschiedene Strichmuster enthalten, um den Eindruck zu erwecken, fühlte sich wie ein anderer Pinsel an. Dies geschieht mithilfe von _Texturatlasierung, _wobei jede Pinseltextur alle möglichen verschiedene Varianten. Die richtige Textur wird ausgewählt, indem die UV-Werte des Schlaganfall.
function updateUVsForSegment( quadVerts, quadUVs, quadLengths, useAtlas,
atlasIndex ) {
let fYStart = 0.0;
let fYEnd = 1.0;
if( useAtlas ){
const fYWidth = 1.0 / TEXTURES_IN_ATLAS;
fYStart = fYWidth * atlasIndex;
fYEnd = fYWidth * (atlasIndex + 1.0);
}
//get length of current segment
const totalLength = quadLengths.reduce( function( total, length ){
return total + length;
}, 0 );
//then, run back through the last segment and update our UVs
let currentLength = 0.0;
quadUVs.forEach( function( uvs, index ){
const segmentLength = quadLengths[ index ];
const fXStart = currentLength / totalLength;
const fXEnd = ( currentLength + segmentLength ) / totalLength;
currentLength += segmentLength;
uvs[ 0 ].set( fXStart, fYStart );
uvs[ 1 ].set( fXEnd, fYStart );
uvs[ 2 ].set( fXStart, fYEnd );
uvs[ 3 ].set( fXStart, fYEnd );
uvs[ 4 ].set( fXEnd, fYStart );
uvs[ 5 ].set( fXEnd, fYEnd );
});
}
Da jede Skizze eine unbegrenzte Anzahl von Strichen hat und die Striche nicht wird die Strichgeometrie im Voraus berechnet und zusammengeführt. in einem einzigen Mesh-Netzwerk zusammengeführt. Auch wenn jeder neue Pinseltyp ein eigener Pinseltyp sein muss, Das reduziert die Anzahl der Aufrufe auf einen Aufruf pro Pinsel.
<ph type="x-smartling-placeholder">Um das System zu testen, erstellten wir eine Skizze, die 20 Minuten dauerte. mit so vielen Scheitelpunkten wie möglich. Die erstellte Skizze wurde immer noch 60fps in WebGL.
Da alle ursprünglichen Eckpunkte eines Strichs auch Zeit enthielten, können wir Daten problemlos wiedergeben können. Die Neuberechnung der Striche pro Frame langsam ist. Stattdessen haben wir die gesamte Skizze beim Laden im Voraus berechnet jedes Quad zu sehen, wenn es Zeit war, dies zu tun.
Ein Quadrat zu verbergen bedeutete einfach, die Eckpunkte auf 0,0,0 Punkt zu reduzieren. Wenn der Parameter Zeit erreicht ist, an der das Quad freigelegt werden soll, um die Eckpunkte wieder an ihrer Position zu setzen.
Ein Bereich für Verbesserungen besteht darin, die Eckpunkte vollständig auf der GPU mit Shader. Bei der aktuellen Implementierung werden sie in einer Schleife durch den Scheitelpunkt platziert. Array aus dem aktuellen Zeitstempel, mit dem geprüft wird, welche Eckpunkte angezeigt werden müssen und anschließend die Geometrie aktualisieren. Dies belastet die CPU stark, was dazu führt, Der Lüfter dreht sich und verschwendet die Akkulaufzeit.
Künstler aufnehmen
Wir waren der Meinung, dass die Skizzen selbst nicht ausreichen würden. Wir möchten Ihnen zeigen, Künstler in ihre Skizzen einzubauen und jeden Pinselstrich zu malen.
Für Aufnahmen der Künstler haben wir Microsoft Kinect-Kameras verwendet, um die Tiefe aufzuzeichnen. Daten der Künstler Körper im Weltraum. So können wir zeigen, dreidimensionale Figuren im selben Raum erscheinen, in dem die Zeichnungen erscheinen.
Da der Körper des Künstlers sich verdecken würde, sodass wir nicht sehen können, im Hintergrund nutzten wir ein Doppel-Kinect-System, in die Mitte zeigen.
Zusätzlich zu den Tiefeninformationen haben wir auch die Farbinformationen der mit Standard-Spiegelreflexkameras. Wir haben die hervorragende DepthKit-Software zum Kalibrieren und Zusammenführen der Tiefenkamera und der Farbkameras ansehen. The Kinect kann mit digitalen Spiegelreflexkameras. Wir haben uns jedoch für DSLRs entschieden, Belichtungseinstellungen, hochwertige High-End-Objektive und HD-Aufnahmen.
Für die Aufnahme der Aufnahmen bauten wir einen speziellen Raum für das HTC Vive, den Künstler und die Kamera. Alle Oberflächen waren mit Material bedeckt, das Infrarot absorbiert. um eine sauberere Punktwolke zu erhalten (Einlageneinzüge an den Wänden, mattiert auf dem Boden. Für den Fall, dass das Material in der Punktwolke auftaucht Wir wählten schwarzes Material, damit es nicht so ablenkend wäre wie etwas der weiß war.
Die resultierenden Videoaufzeichnungen gaben uns genügend Informationen, um ein Partikel zu projizieren System. Einige zusätzliche Tools haben wir openFrameworks zur weiteren Bereinigung des Filmmaterials, besonders beim Entfernen von Böden, Wänden und Decken.
<ph type="x-smartling-placeholder">Wir wollten nicht nur den Künstlern zeigen, sondern auch HMD und die und Controller in 3D ansehen. Das war nicht nur wichtig, um das HMD in deutlich zu machen (die Reflexionsgläser von HTC Vive waren abgeworfen) IR-Messungen von Kinect), gab es uns Ansprechpartner für die Fehlerbehebung des Partikels. und die Videos an der Skizze angleichen.
<ph type="x-smartling-placeholder">Dazu wurde ein benutzerdefiniertes Plug-in in Tilt Brush geschrieben, das die die Position des HMD und der Steuerungen. Da Tilt Brush mit 90 fps läuft, Tonnen Daten gestreamt und die Eingabedaten einer Skizze waren größer als 20 MB unkomprimiert. Wir haben diese Technik auch verwendet, um Ereignisse zu erfassen, die nicht aufgezeichnet werden. in der typischen Tilt Brush-Datei, z. B. wenn der Künstler eine Option im Steuerfeld „Tools“ und die Position des Spiegel-Widgets.
Bei der Verarbeitung der 4 TB an Daten, die wir erfasst hatten, war eine der größten Herausforderungen alle visuellen/Datenquellen miteinander abzustimmen. Jedes Video einer digitalen Spiegelreflexkamera müssen am entsprechenden Kinect ausgerichtet werden, sodass die Pixel als auch für die Zeit. Dann mussten die Aufnahmen dieser beiden Kamerastative zu einem einzigen Künstler zusammenschließen. Dann mussten wir unsere 3D-Animation Künstler mit den Daten ihrer Zeichnung. Geschafft! Wir haben browserbasierte die Ihnen bei den meisten dieser Aufgaben helfen. Sie können sie auch selbst ausprobieren. hier
Nachdem die Daten ausgerichtet waren, haben wir sie mit einigen in NodeJS geschriebenen Skripts verarbeitet. und eine Videodatei sowie eine Reihe von JSON-Dateien ausgeben, die alle geschnitten und synchronisiert. Wir haben drei Maßnahmen ergriffen, um die Dateigröße zu verringern. Zunächst haben wir die Genauigkeit jeder Gleitkommazahl, sodass sie höchstens 3 beträgt Genauigkeit von Dezimalstellen. Zweitens reduzieren wir die Anzahl der Punkte um ein Drittel, 30 fps erreicht und die Positionen clientseitig interpoliert hat. Schließlich haben wir die sodass statt der einfachen JSON-Datei mit Schlüssel/Wert-Paaren eine Wertereihenfolge die für die Position und Drehung des HMD und der Controller erstellt wurden. Dadurch wird die Datei ausgeschnitten. 3 MB groß, was für die Übertragung akzeptabel ist.
Da das Video selbst als HTML5-Videoelement ausgeliefert wird, das von einem Aus WebGL-Texturen werden Partikel. Das Video selbst musste verborgen im Hintergrund. Ein Shader wandelt die Farben in den Tiefenbildern in Positionen in 3D-Raum James George hat ein tolles Beispiel verraten. wie Sie Videomaterial direkt aus DepthKit nutzen können.
Auf iOS-Geräten gibt es Einschränkungen für die Inline-Wiedergabe von Videos. Damit soll verhindert werden, Nutzer werden von automatisch wiedergegebenen Webvideoanzeigen nicht gestört. Wir haben eine Technik verwendet, ähnlich wie in anderen Workarounds Web, nämlich zum Kopieren des in einen Canvas umwandeln und die Videosuchzeit manuell aktualisieren (alle 1/30 eine Sekunde.
videoElement.addEventListener( 'timeupdate', function(){
videoCanvas.paintFrame( videoElement );
});
function loopCanvas(){
if( videoElement.readyState === videoElement.HAVE\_ENOUGH\_DATA ){
const time = Date.now();
const elapsed = ( time - lastTime ) / 1000;
if( videoState.playing && elapsed >= ( 1 / 30 ) ){
videoElement.currentTime = videoElement.currentTime + elapsed;
lastTime = time;
}
}
}
frameLoop.add( loopCanvas );
Leider kam es zu einer deutlichen Senkung der iOS-Version Framerate, da das Kopieren des Pixelpuffers vom Video in das Canvas CPU-intensiv. Um dies zu umgehen, haben wir einfach kleinere Versionen dieselben Videos mit mindestens 30 fps auf einem iPhone 6.
Fazit
Der allgemeine Konsens bei der Entwicklung von VR-Software für 2016 besteht darin, Geometrien und Shader einfach, sodass Sie in einem HMD mit mehr als 90 fps laufen können. Dieses erwiesen sich als sehr gutes Ziel für WebGL-Demos, da die verwendeten Techniken in Tilt Brush in WebGL einbinden.
Während Webbrowser, die komplexe 3D-Mesh-Netzwerke anzeigen, nicht interessant sind war dies ein Beweis dafür, dass sich VR und die im Web durchaus möglich.