100.000 Yıldız Kazanma

Michael Chang
Michael Chang

Merhaba! Adım Michael Chang ve Google'ın Veri Sanatları Ekibi'nde çalışıyorum. Kısa süre önce, yakındaki yıldızları görselleştiren bir Chrome Deneyi olan 100.000 Stars'ı tamamladık. Proje THREE.js ve CSS3D ile oluşturuldu. Bu vaka analizinde, keşif sürecinin ana hatlarını çıkaracağım, bazı programlama tekniklerini paylaşacağım ve ileride iyileştirme sağlamak için bazı düşüncelerimle bitireceğim.

Burada ele alınan konular oldukça genel olacak ve THREE.js hakkında biraz bilgi sahibi olmayı gerektirecektir. Ancak, teknik bir inceleme sonrası için de bunun hoşunuza gideceğini umuyorum. Sağ taraftaki içindekiler düğmesini kullanarak istediğiniz bir alana atlayabilirsiniz. Öncelikle projenin oluşturma kısmını, ardından gölgelendirici yönetimini ve son olarak da CSS metin etiketlerinin WebGL ile birlikte nasıl kullanılacağını göstereceğim.

100.000 Yıldız, Veri Sanatları Ekibi tarafından bir Chrome Denemesi
100.000 Stars,Samanyolu'nda yakındaki yıldızları görselleştirmek için ÜÇ.js'yi kullanıyor

Uzayı Keşfetme

Small Arms Globe'u bitirdikten kısa bir süre sonra alan derinliği olan bir THREE.js parçacık demosuyla deneme yapıyordum. Uygulanan efektin miktarını ayarlayarak sahnenin yorumlanan "ölçeklerini" değiştirebileceğimi fark ettim. Alan derinliği efekti aşırı derecede olduğunda, uzaktaki nesneler, mikroskobik bir sahneye bakma illüzyonu vermek için kullanılan eğim kaydırmalı fotoğrafların kullanıldığı gibi bulanık bir hale geldi. Öte yandan, efekt azaltıldığında görüntü derin bir uzaya bakıyormuş gibi hissediliyordu.

Parçacık konumlarını eklemek için kullanabileceğim verileri aramaya başladım. Bu yol, astronexus.com'un HYG veritabanına, üç veri kaynağının (Hipparcos, Yale Bright Star Catalog ve Gliese/Jahreiss Kataloğu) bir derlemesine ve önceden hesaplanmış xyz Kartezyen koordinatlarına eşlik eder. Başlayalım!

Yıldız verilerinin grafiğini çizme.
İlk adım, katalogdaki her yıldızı tek bir parçacık olarak çizmektir.
Adlandırılmış yıldızlar.
Katalogdaki bazı yıldızların burada etiketlenmiş özel adları vardır.

Yıldız verilerini 3D uzaya yerleştiren bir şeyi hack'lemek yaklaşık bir saat sürdü. Veri kümesinde tam olarak 119.617 yıldız vardır. Bu nedenle, her bir yıldızın parçacıkla temsil edilmesi modern bir GPU için sorun teşkil etmez. Ayrıca, bağımsız olarak tanımlanmış 87 yıldız olduğundan Small Arms Globe'da açıkladığım tekniği kullanarak bir CSS işaretçi yerleşimi oluşturdum.

Bu süre zarfında Mass Effect serisini yeni bitirmiştim. Oyunda oyuncu, galaksiyi keşfetmeye, çeşitli gezegenleri taramaya ve bu gezegenlerin tamamen kurgusal, Vikipedi gibi görünen geçmişlerini, gezegenin jeolojik tarihini vb. taramaya davet ediliyor.

Yıldızlarla ilgili gerçek verilerin ne kadar büyük olduğunu bildiğimiz için galaksiyle ilgili gerçek bilgileri de aynı şekilde sunabiliriz. Bu projenin nihai hedefi, bu verileri hayata geçirmek, izleyicinin à la Mass Effect galaksisini keşfetmesine, yıldızları ve dağılımı hakkında bilgi edinmesine ve uzay konusunda bir hayranlık ve merak duygusu uyandırmak olacaktır. Bora

Muhtemelen bu örnek olay incelemesinin geri kalanına, hiçbir şekilde astronom değilim ve bunun amatör bir araştırmanın çalışması olduğunu söyleyerek ve dışarıdan uzmanlardan tavsiye almam gerek. Bu proje kesinlikle mekanın bir sanatçı yorumu olarak yorumlanmalı.

Galaksi Oluşturma

Planım, prosedür olarak, yıldız verilerini bir bağlama oturtabilecek ve umarım Samanyolu'ndaki yerimize ilişkin mükemmel bir görünüm sunacak bir galaksi modeli oluşturmaktı.

Galaksinin ilk prototipi.
Samanyolu parçacık sisteminin ilk prototipi.

Samanyolu'nu oluşturmak için 100.000 tane parçacık ürettim ve galaksi kollarının oluşturulma biçimini taklit ederek bunları bir sarmala yerleştirdim. Spiral kol oluşumunun ayrıntıları konusunda fazla endişe duymadım çünkü bu matematiksel bir modelden çok temsilsel bir model olacaktı. Bununla birlikte, sarmal kolların sayısını aşağı yukarı doğru ve "doğru yönde" dönmeye çalıştım.

Samanyolu modelinin sonraki sürümlerinde, parçacıkların kullanımına ağırlık vermeden önce parçacıklara eşlik edecek düzlemsel bir galaksiyi öne çıkardım ve böylece parçacıklara daha fazla fotoğrafik bir görünüm kazandıracağını umuyorum. Bizden yaklaşık 70 milyon ışık yılı uzakta bulunan ve Samanyolu'na benzeyen NGC 1232 sarmal gökadasının görüntüsü.

Galaksinin ölçeğini bulmak.
Her GL birimi bir ışık yılıdır. Bu örnekte küre, parçacık sistemini kapsayan 110.000 ışık yılı genişliğindedir.

Daha önce bir GL birimini, temelde 3D boyutundaki bir pikseli bir ışık yılı olarak göstermeye karar verdim. Bu yöntem, görselleştirilen her şey için birleşik bir yerleşim oluyor, ne yazık ki daha sonralarımda ciddi hassasiyet sorunları yaşanmasına neden oluyordu.

Bir diğer yöntem de kamerayı hareket ettirmek yerine sahnenin tamamını döndürmekti. Başka birkaç projede de yaptığım bir şey. Bir avantajı, fare ile sola ve sağa sürüklemenin söz konusu nesneyi döndüreceği şekilde her şeyin bir "döndürülebilir masa" üzerine yerleştirilmesidir. Ancak, yakınlaştırmak için yalnızca Camera.position.z öğesini değiştirmek gerekir.

Kameranın görüş alanı da (FOV) dinamiktir. Biri dışarı doğru çekildiğinde görüş alanı genişler ve galaksinin her geçen gün daha da fazlasını kaplar. Yıldıza doğru içe doğru giderken görüş alanı daralır. Bu özellik sayesinde kamera, görüş açısını tanrı benzeri bir büyüteç gibi bir şeye daraltarak (galaksiyle karşılaştırıldığında) son derece küçük olan nesneleri görüntüleyebilir. Yakın düzlem kırpma sorunlarıyla uğraşmak zorunda kalmaz.

Galaksi oluşturmanın farklı yolları.
(yukarıda) Erken parçacık galaksisi. (aşağıda) Görüntü düzlemi eşliğinde tanecikler.

Buradan, Güneş'i gökada çekirdeğinden belirli sayıda birim uzağa "yerleştirmeyi" başardım. Bunun yerine Kuiper Kayalıkları'nın yarıçapını ortaya çıkararak (nihayetinde Oort Bulutu'nu görselleştirmeye karar verdim) güneş sisteminin göreceli boyutunu görselleştirebildim. Bu güneş sistemi modelinde, Dünya'nın basitleştirilmiş bir yörüngesi ile Güneş'in gerçek yarıçapını karşılaştırmalı olarak görselleştirebilirim.

Güneş sistemi.
Gezegenlerin etrafında dönen Güneş ve Kuiper Kuşağını temsil eden bir küre.

Güneş'in görüntülenmesi zordu. Bildiğim kadar gerçek zamanlı grafik tekniğiyle hile yapmak zorunda kaldım. Güneş'in yüzeyi, plazmanın sıcak köpüklü bir köpüktür. Zaman içinde parlayıp sönmesi ve değişmesi gerekir. Güneş yüzeyinin kızılötesi görüntüsünün bit eşlem dokusu kullanılarak simüle edildi. Yüzey gölgelendirici, bu dokunun gri tonlarına dayalı olarak renk araması yapar ve aramayı ayrı bir renk rampasında gerçekleştirir. Bu arama zaman içinde kaydırıldığında lav benzeri bir bozulma yaratır.

Güneş koronası için de benzer bir teknik kullanıldı. Tek fark, bunun https://github.com/mrdoob/three.js/blob/master/src/extras/core/Gyroscope.js kullanılarak sürekli kameraya bakan düz bir imge kartı olmasıdır.

Sol.
Güneşin erken saatleri.

Güneş parlamaları, tepe noktası ve güneş yüzeyinin hemen kenarı etrafında dönen bir simidin parçası gölgelendiriciler aracılığıyla oluşturulmuştu. Köşe noktası gölgelendiricinin, bloba benzer bir yapıya sahip olmasına neden olan bir gürültü işlevi vardır.

İşte GL hassasiyetinden dolayı bazı z çatışması sorunları yaşamaya başladım. Kesinliğe ilişkin değişkenlerin tümü THREE.js'de önceden tanımlanmış, bu yüzden çok fazla çalışma yapmadan kesinliği gerçekçi bir şekilde artıramadım. Hassasiyet sorunları kaynağı yakınında o kadar kötü değildi. Ama diğer yıldız sistemlerini modellemeye başladığımda bu bir soruna dönüştü.

Modele yıldız ekleyin.
Güneş'i oluşturmak için kullanılan kod daha sonra diğer yıldızları gösterecek şekilde genelleştirildi.

Z çatışmasını azaltmak için uyguladığım birkaç saldırı vardı. THREE Material.polygonoffset özelliği, poligonların algılanan farklı bir konumda oluşturulmasını sağlayan bir özelliktir (anladığımız kadarıyla). Bu, korona uçağının daima Güneş yüzeyinin üzerinde oluşturulmasını sağlamak için kullanılıyordu. Bunun altında, küreden uzaklaşan keskin ışık ışınları sağlamak için bir Güneş "hali" oluşturulmuştur.

Hassasiyetle ilgili farklı bir sorun da, sahne yakınlaştırıldıkça yıldız modellerinin titremeye başlamasıydı. Bu sorunu gidermek için sahne dönüşünü "sıfırlamam" ve yıldızın yörüngesinde döndüğünüzüymuş gibi göstermek için yıldız modelini ve ortam haritasını ayrı ayrı döndürmem gerekti.

Lensflare oluşturuluyor

Büyük güç, büyük sorumluluk da beraberinde getirir.
Büyük güç, beraberinde de büyük sorumluluk getirir.

Uzay görselleştirmeleri, aşırı lens parlaması kullanımından kaçınabileceğimi düşündüğüm yerler. THREE.LensFlare bu amaca hizmet ediyor. Tek yapmam gereken birkaç anamorfik altıgenler ve bir parça JJ Abrams yazmaktı. Aşağıdaki snippet'te bunların sahnenizde nasıl oluşturulacağı gösterilmektedir.

// 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;

}
}

Doku kaydırma yapmanın kolay bir yolu

Homeworld'den esinlenildi.
Uzayda uzamsal yöne yardımcı olan kartezyen düzlem.

"Uzamsal yönelim düzlemi" için, devasa bir ÜÇ.CylinderGeometry() oluşturuldu ve Güneş'i merkeze aldı. Dışa doğru yayılan "ışık dalgası"nı oluşturmak için doku ofsetini zaman içinde şu şekilde değiştirdim:

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

map, malzemeye ait dokudur ve üzerine yazabileceğiniz bir onUpdate işlevi alır. Ofsetin ayarlanması, yapının bu eksende "kaydırılmasına" neden olur ve spam yapmak needUpdate = true şeklinde, bu davranışın döngüye girmesine neden olur.

Renk rampaları kullanma

Her yıldız, astronomların kendisine atadığı bir "renk endeksi"ne bağlı olarak farklı bir rengine sahiptir. Genel olarak, kırmızı yıldızlar daha soğuk, mavi/mor yıldızlar daha sıcaktır. Bu gradyanda beyaz ve ara turuncu renklerden oluşan bir şerit bulunur.

Yıldızları oluştururken, bu verilere dayanarak her bir parçacığa kendi rengini vermek istedim. Bunu yapmanın yolu, parçacıklara uygulanan gölgelendirici malzemeye verilen "özellikleri" kullanmaktır.

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

colorIndex dizisini doldurmak, her taneciğe gölgelendiricide benzersiz bir renk verir. Normalde biri vec3 rengi ile geçiş yapar, ancak bu örnekte, nihai renk rampası araması için bir float geçiriyorum.

Renk rampası.
Bir yıldızın renk dizininden görülebilir rengi bulmak için kullanılan renk rampası.

Renk rampası şöyle görünüyordu, ancak bit eşlem renk verilerine JavaScript'ten erişmem gerekiyordu. Bu şekilde, önce resmi DOM'ye yükleyip bir tuval öğesinin içinde çizdim, ardından tuval bit eşlemine erişin.

// 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;
}

Daha sonra aynı yöntem, yıldız modeli görünümünde tek tek yıldızları renklendirmek için kullanılır.

Gözlerim!
Yıldızın spektral sınıfı için renk araması yapmak için de aynı teknik kullanılır.

Gölge hazırlama

Proje boyunca, görsel efektlerin tümünü başarmak için gittikçe daha fazla gölgelendirici yazmam gerektiğini fark ettim. Gölgelendiricilerin index.html içinde bulunmasından sıkıldığım için bu amaçla özel bir gölgelendirici yükleyici yazdım.

// 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() işlevi, gölgelendirici dosya adlarının bir listesini alır (parça için .fsh, köşe gölgelendiricileri için .vsh bekler), verilerini yüklemeyi dener ve daha sonra, listeyi nesnelerle değiştirir. Nihai sonuç, THREE.js formalarınızda gölgelendiricileri şu şekilde geçirebilirsiniz:

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

Muhtemelen required.js'yi kullanabilirdim ancak bu kullanım için bazı kodların yeniden birleştirilmesi gerekti. Bu çözüm çok daha kolay olsa da, bir THREE.js uzantısı olarak bile geliştirilebilir. Bunu daha iyi hale getirmek için önerileriniz veya yöntemleriniz varsa lütfen bize bildirin.

ÜÇ.js'nin üzerindeki CSS Metin Etiketleri

Son projemiz Small Arms Globe'da, metin etiketlerinin THREE.js sahnesinin üstünde görünmesini sağlamak için çalıştım. Kullandığım yöntem, metnin görünmesini istediğim yerin mutlak model konumunu hesaplıyor, ardından ÜÇ.Projector() kullanarak ekran konumunu çözümliyor ve son olarak, CSS öğelerini istenen konuma yerleştirmek için CSS "top" ve "left" özelliklerini kullanıyor.

Bu projedeki ilk yinelemelerde aynı teknik kullanıldı, ancak Luis Cruz tarafından açıklanan diğer yöntemi denemek için sabırsızlanıyorum.

Temel fikir, CSS3D'nin matris dönüşümünü ÜÇ'ün kamerası ve sahnesiyle eşleştirin ve CSS öğelerini ÜÇ'ün sahnesinin üzerineymiş gibi 3D olarak"yerleştirebilirsiniz". Ancak, bu konuda sınırlamalar söz konusudur. Örneğin, bir THREE.js nesnesinin altına metin yazamazsınız. Bu yine de "top" (üst) ve "left" (sol) CSS özelliklerini kullanarak düzen gerçekleştirmeye çalışmaktan çok daha hızlıdır.

Metin etiketleri.
WebGL'nin üzerine metin etiketleri yerleştirmek için CSS3D dönüşümlerini kullanma.

Buna ilişkin demoyu (ve kodu kaynağı görünümdeki) burada bulabilirsiniz. Ancak, THREE.js dosyası için matris sırasının değiştiğini gördüm. Güncellediğim işlev:

/_ 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(",") + ")";
}

Her şey dönüştürüldüğü için metin artık kameraya bakmıyor. Çözüm, Object3D'yi sahneden devralınan yönünü "kaybetmeye" zorlayan THREE.Gyroscope() kullanılmasıydı. Bu tekniğe "billboard" adı verilir ve Jiroskop bunu yapmak için mükemmeldir.

İşin asıl güzel yanı, normal DOM ve CSS'nin tamamının oynatılmaya devam etmesidir. Örneğin, fareyle 3D metin etiketinin üzerine gelebilir ve etiketin gölgeleriyle parlamasını sağlayabilirsiniz.

Metin etiketleri.
Metin etiketlerinin her zaman kameraya dönük olması için ÜÇ.Jiroskop() işlevine takması gerekir.

Yakınlaştırırken tipografinin ölçeklenmesinin konumlandırmayla ilgili sorunlara neden olduğunu fark ettim. Bunun nedeni metin aralığı ve dolgusu olabilir mi? Başka bir sorun da, DOM oluşturucu oluşturulan metni dokulu bir dörtlü olarak işlediği için yakınlaştırıldığında metnin piksellenmesiydi. Bu yöntem kullanılırken dikkat edilmesi gereken bir nokta vardır. Geriye dönüp baktığımda, yazı tipi boyutundaki devasa metinler kullanabilirdim. Belki de bu, ileride yapılabilecek keşifler için bir fırsattır. Bu projede, daha önce açıklandığı gibi, güneş sistemindeki gezegenlere eşlik eden gerçekten küçük elementler için "üst/sol" CSS yerleşim metin etiketlerini de kullandım.

Müzik çalma ve döngü

Mass Effect'in "Galactic Map" adlı şarkısı sırasında çalan müzik, Bioware bestecileri Sam Hulick ve Jack Wall'a aitti ve ziyaretçinin tecrübe etmesini istediğim türden bir duyguya sahipti. Atmosferin önemli bir parçası olduğunu hissettiğimiz ve hedeflediğimiz hayranlık ve merak duygusunu oluşturmamıza yardımcı olduğu için projemizde müzik istedik.

Prodüktörümüz Valdean Klump, Mass Effect'ten aldığımız ve nezaketle kullanmamıza izin verdiği birçok "cumuncuk" müziği olan Sam ile iletişime geçti. Parçanın adı "In a Strange Land".

Müzik çalmak için ses etiketini kullandım, ancak Chrome'da bile "loop" özelliği güvenilir değildi; bazen döngü başarısız oluyordu. Sonunda bu ikili ses etiketi saldırısı, oynatmanın sonunu kontrol etmek ve çalmak üzere diğer etikete geçmek için kullanılmıştır. Bu videonun hâlâ her zaman mükemmel şekilde döngüye alınmamış olması beni hayal kırıklığına uğrattı. Ancak yapabileceğim en iyisi buydu.

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();

Geliştirilebilecek alanlar

Bir süre THREE.js ile çalıştıktan sonra, verilerimin kodumla çok fazla karıştığını hissediyorum. Örneğin, malzemeleri, dokuları ve geometri talimatlarını satır içi olarak tanımlarken aslında "kodla 3D modelleme" yapıyordum. Bu bana çok kötü hissettirdi ve gelecekte THREE.js ile yapılacak çalışmalarla ilgili olarak örneğin malzeme verilerinin ayrı bir dosyada tanımlanması, tercihen belli bir bağlamda görüntülenebilir ve üzerinde ince ayar yapılarak yapılan çalışmaların büyük ölçüde iyileştirilebileceği bir alandır ve ana projeye geri getirilebilir.

Meslektaşımız Ray McClure da Web Audio API'sının kararsız olması ve Chrome'un sık sık kilitlenmesi nedeniyle kesilmesi gereken üretken "uzay sesleri" için biraz zaman harcadı. Ne yazık ki ileride yapabileceğimiz çalışmalar için daha çok düşünmemize yardımcı oldu. Bu yazının hazırlandığı tarihte, Web Audio API'sına yama uygulandığından bu işlemin şu anda çalışıyor olabileceğini ve gelecekte dikkat edilecek bir şey olduğunu bildirmek isterim.

WebGL ile eşleştirilmiş tipografik öğeler hala bir zorluk olarak görülüyor ve burada yaptıklarımızın doğru olduğundan% 100 emin değilim. Hâlâ bir numara gibi hissediyorum. Belki de gelecekte kullanıma sunulacak CSS Renderer'ı ile THREE'nin gelecekteki sürümleri, bu iki dünyayı daha iyi birleştirmek için kullanılabilir.

Kredi

Bu projeyle beni şehre ziyaret ettiği için Aaron Koblin'e teşekkür ederim. Mükemmel kullanıcı arayüzü tasarımı, uygulaması, tür işlemleri ve tur uygulaması için Jono Brandel. Valdean Klump'a teşekkür ederiz. Veri ve görsel kaynakları için tonlarca kullanım hakkı elde eden Sabah Ahmet. Yayınlanacak doğru kişilere ulaştığınız için Clem Wright'a Teknik mükemmellik için Doug Fritz. George Brower, bana JS ve CSS'yi öğretti. Elbette Mr. Doob, THREE.js için.

Referanslar