יצירת 100,000 כוכבים

Michael Chang
Michael Chang

שלום! שמי מייקל צ'אנג ואני עובד עם צוות 'אומנות הנתונים' ב-Google. לאחרונה סיימנו את ההשלמה של 100,000 כוכבים, ניסוי של Chrome שמציג כוכבים קרובים. הפרויקט נבנה באמצעות THREE.js ו-CSS3D. במקרה לדוגמה הזה אתאר את תהליך הגילוי, אשתף כמה טכניקות תכנות ואסיים עם כמה רעיונות לשיפור עתידי.

הנושאים שנדונו כאן יהיו רחבים למדי, וידרשו מידה מסוימת של ידע ב-THREE.js, אם כי אני מקווה שעדיין תוכל ליהנות מהנושא הטכני לאחר-מורטם. אתם יכולים לדלג לאזור שמעניין אתכם באמצעות הלחצן של תוכן העניינים שמשמאל. קודם כל אראה את חלק הרינדור של הפרויקט, ולאחר מכן אראה איך מנהלים את תוכנת ההצללה, ולבסוף אסביר איך להשתמש בתוויות טקסט ב-CSS בשילוב עם WebGL.

100,000 כוכבים, ניסוי של Chrome מאת צוות 'אומנות הנתונים'
הפונקציה 100,000 כוכבים משתמשת ב-THREE.js כדי להציג כוכבים בקרבת מקום בשביל החלב

מגלים את החלל

זמן קצר אחרי שסיימנו את המשחק Small Arms Globe, ניסיתי את הדגמת חלקיקים מסוג THREE.js עם עומק שדה. שמתי לב שאני יכול לשנות את ה "סולם" המפוענח של הסצנה על ידי התאמת כמות האפקט שהוחל. כאשר אפקט עומק השדה היה ממש קיצוני, אובייקטים מרוחקים הפכו למטושטשים ממש בדומה לאופן שבו פועל צילום בעזרת הטיה באמצעות הטיה כדי ליצור אשליה של מבט בסצנה מיקרוסקופית. מצד שני, הפחתת האפקט גרמה לו להיראות כאילו אתה בוהה בחלל העמוק.

התחלתי לחפש נתונים שאפשר להשתמש בהם כדי להחדיר מיקום חלקיקים, נתיב שמוביל אותי למסד הנתונים HYG של astronexus.com, שהוא אוסף של שלושת מקורות הנתונים (Hipparcos, Yale Bright Star Catalog ו-Gliese/Jahreiss Catalog) בליווי קואורדינטות קרטזיות מחושבות מראש של xyz. קדימה, מתחילים!

הצגת נתוני כוכבים.
השלב הראשון הוא להציב כל כוכב בקטלוג כחלקיק אחד.
הכוכבים עם השם.
לחלק מהכוכבים בקטלוג יש שמות עצם פרטיים.

ארכה כשעה כדי לפרוץ למשהו שמיקם את נתוני הכוכבים בחלל התלת-ממדי. במערך הנתונים יש בדיוק 119,617 כוכבים, כך שייצוג של כל כוכב עם חלקיק לא בעייתי במעבד גרפי מודרני. קיימים גם 87 כוכבים שמזוהים באופן אינדיבידואלי, לכן יצרתי שכבת-על של סמן CSS באמצעות אותה טכניקה שתיארתי ב-S Small Arms Globe.

בזמן הזה בדיוק סיימתי את הסדרה Mass Effect (אפקט המוני). במשחק, השחקן מוזמן לחקור את הגלקסיה ולסרוק כוכבי לכת שונים ולקרוא על ההיסטוריה הדמיונית לחלוטין שלהם, שנשמעת כמו ויקיפדיה: אילו מינים שלחו על כדור הארץ, ההיסטוריה הגיאולוגית שלו וכן הלאה.

כשאתם יודעים את שפע הנתונים האמיתיים שקיימים על כוכבים, אפשר להעלות מידע אמיתי על הגלקסיה באותו אופן. המטרה האולטימטיבית של הפרויקט היא להפיח חיים בנתונים האלה, לאפשר לצופה לחקור את הגלקסיה אה לה מס אפקט, ללמוד על כוכבים ועל תפוצתם, ולהעניק השראה לתחושה של ירדה ופלא לגבי החלל. סוף סוף!

כנראה אצטרך להקדים את שאר תיאור המקרה ולומר שאני בהחלט לא אסטרונום, ושמדובר במחקר חובב שנתמך על ידי כמה עצות ממומחים חיצוניים. הפרויקט הזה בהחלט צריך להיות פרשנות של אמן למרחב.

בניית גלקסיה

התוכנית שלי הייתה ליצור באופן פרוצדורלי מודל של הגלקסיה שיוכל להוסיף את נתוני הכוכבים להקשר, ואני מקווה לקבל תמונה מדהימה של המקום שלנו בדרך החלב.

אב-טיפוס מוקדם של הגלקסיה.
אב-טיפוס מוקדם של מערכת החלקיקים של שביל החלב.

כדי ליצור את שביל החלב, השלמתי 100,000 חלקיקים והצבתי אותם בספירלה על ידי הדמיה של הדרך שבה נוצרות זרועות גלקטיות. לא חששתי יותר מדי לגבי הפרטים הספציפיים של מבנה גוף ספירלי, כי זה מודל ייצוגי ולא מודל מתמטי. עם זאת, ניסיתי למצוא את מספר הידיים הספירליות, נכון יותר או פחות, והסתובב בכיוון הנכון.

בגרסאות מאוחרות יותר של מודל שביל החלב, הדגשתי את השימוש בחלקיקים לטובת תמונה מישורית של הגלקסיה שתלווה את החלקיקים, בתקווה שתיתן לה מראה יותר מצולם. התמונה האמיתית היא של הגלקסיה הספירלית NGC 1232 במרחק של כ-70 מיליון שנות אור מאיתנו, לאחר שינוי תמונה שנראית כמו שביל החלב.

מציאת קנה המידה של הגלקסיה.
כל יחידת GL היא שנת אור. במקרה הזה,הכדור הוא ברוחב של 110, 000 שנות אור ומקיפה את מערכת החלקיקים.

בשלב מוקדם החלטתי לייצג יחידת GL אחת, שלמעשה, פיקסל בתלת-ממד, כשנת אור אחת. מוסכמה שלפיה המיקום המאוחד עבור כל התוכן מוצג באופן ויזואלי, ולצערי, בהמשך ציפיתי לבעיות חמורות ברמת הדיוק.

מוסכמה נוספת שהחלטתי הייתה לסובב את כל הסצנה במקום להזיז את המצלמה. זה משהו שעשיתי בכמה פרויקטים אחרים. יתרון אחד הוא שהכול מונח על 'פטיפון' כך שגרירת העכבר שמאלה וימינה תגרום לסובב את האובייקט המדובר, אבל הגדלת התצוגה היא רק עניין של שינוי Camera.position.z.

גם שדה הראייה (או FOV) של המצלמה הוא דינמי. כשמושכים החוצה, שדה הראייה מתרחב ולובש יותר ויותר מהגלקסיה. ההפך נכון כאשר נעים פנימה לכיוון כוכב, שדה הראייה צר. זה מאפשר למצלמה לראות דברים שהם אינסופיים (בהשוואה לגלקסיה) על ידי כיווץ שדה הראייה עד לזכוכית מגדלת דמוית אלוהים, בלי שיהיה צורך להתמודד עם בעיות של חיתוך כמעט מישור.

דרכים שונות לעיבוד גלקסיה.
(למעלה) גלקסיית החלקיקים המוקדמת. (בהמשך) חלקיקים שמלווים במישור תמונה.

מכאן הצלחתי "להציב" את השמש במספר יחידות נפרדות מהליבה הגלקטית. הצלחתי גם להמחיש את הגודל היחסי של מערכת השמש על ידי מיפוי הרדיוס של צוק קויפר (בשלב מסוים בחרתי ליצור תצוגה חזותית של ענן אורט). במודל הזה של מערכת השמש, הצלחתי גם להמחיש מסלול פשוט של כדור הארץ ואת הרדיוס של השמש בפועל.

מערכת השמש.
השמש סובבת סביב כוכבי לכת וכדור שמייצג את חגורת קויפר.

היה קשה לעבד את השמש. נאלצתי לרמות עם כמה שיותר טכניקות גרפיקה בזמן אמת שידעתי. פני השטח של השמש הם קצף חם של פלזמה, והוא צריך להבהב ולהשתנות עם הזמן. מטרת הסימולציה היא באמצעות מרקם של מפת סיביות (bitmap) של תמונה באינפרה-אדום של פני השטח הסולאריים. תוכנת ההצללה (shader) שעל פני השטח יוצרת מראה צבע על סמך גווני האפור של המרקם הזה, ומבצעת בדיקה באמצעות רמפת צבע נפרדת. כאשר בדיקת המידע הזה משתנה עם הזמן, נוצר עיוות דמוי לבה.

נעשה שימוש בשיטה דומה עבור 'קורונה', למעט 'כרטיס Sprite שטוח' שפונה תמיד למצלמה באמצעות https://github.com/mrdoob/three.js/blob/master/src/extras/core/Gyroscope.js.

מעבד סול.
גרסה מוקדמת של השמש.

ההבהובים הסולאריים נוצרו דרך קודקוד ולוחות הצללה (shader) שהוחלו על טורוס והסתובב סביב קצה פני השטח הסולארי. לכלי ההצללה קודקוד יש פונקציית רעש, שגורמת לו להסתובב בצורה דמוית blob.

כאן נתקלתי בבעיות שקשורות ל-Z-fighting בגלל דיוק ב-GL. כל משתני הדיוק הוגדרו מראש ב-THREE.js, כך שלא יכולתי להגדיל את רמת הדיוק באופן מציאותי ללא עבודה רבה. הבעיות ברמת הדיוק לא היו גרועות באותה מידה ליד המקור. אבל אחרי שהתחלתי לבנות מודלים של מערכות כוכבים אחרות, זה הפך לבעיה.

מודל כוכב.
מאוחר יותר הקוד לעיבוד של השמש כלל כוכבים אחרים.

השתמשתי בכמה פריצות כדי לצמצם את קרבות מסוג Z-fighting. Material.polygonoffset של THREE הוא מאפיין שמאפשר עיבוד של פוליגונים במיקום נתפס שונה (עד כמה שהבנתי). הוא שימש כדי לאלץ את מישור הקורונה להיקלט תמיד על פני השטח של השמש. מתחת לתמונה הזו, הופקה "הילה" של שמש שנועדה לתת קרני אור חדות שמתרחקים מהכדור.

בעיה אחרת שקשורה לדיוק הייתה שהמודלים של הכוכבים יתחילו לרעוד עם התקרבות הסצנה. כדי לתקן זאת, נאלצתי "אפס" את סיבוב סצנות הסביבה ולסובב בנפרד את מודל הכוכב ואת מפת הסביבה כדי ליצור אשליה שאתה סובב את הכוכב.

בתהליך יצירת Lensflare

עם כוח גדול יש אחריות גדולה.
עם כוח גדול יש גם אחריות גדולה.

תצוגות חזותיות של החלל מאפשרות לי להשתמש יותר מדי בעדשות מצלמה. THREE.LensFlare משרת את המטרה הזו, וכל מה שהייתי צריך לעשות היה להוסיף כמה משושים אנמורפיים ומקף של JJ Abrams. קטע הקוד הבא מראה איך לבנות אותן בסצנה.

// This function returns a lesnflare THREE object to be .add()ed to the scene graph
function addLensFlare(x,y,z, size, overrideImage){
var flareColor = new THREE.Color( 0xffffff );

lensFlare = new THREE.LensFlare( overrideImage, 700, 0.0, THREE.AdditiveBlending, flareColor );

// we're going to be using multiple sub-lens-flare artifacts, each with a different size
lensFlare.add( textureFlare1, 4096, 0.0, THREE.AdditiveBlending );
lensFlare.add( textureFlare2, 512, 0.0, THREE.AdditiveBlending );
lensFlare.add( textureFlare2, 512, 0.0, THREE.AdditiveBlending );
lensFlare.add( textureFlare2, 512, 0.0, THREE.AdditiveBlending );

// and run each through a function below
lensFlare.customUpdateCallback = lensFlareUpdateCallback;

lensFlare.position = new THREE.Vector3(x,y,z);
lensFlare.size = size ? size : 16000 ;
return lensFlare;
}

// this function will operate over each lensflare artifact, moving them around the screen
function lensFlareUpdateCallback( object ) {
var f, fl = this.lensFlares.length;
var flare;
var vecX = -this.positionScreen.x _ 2;
var vecY = -this.positionScreen.y _ 2;
var size = object.size ? object.size : 16000;

var camDistance = camera.position.length();

for( f = 0; f < fl; f ++ ) {
flare = this.lensFlares[ f ];

flare.x = this.positionScreen.x + vecX * flare.distance;
flare.y = this.positionScreen.y + vecY * flare.distance;

flare.scale = size / camDistance;
flare.rotation = 0;

}
}

דרך קלה לבצע גלילת מרקם

בהשראת עולם הבית.
מישור קרטזית שעוזר בקביעת פריסה מרחבית בחלל.

עבור 'מישור הכיוון המרחבי', נוצרה פונקציית THREE.CylinderGeometry() ענקית וממרכזת את השמש. כדי ליצור את "גל האור" שמתאוורר כלפי חוץ, שיניתי את קיזוז המרקם שלו לאורך הזמן באופן הבא:

mesh.material.map.needsUpdate = true;
mesh.material.map.onUpdate = function(){
this.offset.y -= 0.001;
this.needsUpdate = true;
}

map הוא המרקם השייך לחומר, וניתן לשכתב אותו באמצעות פונקציית onUpdate. הגדרת ההיסט שלו גורמת ל "גלילה" של המרקם לאורך הציר, והפצת ספאם נדרשת = true תאלץ את ההתנהגות הזו בלולאה.

שימוש ברמפות צבע

לכל כוכב יש צבע שונה על סמך 'אינדקס צבעים' שהאסטרונומים הקצו לו. באופן כללי, כוכבים אדומים הם קרים יותר וכוכבים כחולים/סגולים חמים יותר. רצועה של צבעי לבן וכתום בינוני קיימת בהדרגה הזו.

בזמן יצירת הכוכבים רציתי לתת לכל חלקיק צבע משלו על סמך הנתונים האלה. ניתן לעשות זאת באמצעות "מאפיינים" שניתנו לחומר ההצללה שמוחל על החלקיקים.

var shaderMaterial = new THREE.ShaderMaterial( {
uniforms: datastarUniforms,
attributes: datastarAttributes,
/_ ... etc _/
});
var datastarAttributes = {
size: { type: 'f', value: [] },
colorIndex: { type: 'f', value: [] },
};

מילוי מערך colorIndex יספק לכל חלקיק את הצבע הייחודי שלו בהצללה. בדרך כלל יש להעביר אחד באמצעות צבע vec3, אבל במקרה הזה אני מעביר מספר צף כדי לחפש את רמפת הצבעים הסופית.

טווח צבעים.
רמפת צבע המשמשת לחיפוש הצבע הגלוי מאינדקס הצבעים של כוכב.

תצוגת הצבעים נראתה כך, אבל היה צורך לגשת לנתוני הצבעים של מפת הסיביות מ-JavaScript. עשיתי את זה כדי לטעון קודם את התמונה ב-DOM, לצייר אותה לתוך רכיב בד ציור ולאחר מכן לגשת למפת הסיביות של הקנבס.

// make a blank canvas, sized to the image, in this case gradientImage is a dom image element
gradientCanvas = document.createElement('canvas');
gradientCanvas.width = gradientImage.width;
gradientCanvas.height = gradientImage.height;

// draw the image
gradientCanvas.getContext('2d').drawImage( gradientImage, 0, 0, gradientImage.width, gradientImage.height );

// a function to grab the pixel color based on a normalized percentage value
gradientCanvas.getColor = function( percentage ){
return this.getContext('2d').getImageData(percentage \* gradientImage.width,0, 1, 1).data;
}

משתמשים באותה שיטה לצביעת כוכבים בודדים בתצוגת מודל הכוכבים.

העיניים שלי!
אותה שיטה משמשת לחיפוש צבע אחר המחלקה הספקטרלית של כוכב.

התעסקות עם צילייה

במהלך הפרויקט גיליתי שצריך לכתוב יותר ויותר תוכנות הצללה כדי להשיג את כל האפקטים החזותיים. כתבתי תוכנת הצללה מותאמת אישית למטרה הזו כי נמאס לי להפעיל תוכנות הצללה (shader).

// list of shaders we'll load
var shaderList = ['shaders/starsurface', 'shaders/starhalo', 'shaders/starflare', 'shaders/galacticstars', /*...etc...*/];

// a small util to pre-fetch all shaders and put them in a data structure (replacing the list above)
function loadShaders( list, callback ){
var shaders = {};

var expectedFiles = list.length \* 2;
var loadedFiles = 0;

function makeCallback( name, type ){
return function(data){
if( shaders[name] === undefined ){
shaders[name] = {};
}

    shaders[name][type] = data;

    //  check if done
    loadedFiles++;
    if( loadedFiles == expectedFiles ){
    callback( shaders );
    }

};

}

for( var i=0; i<list.length; i++ ){
var vertexShaderFile = list[i] + '.vsh';
var fragmentShaderFile = list[i] + '.fsh';

//  find the filename, use it as the identifier
var splitted = list[i].split('/');
var shaderName = splitted[splitted.length-1];
$(document).load( vertexShaderFile, makeCallback(shaderName, 'vertex') );
$(document).load( fragmentShaderFile,  makeCallback(shaderName, 'fragment') );

}
}

הפונקציה loadShaders() לוקחת רשימה של שמות של קובצי הצללה (נדרשים .fsh למקטע ו- .vsh לתוכנות הצללה קוד), מנסה לטעון את הנתונים שלהם ורק מחליפה את הרשימה באובייקטים. התוצאה הסופית היא מדים של THREE.js, שאפשר להעביר אליהם תוכנות הצללה (shader), באופן הבא:

var galacticShaderMaterial = new THREE.ShaderMaterial( {
vertexShader: shaderList.galacticstars.vertex,
fragmentShader: shaderList.galacticstars.fragment,
/_..._/
});

יכול להיות שהייתי יכול להשתמש ב-required.js, אבל היה צורך בהרכבת קוד מחדש למטרה הזו בלבד. לדעתי, ניתן לשפר את הפתרון הזה, למרות שהוא פשוט הרבה יותר, אולי אפילו באמצעות תוסף של THREE.js. אם יש לך הצעות או דרכים לשפר את המצב, אשמח לדעת.

תוויות טקסט של CSS מעל THREE.js

בפרויקט האחרון שלנו, Small Arms Globe, השתעשעתי ביצירת תוויות טקסט על גבי סצנה של THREE.js. השיטה שהשתמשתי בה מחשבת את המיקום המוחלט של המודל שבו אני רוצה שהטקסט יופיע. לאחר מכן היא קובעת את מיקום המסך באמצעות THREE.Projector() , ולבסוף משתמשת ב-CSS "top" ו-"left" כדי למקם את רכיבי ה-CSS במיקום הרצוי.

בניסיונות המוקדמים בפרויקט הזה נעשה שימוש באותה טכניקה, אבל אני רוצה לנסות את השיטה האחרת שמתוארת על ידי לואיס קרוז.

הרעיון הבסיסי: להתאים את הטרנספורמציה של ה-CSS3D למצלמה ולסצנה של THREE, וניתן "למקם" רכיבי CSS בתלת-ממד כאילו הם מעל הסצנה של THREE. עם זאת, יש מגבלות לכך, לדוגמה, לא ניתן יהיה להציג טקסט מתחת לאובייקט THREE.js. זה עדיין הרבה יותר מהיר מהניסיון לבצע פריסה באמצעות מאפייני CSS 'למעלה' ו'שמאל'.

תוויות טקסט.
שימוש בהמרות CSS3D כדי להציב תוויות טקסט על WebGL.

כאן תוכלו למצוא את ההדגמה (והקוד במקור התצוגה) של הבקשה. עם זאת, גיליתי שסדר המטריצה השתנה מאז עבור THREE.js. הפונקציה שעדכנתי:

/_ Fixes the difference between WebGL coordinates to CSS coordinates _/
function toCSSMatrix(threeMat4, b) {
var a = threeMat4, f;
if (b) {
f = [
a.elements[0], -a.elements[1], a.elements[2], a.elements[3],
a.elements[4], -a.elements[5], a.elements[6], a.elements[7],
a.elements[8], -a.elements[9], a.elements[10], a.elements[11],
a.elements[12], -a.elements[13], a.elements[14], a.elements[15]
];
} else {
f = [
a.elements[0], a.elements[1], a.elements[2], a.elements[3],
a.elements[4], a.elements[5], a.elements[6], a.elements[7],
a.elements[8], a.elements[9], a.elements[10], a.elements[11],
a.elements[12], a.elements[13], a.elements[14], a.elements[15]
];
}
for (var e in f) {
f[e] = epsilon(f[e]);
}
return "matrix3d(" + f.join(",") + ")";
}

מכיוון שהכול עובר טרנספורמציה, הטקסט לא פונה יותר למצלמה. הפתרון היה להשתמש ב-THREE.Gyroscope(), שמאלץ את Object3D "לאבד" את הכיוון שעבר בירושה מהסצנה. שיטה זו נקראת "לוח חשבונות", וג'ירוסקופ מושלם לשם כך.

מה שמעניין במיוחד הוא שכל ה-DOM וה-CSS הרגילים עדיין פועלים יחד, כמו האפשרות להעביר את העכבר מעל תווית טקסט תלת-ממדית ולהפוך אותה לזהה עם הטלת צלליות.

תוויות טקסט.
תוויות טקסט תמיד פונות למצלמה על ידי חיבורה לפונקציית THREE.Gyroscope().

בדקתי את התצוגה וגיליתי שקנה המידה של הטיפוגרפיה גרם לבעיות במיקום. אולי הסיבה לכך היא הצימוד והמרווח הפנימי של הטקסט? בעיה אחרת הייתה שהטקסט הפך מפוקסל כשהגדלתו את התצוגה, מאחר שמעבד DOM מתייחס לטקסט שעבר עיבוד כריבוע עם מרקם, שיש לשים לב אליו בעת שימוש בשיטה זו. במבט לאחור, יכולתי להשתמש בטקסט בגודל גופן ענקי, ואולי זה משהו שנלמד בעתיד. בפרויקט הזה השתמשתי גם בתוויות הטקסט "למעלה/משמאל" למיקום CSS, שתוארו קודם לכן, לאלמנטים ממש קטנים שמתלווים לכוכבי הלכת במערכת השמש.

השמעת מוזיקה והפעלה בלופ

היצירה המושמעת במהלך'המפה הגלקטית ' של Mass Effect הייתה של המלחינים סם האליק וג'ק וול, והיא הייתה הרגשה שרציתי שהמבקר יחווה. רצינו קצת מוזיקה בפרויקט שלנו, כי הרגשנו שהוא חלק חשוב מהאטמוספרה, ועזרנו ליצור את התחושה הזו של הפלה ותחושת פלא.

המפיק שלנו Valdean Klump יצר קשר עם סאם, שהגדיר שפע של מוזיקת "קיצוץ" ב-Mass Effect והתירו לנו להשתמש בו באדיבות. שם הטראק הוא "בארץ מוזרה".

השתמשתי בתג האודיו להפעלת מוזיקה, אבל גם ב-Chrome, המאפיין " לולאה" לא היה אמין -- לפעמים הוא פשוט נכשל בלופ. בסוף הפריצה הזו לתגי האודיו הכפול שימשה כדי לבדוק את סיום ההפעלה והרכיבה על אופניים לתג השני שהוגדר להפעלה. מה שהתאכזב היה שהעדיין הזה לא היה פועל כל הזמן בלופ, אבל לצערי אני חושב שזה היה הכי טוב שיכולתי לעשות.

var musicA = document.getElementById('bgmusicA');
var musicB = document.getElementById('bgmusicB');
musicA.addEventListener('ended', function(){
this.currentTime = 0;
this.pause();
var playB = function(){
musicB.play();
}
// make it wait 15 seconds before playing again
setTimeout( playB, 15000 );
}, false);

musicB.addEventListener('ended', function(){
this.currentTime = 0;
this.pause();
var playA = function(){
musicA.play();
}
// otherwise the music will drive you insane
setTimeout( playA, 15000 );
}, false);

// okay so there's a bit of code redundancy, I admit it
musicA.play();

מקום לשיפור

אחרי שעבדתי עם THREE.js במשך זמן מה, אני מרגיש שהגעתי לנקודה שבה הנתונים שלי התערבבו עם הקוד יותר מדי. לדוגמה, כשהגדרתי את התוכן של חומרים, טקסטורות והוראות גיאומטריה ישירות במקום, רציתי בעצם 'בניית מודלים תלת-ממדיים עם קוד'. זה הרגיש מאוד לא טוב, והתחום שבו מאמצים עתידיים עם THREE.js עשויים להשתפר משמעותית, לדוגמה, הגדרת נתונים של חומר בקובץ נפרד, עדיף להציג ולשנות אותם בהקשר מסוים, וייתכן שיהיה אפשר להחזיר אותם לפרויקט הראשי.

העמית שלנו ריי מקלור הקדיש זמן כדי ליצור כמה "רעשי חלל" גנרטיביים מדהימים, שהיה צריך להיחתך בגלל שה-API של האודיו באינטרנט לא היה יציב, ו-Chrome קורס כל הזמן. זה חבל... אבל זה בהחלט גרם לנו לחשוב יותר בתחום הצלילים לקראת עבודה עתידית. נכון למועד כתיבת ההודעה אני רוצה לדעת שה-Web Audio API תוקן, כך שיכול להיות שהוא פועל עכשיו וצריך לחפש אותו בעתיד.

רכיבי טיפוגרפיה שמותאמים ל-WebGL עדיין מהווים אתגר, ואני לא בטוח ב-100% שמה שאנחנו עושים כאן הוא הדרך הנכונה. זה עדיין מרגיש כמו פריצה. אולי גרסאות עתידיות של THREE, עם כלי עיבוד ה-CSS החדש והחדש שלו, יוכלו לשמש כדי להצטרף טוב יותר לשני העולמות.

זיכויים

תודה לארון קובלין שאישר לי לנסוע לעיר עם הפרויקט הזה. ג'ונו ברנדל על העיצוב המצטיין של ממשק המשתמש + ההטמעה, הטיפול בסוגי וההטמעה של הסיורים. ואלדן קלאמפ שנתן לפרויקט שם ואת כל העותק. סבה אחמד דיברת על ההקצאה של כל המטריצות של זכויות השימוש לנתונים ולמקורות של התמונות. קלם רייט הגיע אל האנשים הנכונים לפרסום. דאג פריץ על מצוינות טכנית. ג'ורג' ברואר כי הוא לימד אותי JS ו-CSS. וכמובן Mr. Doob עבור THREE.js.

קובצי עזר