Instructables universum i Three.js (8 / 13 steg)
Steg 8: Three.js: en annan ljusstyrka för varje stjärna: WebGL Shaders
Stjärnor är inte enhetlig. De är olika storlekar, olika ljusstyrka och olika färger. Mitt knep med att ha sex föremål från innan verkade inte att ansöka här: Jag ville verkligen varje stjärna är unikt och att återspegla den relativa betydelsen av projektet. I grund och botten ska de projekt som är de "ljusaste stjärnorna" lysa. Att göra varje vertex unika är en perfekt användning för WebGL shaders. Minns shader koden från innan:
< script typ = "x-shader/x-vertex" id = "vertexshader" >
attributet float alpha;
attributet float storlek;
attributet vec3 ca;
varierande vec3 vColor;
varierande float vAlpha;
void main () {
vColor = ca;
vAlpha = alpha;
vec4 mvPosition = modelViewMatrix * vec4 (position, 1.0);
gl_PointSize = storlek * (1.0 + 300,0 / längd (mvPosition.xyz));
gl_Position = projectionMatrix * mvPosition;
}
< / script >
< script typ = "x-shader/x-fragment" id = "fragmentshader" >
enhetliga vec3 färg;
enhetliga sampler2D textur;
varierande vec3 vColor;
varierande float vAlpha;
void main () {
gl_FragColor = vec4 (vColor, vAlpha);
gl_FragColor = vAlpha * texture2D (textur, gl_PointCoord);
}
< / script >
Dessa shaders arbeta hand i hand med den här ThreeJS koden:
Galaxy.Utilities.projectData = parsedData;
Galaxy.Datasource = parsedData;
var instructableIds = _.keys(parsedData);
skapa geometrier för varje av de sex ringarna, så partikelsystem kan gå självständigt
var particleGeometries = [];
_.each (fönster. Galaxy.Settings.categories,function() {
particleGeometries.push (nya tre. Geometry());
attribut = {
storlek: {typ: "f", värde: []},
ca: {typ: 'c', värde: []},
alpha: {typ: "f", värde: []}
};
Uniform = {
färg: {typ: "c", värde: nya tre. Färg (0xffffff)},
konsistens: {typ: "t", värde: tre. ImageUtils.loadTexture("images/particle4B.png")}
};
shaderMaterialsArray.push (nya tre. ShaderMaterial ({
uniformer: uniformer,
attribut: attribut,
vertexShader: document.getElementById ('vertexshader') .textContent,
fragmentShader: document.getElementById ('fragmentshader') .textContent,
blandning: tre. AdditiveBlending,
depthTest: falska,
öppet: sanna
}));
});
_.each(instructableIds,function(ID) {
var pX = parsedData [id] .x - fönstret. Galaxy.Settings.width/2,
pY = parsedData [id] .y - fönstret. Galaxy.Settings.height/2,
pZ = Galaxy.Utilities.random(0,10),
partikel = nya tre. Vector3 (pX, pY, pZ);
lägga till varje partikel i rätt geometri (ring) så det kommer att hamna i en tillhörande partikel system senare
var ring = indexForCategory(parsedData[id].category);
om (ring! == -1) {
particleGeometries[ring].vertices.push(particle);
var utseende = Galaxy.Utilities.vertexAppearanceByViews(parsedData[id].views);
shaderMaterialsArray[ring].attributes.size.value.push(appearance.size);
shaderMaterialsArray[ring].attributes.ca.value.push(appearance.ca);
shaderMaterialsArray[ring].attributes.alpha.value.push(appearance.alpha);
Vi måste hålla referenser båda riktningarna. Användaren klickar partikel, vi måste slå upp Detaljer av id
Också, om vi vill markera relaterade instructables, vi behöver snabbt enkelt till hörn med refererade ids.
particle.instructableId = id;
.particleMaterial parsedData [id] = shaderMaterialsArray [ring];
.vertexNumber parsedData [id] = particleGeometries [ring].vertices.length-1;
}
});
stora scenen, för alla vanliga galaxy framträdanden
var scen = nya tre. Scene();
Galaxy.Scene = scen;
skapa det partikel systemet
_.each (particleGeometries, funktion (particleGeometry, index) {
particleGeometry.applyMatrix (nya tre. Matrix4 () .makeTranslation (Math.random () * 50, Math.random () * 50, 0));
var systemet = nya tre. () ParticleSystem
particleGeometry,
shaderMaterialsArray [index]
);
particleSystemsArray.push(system);
Scene.Add(system);
});
Här är vad som händer på ren svenska:1. jag satt upp en tre. ShaderMaterial för varje tre. ParticleSystem. Minns från det sista steget att det finns sex ParticleSystems, en för varje kategori av Instructables, och att varje ParticleSystem måste två saker att instansieras: en geometri och ett Material. (se ThreeJS: komma igång ovan)
2. varje tre. ShaderMaterial är väsentligen den samma på denna punkt: de är konfigurerad att använda fragment och vertex shaders lastas i script-taggar ovan. De inkluderar uniformer och attribut gått i från JavaScript. Det är två av de tre typerna av variabler som du kan skicka till WebGL. Också förklaras på html5rocks.com:
-Uniformer ändras inte inom en given ram. De skickas till både fragment och vertex shaders. I det här fallet är färg och konsistens bild (den fina glödande star-liknande bilden) samma för varje stjärna.
-Attribut tillämpas på enskilda noder. De skickas till vertex shaders bara. I det här fallet är de attribut som kan variera från star färg, storlek och alpha.
-Varyings kan vertex shaders att skicka värden till fragment skuggningen.
3. med de tomma tre. ShaderMaterials definieras, min nästa block steg över varje Instructable som visas på skärmen. Den passerar Instructable till en hjälpare funktion som avgör hur stjärnan ska visas, baserat på antalet visningar för detta Instructable:
vertexAppearanceByViews: function(viewcount) {
var framträdande = (Math.pow(Math.log(viewcount),3))/(1000);
returnera {
storlek: framträdande * 9,
ca: Galaxy.Utilities.whiteColor,
alpha: Math.min (0,15 + 0,3 * framträdande, 0,9)
}
}
I den slutliga versionen av koden variera inte jag faktiskt färgen på stjärnorna! Alpha gör det åt mig, eftersom varje stjärna visas på en färgad bakgrund.
4. inuti denna loop trycks varje partikel i en array av brytpunkter i geometri:
var partikel = nya tre. Vector3 (pX, pY, pZ);
...
particleGeometries[ring].vertices.push(particle);
och en motsvarande uppsättning värden som "attribut" trycks in motsvarande ShaderMaterial:
var utseende = Galaxy.Utilities.vertexAppearanceByViews(parsedData[id].views);
shaderMaterialsArray[ring].attributes.size.value.push(appearance.size);
shaderMaterialsArray[ring].attributes.ca.value.push(appearance.ca);
shaderMaterialsArray[ring].attributes.alpha.value.push(appearance.alpha);
Slutligen med en matris av partikel geometrier och motsvarande mängd partikel material, två är sammanslagna till en matris av ParticleSystems och varje ParticleSystem läggs till scenen:
för varje objekt i matrisen particleGeometries:
var systemet = nya tre. () ParticleSystem
particleGeometry,
shaderMaterialsArray [index]
);
...
Scene.Add(system);