282 lines
24 KiB
HTML
282 lines
24 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en"><head>
|
|
<link href="https://google.github.io/filament/favicon.png" rel="icon" type="image/x-icon" />
|
|
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700|Tangerine:700|Inconsolata" rel="stylesheet">
|
|
<link href="main.css" rel="stylesheet" type="text/css">
|
|
</head>
|
|
<body class="verbiage">
|
|
<div class="demo_frame"><iframe src="demo_redball.html"></iframe><a href="demo_redball.html">🔗</a></div>
|
|
<p>This tutorial will describe how to create the <strong>redball</strong> demo, introducing you to materials and
|
|
textures.</p>
|
|
<p>For starters, create a text file called <code>redball.html</code> and copy over the HTML that we used in the
|
|
<a href="tutorial_triangle.html">previous tutorial</a>. Change the last script tag from <code>triangle.js</code> to <code>redball.js</code>.</p>
|
|
<p>Next you'll need to get a couple command-line tools: <code>matc</code> and <code>cmgen</code>. You can find these in the
|
|
appropriate <a href="//github.com/google/filament/releases">Filament release</a>. You should choose the
|
|
archive that corresponds to your development machine rather than the one for web.</p>
|
|
<h2>Define plastic material</h2>
|
|
<p>The <code>matc</code> tool consumes a text file containing a high-level description of a PBR material, and
|
|
produces a binary material package that contains shader code and associated metadata. For more
|
|
information, see the official document describing the <a href="https://google.github.io/filament/Materials.md.html">Filament Material System</a>.</p>
|
|
<p>Let's try out <code>matc</code>. Create the following file in your favorite text editor and call it
|
|
<code>plastic.mat</code>.</p>
|
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span></span>material {
|
|
name : Lit,
|
|
shadingModel : lit,
|
|
parameters : [
|
|
{ type : float3, name : baseColor },
|
|
{ type : float, name : roughness },
|
|
{ type : float, name : clearCoat },
|
|
{ type : float, name : clearCoatRoughness }
|
|
],
|
|
}
|
|
|
|
fragment {
|
|
void material(inout MaterialInputs material) {
|
|
prepareMaterial(material);
|
|
material.baseColor.rgb = materialParams.baseColor;
|
|
material.roughness = materialParams.roughness;
|
|
material.clearCoat = materialParams.clearCoat;
|
|
material.clearCoatRoughness = materialParams.clearCoatRoughness;
|
|
}
|
|
}
|
|
</pre></div>
|
|
|
|
<p>Next, invoke <code>matc</code> as follows.</p>
|
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span></span>matc -a opengl -p mobile -o plastic.filamat plastic.mat
|
|
</pre></div>
|
|
|
|
<p>You should now have a material archive in your working directory, which we'll use later in the
|
|
tutorial.</p>
|
|
<h2>Bake environment map</h2>
|
|
<p>Next we'll use Filament's <code>cmgen</code> tool to consume a HDR environment map in latlong format, and
|
|
produce two cubemap files: a mipmapped IBL and a blurry skybox.</p>
|
|
<p>Download <a href="//github.com/google/filament/blob/main/third_party/environments/pillars_2k.hdr">pillars_2k.hdr</a>, then invoke the following command in your terminal.</p>
|
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span></span>cmgen -x pillars_2k --format<span style="color: #666666">=</span>ktx --size<span style="color: #666666">=256</span> --extract-blur<span style="color: #666666">=0</span>.1 pillars_2k.hdr
|
|
</pre></div>
|
|
|
|
<p>You should now have a <code>pillars_2k</code> folder containing a couple KTX files for the IBL and skybox, as
|
|
well as a text file with spherical harmonics coefficients. You can discard the text file because the
|
|
IBL KTX contains these coefficients in its metadata.</p>
|
|
<h2>Create JavaScript</h2>
|
|
<p>Next, create <code>redball.js</code> with the following content.</p>
|
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span></span><span style="color: #008000; font-weight: bold">const</span> environ <span style="color: #666666">=</span> <span style="color: #BA2121">'pillars_2k'</span>;
|
|
<span style="color: #008000; font-weight: bold">const</span> ibl_url <span style="color: #666666">=</span> <span style="color: #BA2121">`</span><span style="color: #BB6688; font-weight: bold">${</span>environ<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #BB6688; font-weight: bold">${</span>environ<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">_ibl.ktx`</span>;
|
|
<span style="color: #008000; font-weight: bold">const</span> sky_url <span style="color: #666666">=</span> <span style="color: #BA2121">`</span><span style="color: #BB6688; font-weight: bold">${</span>environ<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #BB6688; font-weight: bold">${</span>environ<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">_skybox.ktx`</span>;
|
|
<span style="color: #008000; font-weight: bold">const</span> filamat_url <span style="color: #666666">=</span> <span style="color: #BA2121">'plastic.filamat'</span>
|
|
|
|
Filament.init([ filamat_url, ibl_url, sky_url ], () => {
|
|
<span style="color: #408080; font-style: italic">// Create some global aliases to enums for convenience.</span>
|
|
<span style="color: #008000">window</span>.VertexAttribute <span style="color: #666666">=</span> Filament.VertexAttribute;
|
|
<span style="color: #008000">window</span>.AttributeType <span style="color: #666666">=</span> Filament.VertexBuffer$AttributeType;
|
|
<span style="color: #008000">window</span>.PrimitiveType <span style="color: #666666">=</span> Filament.RenderableManager$PrimitiveType;
|
|
<span style="color: #008000">window</span>.IndexType <span style="color: #666666">=</span> Filament.IndexBuffer$IndexType;
|
|
<span style="color: #008000">window</span>.Fov <span style="color: #666666">=</span> Filament.Camera$Fov;
|
|
<span style="color: #008000">window</span>.LightType <span style="color: #666666">=</span> Filament.LightManager$Type;
|
|
|
|
<span style="color: #408080; font-style: italic">// Obtain the canvas DOM object and pass it to the App.</span>
|
|
<span style="color: #008000; font-weight: bold">const</span> canvas <span style="color: #666666">=</span> <span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">'canvas'</span>)[<span style="color: #666666">0</span>];
|
|
<span style="color: #008000">window</span>.app <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">new</span> App(canvas);
|
|
} );
|
|
|
|
<span style="color: #008000; font-weight: bold">class</span> App {
|
|
constructor(canvas) {
|
|
<span style="color: #008000; font-weight: bold">this</span>.canvas <span style="color: #666666">=</span> canvas;
|
|
<span style="color: #008000; font-weight: bold">const</span> engine <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine <span style="color: #666666">=</span> Filament.Engine.create(canvas);
|
|
<span style="color: #008000; font-weight: bold">const</span> scene <span style="color: #666666">=</span> engine.createScene();
|
|
|
|
<span style="color: #408080; font-style: italic">// TODO: create material</span>
|
|
<span style="color: #408080; font-style: italic">// TODO: create sphere</span>
|
|
<span style="color: #408080; font-style: italic">// TODO: create lights</span>
|
|
<span style="color: #408080; font-style: italic">// TODO: create IBL</span>
|
|
<span style="color: #408080; font-style: italic">// TODO: create skybox</span>
|
|
|
|
<span style="color: #008000; font-weight: bold">this</span>.swapChain <span style="color: #666666">=</span> engine.createSwapChain();
|
|
<span style="color: #008000; font-weight: bold">this</span>.renderer <span style="color: #666666">=</span> engine.createRenderer();
|
|
<span style="color: #008000; font-weight: bold">this</span>.camera <span style="color: #666666">=</span> engine.createCamera(Filament.EntityManager.get().create());
|
|
<span style="color: #008000; font-weight: bold">this</span>.view <span style="color: #666666">=</span> engine.createView();
|
|
<span style="color: #008000; font-weight: bold">this</span>.view.setCamera(<span style="color: #008000; font-weight: bold">this</span>.camera);
|
|
<span style="color: #008000; font-weight: bold">this</span>.view.setScene(scene);
|
|
<span style="color: #008000; font-weight: bold">this</span>.resize();
|
|
<span style="color: #008000; font-weight: bold">this</span>.render <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>);
|
|
<span style="color: #008000; font-weight: bold">this</span>.resize <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>);
|
|
<span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">'resize'</span>, <span style="color: #008000; font-weight: bold">this</span>.resize);
|
|
<span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
|
|
}
|
|
|
|
render() {
|
|
<span style="color: #008000; font-weight: bold">const</span> eye <span style="color: #666666">=</span> [<span style="color: #666666">0</span>, <span style="color: #666666">0</span>, <span style="color: #666666">4</span>], center <span style="color: #666666">=</span> [<span style="color: #666666">0</span>, <span style="color: #666666">0</span>, <span style="color: #666666">0</span>], up <span style="color: #666666">=</span> [<span style="color: #666666">0</span>, <span style="color: #666666">1</span>, <span style="color: #666666">0</span>];
|
|
<span style="color: #008000; font-weight: bold">const</span> radians <span style="color: #666666">=</span> <span style="color: #008000">Date</span>.now() <span style="color: #666666">/</span> <span style="color: #666666">10000</span>;
|
|
vec3.rotateY(eye, eye, center, radians);
|
|
<span style="color: #008000; font-weight: bold">this</span>.camera.lookAt(eye, center, up);
|
|
<span style="color: #008000; font-weight: bold">this</span>.renderer.render(<span style="color: #008000; font-weight: bold">this</span>.swapChain, <span style="color: #008000; font-weight: bold">this</span>.view);
|
|
<span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
|
|
}
|
|
|
|
resize() {
|
|
<span style="color: #008000; font-weight: bold">const</span> dpr <span style="color: #666666">=</span> <span style="color: #008000">window</span>.devicePixelRatio;
|
|
<span style="color: #008000; font-weight: bold">const</span> width <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.canvas.width <span style="color: #666666">=</span> <span style="color: #008000">window</span>.innerWidth <span style="color: #666666">*</span> dpr;
|
|
<span style="color: #008000; font-weight: bold">const</span> height <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.canvas.height <span style="color: #666666">=</span> <span style="color: #008000">window</span>.innerHeight <span style="color: #666666">*</span> dpr;
|
|
<span style="color: #008000; font-weight: bold">this</span>.view.setViewport([<span style="color: #666666">0</span>, <span style="color: #666666">0</span>, width, height]);
|
|
<span style="color: #008000; font-weight: bold">this</span>.camera.setProjectionFov(<span style="color: #666666">45</span>, width <span style="color: #666666">/</span> height, <span style="color: #666666">1.0</span>, <span style="color: #666666">10.0</span>, Fov.VERTICAL);
|
|
}
|
|
}
|
|
</pre></div>
|
|
|
|
<p>The above boilerplate should be familiar to you from the previous tutorial, although it loads in a
|
|
new set of assets. We also added some animation to the camera.</p>
|
|
<p>Next let's create a material instance from the package that we built at the beginning the tutorial.
|
|
Replace the <strong>create material</strong> comment with the following snippet.</p>
|
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span></span><span style="color: #008000; font-weight: bold">const</span> material <span style="color: #666666">=</span> engine.createMaterial(filamat_url);
|
|
<span style="color: #008000; font-weight: bold">const</span> matinstance <span style="color: #666666">=</span> material.createInstance();
|
|
|
|
<span style="color: #008000; font-weight: bold">const</span> red <span style="color: #666666">=</span> [<span style="color: #666666">0.8</span>, <span style="color: #666666">0.0</span>, <span style="color: #666666">0.0</span>];
|
|
matinstance.setColor3Parameter(<span style="color: #BA2121">'baseColor'</span>, Filament.RgbType.sRGB, red);
|
|
matinstance.setFloatParameter(<span style="color: #BA2121">'roughness'</span>, <span style="color: #666666">0.5</span>);
|
|
matinstance.setFloatParameter(<span style="color: #BA2121">'clearCoat'</span>, <span style="color: #666666">1.0</span>);
|
|
matinstance.setFloatParameter(<span style="color: #BA2121">'clearCoatRoughness'</span>, <span style="color: #666666">0.3</span>);
|
|
</pre></div>
|
|
|
|
<p>The next step is to create a renderable for the sphere. To help with this, we'll use the <code>IcoSphere</code>
|
|
utility class, whose constructor takes a LOD. Its job is to subdivide an icosadedron, producing
|
|
three arrays:</p>
|
|
<ul>
|
|
<li><code>icosphere.vertices</code> Float32Array of XYZ coordinates.</li>
|
|
<li><code>icosphere.tangents</code> Uint16Array (interpreted as half-floats) encoding the surface orientation
|
|
as quaternions.</li>
|
|
<li><code>icosphere.triangles</code> Uint16Array with triangle indices.</li>
|
|
</ul>
|
|
<p>Let's go ahead use these arrays to build the vertex buffer and index buffer. Replace <strong>create
|
|
sphere</strong> with the following snippet.</p>
|
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span></span><span style="color: #008000; font-weight: bold">const</span> renderable <span style="color: #666666">=</span> Filament.EntityManager.get().create();
|
|
scene.addEntity(renderable);
|
|
|
|
<span style="color: #008000; font-weight: bold">const</span> icosphere <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">new</span> Filament.IcoSphere(<span style="color: #666666">5</span>);
|
|
|
|
<span style="color: #008000; font-weight: bold">const</span> vb <span style="color: #666666">=</span> Filament.VertexBuffer.Builder()
|
|
.vertexCount(icosphere.vertices.length <span style="color: #666666">/</span> <span style="color: #666666">3</span>)
|
|
.bufferCount(<span style="color: #666666">2</span>)
|
|
.attribute(VertexAttribute.POSITION, <span style="color: #666666">0</span>, AttributeType.FLOAT3, <span style="color: #666666">0</span>, <span style="color: #666666">0</span>)
|
|
.attribute(VertexAttribute.TANGENTS, <span style="color: #666666">1</span>, AttributeType.SHORT4, <span style="color: #666666">0</span>, <span style="color: #666666">0</span>)
|
|
.normalized(VertexAttribute.TANGENTS)
|
|
.build(engine);
|
|
|
|
<span style="color: #008000; font-weight: bold">const</span> ib <span style="color: #666666">=</span> Filament.IndexBuffer.Builder()
|
|
.indexCount(icosphere.triangles.length)
|
|
.bufferType(IndexType.USHORT)
|
|
.build(engine);
|
|
|
|
vb.setBufferAt(engine, <span style="color: #666666">0</span>, icosphere.vertices);
|
|
vb.setBufferAt(engine, <span style="color: #666666">1</span>, icosphere.tangents);
|
|
ib.setBuffer(engine, icosphere.triangles);
|
|
|
|
Filament.RenderableManager.Builder(<span style="color: #666666">1</span>)
|
|
.boundingBox({ center<span style="color: #666666">:</span> [<span style="color: #666666">-1</span>, <span style="color: #666666">-1</span>, <span style="color: #666666">-1</span>], halfExtent<span style="color: #666666">:</span> [<span style="color: #666666">1</span>, <span style="color: #666666">1</span>, <span style="color: #666666">1</span>] })
|
|
.material(<span style="color: #666666">0</span>, matinstance)
|
|
.geometry(<span style="color: #666666">0</span>, PrimitiveType.TRIANGLES, vb, ib)
|
|
.build(engine, renderable);
|
|
</pre></div>
|
|
|
|
<p>At this point, the app is rendering a sphere, but it is black so it doesn't show up. To prove that
|
|
the sphere is there, you can try changing the background color to blue via <code>setClearColor</code>, like we
|
|
did in the first tutorial.</p>
|
|
<h2>Add lighting</h2>
|
|
<p>In this section we will create some directional light sources, as well as an image-based light (IBL)
|
|
defined by one of the KTX files we built at the start of the demo. First, replace the <strong>create
|
|
lights</strong> comment with the following snippet.</p>
|
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span></span><span style="color: #008000; font-weight: bold">const</span> sunlight <span style="color: #666666">=</span> Filament.EntityManager.get().create();
|
|
scene.addEntity(sunlight);
|
|
Filament.LightManager.Builder(LightType.SUN)
|
|
.color([<span style="color: #666666">0.98</span>, <span style="color: #666666">0.92</span>, <span style="color: #666666">0.89</span>])
|
|
.intensity(<span style="color: #666666">110000.0</span>)
|
|
.direction([<span style="color: #666666">0.6</span>, <span style="color: #666666">-1.0</span>, <span style="color: #666666">-0.8</span>])
|
|
.sunAngularRadius(<span style="color: #666666">1.9</span>)
|
|
.sunHaloSize(<span style="color: #666666">10.0</span>)
|
|
.sunHaloFalloff(<span style="color: #666666">80.0</span>)
|
|
.build(engine, sunlight);
|
|
|
|
<span style="color: #008000; font-weight: bold">const</span> backlight <span style="color: #666666">=</span> Filament.EntityManager.get().create();
|
|
scene.addEntity(backlight);
|
|
Filament.LightManager.Builder(LightType.DIRECTIONAL)
|
|
.direction([<span style="color: #666666">-1</span>, <span style="color: #666666">0</span>, <span style="color: #666666">1</span>])
|
|
.intensity(<span style="color: #666666">50000.0</span>)
|
|
.build(engine, backlight);
|
|
</pre></div>
|
|
|
|
<p>The <code>SUN</code> light source is similar to the <code>DIRECTIONAL</code> light source, but has some extra
|
|
parameters because Filament will automatically draw a disk into the skybox.</p>
|
|
<p>Next we need to create an <code>IndirectLight</code> object from the KTX IBL. One way of doing this is the
|
|
following (don't type this out, there's an easier way).</p>
|
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span></span><span style="color: #008000; font-weight: bold">const</span> format <span style="color: #666666">=</span> Filament.PixelDataFormat.RGB;
|
|
<span style="color: #008000; font-weight: bold">const</span> datatype <span style="color: #666666">=</span> Filament.PixelDataType.UINT_10F_11F_11F_REV;
|
|
|
|
<span style="color: #408080; font-style: italic">// Create a Texture object for the mipmapped cubemap.</span>
|
|
<span style="color: #008000; font-weight: bold">const</span> ibl_package <span style="color: #666666">=</span> Filament.Buffer(Filament.assets[ibl_url]);
|
|
<span style="color: #008000; font-weight: bold">const</span> iblktx <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">new</span> Filament.KtxBundle(ibl_package);
|
|
|
|
<span style="color: #008000; font-weight: bold">const</span> ibltex <span style="color: #666666">=</span> Filament.Texture.Builder()
|
|
.width(iblktx.info().pixelWidth)
|
|
.height(iblktx.info().pixelHeight)
|
|
.levels(iblktx.getNumMipLevels())
|
|
.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP)
|
|
.format(Filament.Texture$InternalFormat.RGBA8)
|
|
.build(engine);
|
|
|
|
<span style="color: #008000; font-weight: bold">for</span> (<span style="color: #008000; font-weight: bold">let</span> level <span style="color: #666666">=</span> <span style="color: #666666">0</span>; level <span style="color: #666666"><</span> iblktx.getNumMipLevels(); <span style="color: #666666">++</span>level) {
|
|
<span style="color: #008000; font-weight: bold">const</span> uint8array <span style="color: #666666">=</span> iblktx.getCubeBlob(level).getBytes();
|
|
<span style="color: #008000; font-weight: bold">const</span> pixelbuffer <span style="color: #666666">=</span> Filament.PixelBuffer(uint8array, format, datatype);
|
|
ibltex.setImageCube(engine, level, pixelbuffer);
|
|
}
|
|
|
|
<span style="color: #408080; font-style: italic">// Parse the spherical harmonics metadata.</span>
|
|
<span style="color: #008000; font-weight: bold">const</span> shstring <span style="color: #666666">=</span> iblktx.getMetadata(<span style="color: #BA2121">'sh'</span>);
|
|
<span style="color: #008000; font-weight: bold">const</span> shfloats <span style="color: #666666">=</span> shstring.split(<span style="color: #BB6688">/\s/</span>, <span style="color: #666666">9</span> <span style="color: #666666">*</span> <span style="color: #666666">3</span>).map(<span style="color: #008000">parseFloat</span>);
|
|
|
|
<span style="color: #408080; font-style: italic">// Build the IBL object and insert it into the scene.</span>
|
|
<span style="color: #008000; font-weight: bold">const</span> indirectLight <span style="color: #666666">=</span> Filament.IndirectLight.Builder()
|
|
.reflections(ibltex)
|
|
.irradianceSh(<span style="color: #666666">3</span>, shfloats)
|
|
.intensity(<span style="color: #666666">50000.0</span>)
|
|
.build(engine);
|
|
|
|
scene.setIndirectLight(indirectLight);
|
|
</pre></div>
|
|
|
|
<p>Filament provides a JavaScript utility to make this simpler,
|
|
simply replace the <strong>create IBL</strong> comment with the following snippet.</p>
|
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span></span><span style="color: #008000; font-weight: bold">const</span> indirectLight <span style="color: #666666">=</span> engine.createIblFromKtx(ibl_url);
|
|
indirectLight.setIntensity(<span style="color: #666666">50000</span>);
|
|
scene.setIndirectLight(indirectLight);
|
|
</pre></div>
|
|
|
|
<h2>Add background</h2>
|
|
<p>At this point you can run the demo and you should see a red plastic ball against a black background.
|
|
Without a skybox, the reflections on the ball are not representative of its surroundings.
|
|
Here's one way to create a texture for the skybox:</p>
|
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span></span><span style="color: #008000; font-weight: bold">const</span> sky_package <span style="color: #666666">=</span> Filament.Buffer(Filament.assets[sky_url]);
|
|
<span style="color: #008000; font-weight: bold">const</span> skyktx <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">new</span> Filament.KtxBundle(sky_package);
|
|
<span style="color: #008000; font-weight: bold">const</span> skytex <span style="color: #666666">=</span> Filament.Texture.Builder()
|
|
.width(skyktx.info().pixelWidth)
|
|
.height(skyktx.info().pixelHeight)
|
|
.levels(<span style="color: #666666">1</span>)
|
|
.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP)
|
|
.format(Filament.Texture$InternalFormat.RGBA8)
|
|
.build(engine);
|
|
|
|
<span style="color: #008000; font-weight: bold">const</span> uint8array <span style="color: #666666">=</span> skyktx.getCubeBlob(<span style="color: #666666">0</span>).getBytes();
|
|
<span style="color: #008000; font-weight: bold">const</span> pixelbuffer <span style="color: #666666">=</span> Filament.PixelBuffer(uint8array, format, datatype);
|
|
skytex.setImageCube(engine, <span style="color: #666666">0</span>, pixelbuffer);
|
|
</pre></div>
|
|
|
|
<p>Filament provides a Javascript utility to make this easier.
|
|
Replace <strong>create skybox</strong> with the following.</p>
|
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span></span><span style="color: #008000; font-weight: bold">const</span> skybox <span style="color: #666666">=</span> engine.createSkyFromKtx(sky_url);
|
|
scene.setSkybox(skybox);
|
|
</pre></div>
|
|
|
|
<p>That's it, we now have a shiny red ball floating in an environment! The complete JavaScript file is
|
|
available <a href="tutorial_redball.js">here</a>.</p>
|
|
<p>In the <a href="tutorial_suzanne.html">next tutorial</a>, we'll take a closer look at textures and interaction.</p>
|
|
|
|
</body>
|
|
</html>
|