diff --git a/site/content/webgl/index.md b/site/content/webgl/index.md index f0a7b64cd1..e63cb5a150 100644 --- a/site/content/webgl/index.md +++ b/site/content/webgl/index.md @@ -4,15 +4,19 @@ date: 2018-10-30T13:13:14-07:00 menu: main --- -## documentation +## tutorials -- [JavaScript API reference](https://google.github.io/filament/webgl/reference.html) -- [Triangle Tutorial](https://google.github.io/filament/webgl/tutorial_triangle.html) -- [Redball Tutorial](https://google.github.io/filament/webgl/tutorial_redball.html) -- [WebGL Meetup Slides](https://prideout.net/slides/filawasm) (2018) +1. [Triangle Tutorial](https://google.github.io/filament/webgl/tutorial_triangle.html) +2. [Redball Tutorial](https://google.github.io/filament/webgl/tutorial_redball.html) +3. [Suzanne Tutorial](https://google.github.io/filament/webgl/tutorial_suzanne.html) ## demos - [parquet](https://google.github.io/filament/webgl/parquet.html) - [suzanne](https://google.github.io/filament/webgl/suzanne.html) - [knotess](https://prideout.net/knotess/) + +## other documentation + +- [JavaScript API reference](https://google.github.io/filament/webgl/reference.html) +- [WebGL Meetup Slides](https://prideout.net/slides/filawasm) (2018) diff --git a/web/docs/CMakeLists.txt b/web/docs/CMakeLists.txt index 09489349db..fc6a3f0702 100644 --- a/web/docs/CMakeLists.txt +++ b/web/docs/CMakeLists.txt @@ -11,7 +11,7 @@ else() set(CUSTOM_OUTPUTS) set(CUSTOM_INPUTS) - foreach (NAME triangle redball) + foreach (NAME triangle redball suzanne) list(APPEND CUSTOM_OUTPUTS ${PROJECT_BINARY_DIR}/demo_${NAME}.html) list(APPEND CUSTOM_OUTPUTS ${PROJECT_BINARY_DIR}/tutorial_${NAME}.html) list(APPEND CUSTOM_OUTPUTS ${PROJECT_BINARY_DIR}/tutorial_${NAME}.js) diff --git a/web/docs/build.py b/web/docs/build.py index 6ff0678e80..cd1a8baca5 100755 --- a/web/docs/build.py +++ b/web/docs/build.py @@ -495,7 +495,7 @@ if __name__ == "__main__": ENABLE_EMBEDDED_DEMO = not args.disable_demo os.makedirs(os.path.realpath(OUTPUT_DIR), exist_ok=True) - for name in ["triangle", "redball"]: + for name in ["triangle", "redball", "suzanne"]: weave(name) tangle(name) generate_demo_html(name) diff --git a/web/docs/demo_template.html b/web/docs/demo_template.html index 96e7fd1277..34d1223c5d 100644 --- a/web/docs/demo_template.html +++ b/web/docs/demo_template.html @@ -14,6 +14,7 @@ + \ No newline at end of file diff --git a/web/docs/textured.mat b/web/docs/textured.mat new file mode 100644 index 0000000000..4e21e5b734 --- /dev/null +++ b/web/docs/textured.mat @@ -0,0 +1,25 @@ +material { + name : textured, + requires : [ uv0 ], + shadingModel : lit, + parameters : [ + { type : sampler2d, name : albedo }, + { type : sampler2d, name : roughness }, + { type : sampler2d, name : metallic }, + { type : float, name : clearCoat }, + { type : sampler2d, name : normal }, + { type : sampler2d, name : ao } + ], +} + +fragment { + void material(inout MaterialInputs material) { + material.normal = texture(materialParams_normal, getUV0()).xyz * 2.0 - 1.0; + prepareMaterial(material); + material.baseColor = texture(materialParams_albedo, getUV0()); + material.roughness = texture(materialParams_roughness, getUV0()).r; + material.metallic = texture(materialParams_metallic, getUV0()).r; + material.clearCoat = materialParams.clearCoat; + material.ambientOcclusion = texture(materialParams_ao, getUV0()).r; + } +} diff --git a/web/docs/tutorial_redball.md b/web/docs/tutorial_redball.md index 60c8bdc1ea..069bbee60e 100644 --- a/web/docs/tutorial_redball.md +++ b/web/docs/tutorial_redball.md @@ -1,8 +1,11 @@ -This tutorial will describe how to create the redball demo, introducing you to materials and +This tutorial will describe how to create the **redball** demo, introducing you to materials and textures. -You'll need to use a couple command-line tools: `matc` and `cmgen`. You can find these in the +For starters, create a text file called `redball.html` and copy over the HTML that we used in the +[previous tutorial]. Change the last script tag from `triangle.js` to `redball.js`. + +Next you'll need to get a couple command-line tools: `matc` and `cmgen`. You can find these in the appropriate [Filament release](//github.com/google/filament/releases). You should choose the archive that corresponds to your development machine rather than the one for web. @@ -10,7 +13,7 @@ archive that corresponds to your development machine rather than the one for web The `matc` 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 [Filament Material System](). +information, see the official document describing the [Filament Material System]. Let's try out `matc`. Create the following file in your favorite text editor and call it `plastic.mat`. @@ -52,9 +55,6 @@ tutorial. Next we'll use Filament's `cmgen` tool to consume a HDR environment map in latlong format, and produce two cubemap files: a mipmapped IBL and a blurry skybox. -[pillars_2k.hdr]: -//github.com/google/filament/blob/master/third_party/environments/pillars_2k.hdr - Download [pillars_2k.hdr], then invoke the following command in your terminal. ```bash @@ -62,19 +62,20 @@ cmgen -x . --format=ktx --size=256 --extract-blur=0.1 pillars_2k.hdr ``` You should now have a `pillars_2k` folder containing a couple KTX files for the IBL and skybox, as -well as a text file with spherical harmonics coefficients. Move the KTX files into your project -folder. You can discard the text file because the IBL KTX contains these coefficients in its -metadata. +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. -## Create HTML and JavaScript - -Create a text file called `redball.html` and copy over the HTML that we used in the [previous -tutorial](tutorial_triangle.html). Change the last script tag from `triangle.js` to `redball.js`. +## Create JavaScript Next, create `redball.js` with the following content. ```js {fragment="root"} -Filament.init([ 'plastic.filamat', 'pillars_2k_ibl.ktx', 'pillars_2k_skybox.ktx' ], () => { +const environ = 'pillars_2k'; +const ibl_url = `${environ}/${environ}_ibl.ktx`; +const sky_url = `${environ}/${environ}_skybox.ktx`; +const filamat_url = 'plastic.filamat' + +Filament.init([ filamat_url, ibl_url, sky_url ], () => { // Create some global aliases to enums for convenience. window.VertexAttribute = Filament.VertexAttribute; window.AttributeType = Filament.VertexBuffer$AttributeType; @@ -109,7 +110,7 @@ class App { this.resize(); this.render = this.render.bind(this); this.resize = this.resize.bind(this); - window.addEventListener("resize", this.resize); + window.addEventListener('resize', this.resize); window.requestAnimationFrame(this.render); } @@ -139,14 +140,14 @@ Next let's create a material instance from the package that we built at the begi Replace the **create material** comment with the following snippet. ```js {fragment="create material"} -const material = engine.createMaterial('plastic.filamat'); +const material = engine.createMaterial(filamat_url); const matinstance = material.createInstance(); const red = [0.8, 0.0, 0.0]; -matinstance.setColorParameter("baseColor", Filament.RgbType.sRGB, red); -matinstance.setFloatParameter("roughness", 0.5); -matinstance.setFloatParameter("clearCoat", 1.0); -matinstance.setFloatParameter("clearCoatRoughness", 0.3); +matinstance.setColorParameter('baseColor', Filament.RgbType.sRGB, red); +matinstance.setFloatParameter('roughness', 0.5); +matinstance.setFloatParameter('clearCoat', 1.0); +matinstance.setFloatParameter('clearCoatRoughness', 0.3); ``` The next step is to create a renderable for the sphere. To help with this, we'll use the `IcoSphere` @@ -232,7 +233,7 @@ const format = Filament.PixelDataFormat.RGBM; const datatype = Filament.PixelDataType.UBYTE; // Create a Texture object for the mipmapped cubemap. -const ibl_package = Filament.Buffer(Filament.assets['pillars_2k_ibl.ktx']); +const ibl_package = Filament.Buffer(Filament.assets[ibl_url]); const iblktx = new Filament.KtxBundle(ibl_package); const ibltex = Filament.Texture.Builder() @@ -251,7 +252,7 @@ for (let level = 0; level < iblktx.getNumMipLevels(); ++level) { } // Parse the spherical harmonics metadata. -const shstring = iblktx.getMetadata("sh"); +const shstring = iblktx.getMetadata('sh'); const shfloats = shstring.split(/\s/, 9 * 3).map(parseFloat); // Build the IBL object and insert it into the scene. @@ -268,7 +269,7 @@ Filament provides a JavaScript utility to make this simpler, simply replace the **create IBL** comment with the following snippet. ```js {fragment="create IBL"} -const indirectLight = engine.createIblFromKtx('pillars_2k_ibl.ktx'); +const indirectLight = engine.createIblFromKtx(ibl_url); indirectLight.setIntensity(50000); scene.setIndirectLight(indirectLight); ``` @@ -280,7 +281,7 @@ Without a skybox, the reflections on the ball are not representative of its surr Here's one way to create a texture for the skybox: ```js -const sky_package = Filament.Buffer(Filament.assets['pillars_2k_skybox.ktx']); +const sky_package = Filament.Buffer(Filament.assets[sky_url]); const skyktx = new Filament.KtxBundle(sky_package); const skytex = Filament.Texture.Builder() .width(skyktx.info().pixelWidth) @@ -300,9 +301,19 @@ Filament provides a Javascript utility to make this easier. Replace **create skybox** with the following. ```js {fragment="create skybox"} -const skybox = engine.createSkyFromKtx('pillars_2k_skybox.ktx'); +const skybox = engine.createSkyFromKtx(sky_url); scene.setSkybox(skybox); ``` -That's it, we now have a shiny red ball floating in an environment! The complete JavaScript -file is available [here](tutorial_redball.js). +That's it, we now have a shiny red ball floating in an environment! The complete JavaScript file is +available [here](tutorial_redball.js). + +In the [next tutorial], we'll take a closer look at textures and interaction. + +[pillars_2k.hdr]: +//github.com/google/filament/blob/master/third_party/environments/pillars_2k.hdr + +[next tutorial]: tutorial_suzanne.html +[previous tutorial]: tutorial_triangle.html +[Filament release]: //github.com/google/filament/releases +[Filament Material System]: https://google.github.io/filament/Materials.md.html diff --git a/web/docs/tutorial_suzanne.md b/web/docs/tutorial_suzanne.md new file mode 100644 index 0000000000..60341085c6 --- /dev/null +++ b/web/docs/tutorial_suzanne.md @@ -0,0 +1,311 @@ + +This tutorial will describe how to create the **suzanne** demo, introducing you to compressed +textures, mipmap generation, asynchronous texture loading, and trackball rotation. + +Much like the [previous tutorial], you'll need to use the command-line tools that can be found in +the appropriate [Filament release] for your development machine. In addition to `matc` and `cmgen`, +we'll also be using `filamesh` and `mipgen`. + +## Create filamesh file + +Filament does not have an asset loading system, but it does provide a simple binary mesh format +called `filamesh` for demonstration purposes. Let's create a filamesh file for suzanne by converting +[this OBJ file]: + +```bash +filamesh monkey.obj suzanne.filamesh +``` + +## Create mipmapped textures + +Next, let's create mipmapped KTX files using filament's `mipgen` tool. We'll create compressed and +non-compressed variants for each texture, since not all platforms support the same compression +formats. First copy over the PNG files from the [monkey folder], then do: + +```bash +# Create mipmaps for base color and two compressed variants. +mipgen albedo.png albedo.ktx +mipgen --compression=astc_fast_ldr_4x4 albedo.png albedo_astc.ktx +mipgen --compression=s3tc_rgb_dxt1 albedo.png albedo_s3tc.ktx + +# Create mipmaps for the normal map and a compressed variant. +mipgen --kernel=NORMALS --linear normal.png normal.ktx +mipgen --kernel=NORMALS --linear --compression=etc_rgb8_normalxyz_40 normal.png normal_etc.ktx + +# Create mipmaps for the single-component roughness map and a compressed variant. +mipgen --grayscale roughness.png roughness.ktx +mipgen --grayscale --compression=etc_r11_numeric_40 roughness.png roughness_etc.ktx + +# Create mipmaps for the single-component metallic map and a compressed variant. +mipgen --grayscale metallic.png metallic.ktx +mipgen --grayscale --compression=etc_r11_numeric_40 metallic.png metallic_etc.ktx + +# Create mipmaps for the single-component occlusion map and a compressed variant. +mipgen --grayscale ao.png ao.ktx +mipgen --grayscale --compression=etc_r11_numeric_40 ao.png ao_etc.ktx +``` + +For more information on mipgen's arguments and supported formats, do `mipgen --help`. + +In a production setting, you'd want to invoke these commands with a script or build system. + +## Bake environment map + +Much like the [previous tutorial] we need to use Filament's `cmgen` tool to produce cubemap files, +but this time we'll create compressed variants. + +Download [syferfontein_18d_clear_2k.hdr], then invoke the following commands in your terminal. + +```bash +# Create S3TC variant of the IBL, then rename it to have a _s3tc suffix. +cmgen -x . --format=ktx --size=256 --extract-blur=0.1 --compression=s3tc_rgba_dxt5 \ + syferfontein_18d_clear_2k.hdr +cd syfer* ; mv syfer*_ibl.ktx syferfontein_18d_clear_2k_ibl_s3tc.ktx ; cd - + +# Create ETC variant of the IBL, then rename it to have a _s3tc suffix. +cmgen -x . --format=ktx --size=256 --extract-blur=0.1 --compression=etc_rgba8_rgba_40 \ + syferfontein_18d_clear_2k.hdr +cd syfer* ; mv syfer*_ibl.ktx syferfontein_18d_clear_2k_ibl_etc.ktx ; cd - + +# Create small uncompressed Skybox variant, then rename it to have a _tiny suffix. +cmgen -x . --format=ktx --size=64 --extract-blur=0.1 syferfontein_18d_clear_2k.hdr +cd syfer* ; mv syfer*_ibl.ktx syferfontein_18d_clear_2k_skybox_tiny.ktx ; cd - + +# Create full-size uncompressed Skybox and IBL +cmgen -x . --format=ktx --size=256 --extract-blur=0.1 syferfontein_18d_clear_2k.hdr +``` + +## Define textured material + +You might recall the `filamat` file we generated in the previous tutorial for red plastic. For this +demo, we'll create a material that uses textures for several parameters. + +Create the following textz file call it `textured.mat`. Note that our material definition now +requires a `uv0` attribute. + +```text +material { + name : textured, + requires : [ uv0 ], + shadingModel : lit, + parameters : [ + { type : sampler2d, name : albedo }, + { type : sampler2d, name : roughness }, + { type : sampler2d, name : metallic }, + { type : float, name : clearCoat }, + { type : sampler2d, name : normal }, + { type : sampler2d, name : ao } + ], +} + +fragment { + void material(inout MaterialInputs material) { + material.normal = texture(materialParams_normal, getUV0()).xyz * 2.0 - 1.0; + prepareMaterial(material); + material.baseColor = texture(materialParams_albedo, getUV0()); + material.roughness = texture(materialParams_roughness, getUV0()).r; + material.metallic = texture(materialParams_metallic, getUV0()).r; + material.clearCoat = materialParams.clearCoat; + material.ambientOcclusion = texture(materialParams_ao, getUV0()).r; + } +} +``` + +Next, invoke `matc` as follows. + +```bash +matc -O -a opengl -p mobile -o textured.filamat textured.mat +``` + +You should now have a material archive in your working directory. For the suzanne asset, the normal +map adds scratches, the albedo map paints the eyes white, and so on. For more information on +materials, consult the official document describing the [Filament Material System]. + +## Create app skeleton + +Create a text file called `suzanne.html` and copy over the HTML that we used in the [previous +tutorial]. Change the last script tag from `redball.js` to `suzanne.js`. Next, create `suzanne.js` +with the following content. + +```js {fragment="root"} +// TODO: declare asset URLs + +Filament.init([ filamat_url, filamesh_url, sky_small_url, ibl_url ], () => { + window.app = new App(document.getElementsByTagName('canvas')[0]); +}); + +class App { + constructor(canvas) { + this.canvas = canvas; + this.engine = Filament.Engine.create(canvas); + this.scene = this.engine.createScene(); + + const material = this.engine.createMaterial(filamat_url); + this.matinstance = material.createInstance(); + + const filamesh = this.engine.loadFilamesh(filamesh_url, this.matinstance); + this.suzanne = filamesh.renderable; + + // TODO: create sky box and IBL + // TODO: initialize gltumble + // TODO: fetch larger assets + + this.swapChain = this.engine.createSwapChain(); + this.renderer = this.engine.createRenderer(); + this.camera = this.engine.createCamera(); + this.view = this.engine.createView(); + this.view.setCamera(this.camera); + this.view.setScene(this.scene); + this.render = this.render.bind(this); + this.resize = this.resize.bind(this); + window.addEventListener('resize', this.resize); + + const eye = [0, 0, 4], center = [0, 0, 0], up = [0, 1, 0]; + this.camera.lookAt(eye, center, up); + + this.resize(); + window.requestAnimationFrame(this.render); + } + + render() { + // TODO: apply gltumble matrix + this.renderer.render(this.swapChain, this.view); + window.requestAnimationFrame(this.render); + } + + resize() { + const dpr = window.devicePixelRatio; + const width = this.canvas.width = window.innerWidth * dpr; + const height = this.canvas.height = window.innerHeight * dpr; + this.view.setViewport([0, 0, width, height]); + + const aspect = width / height; + const Fov = Filament.Camera$Fov, fov = aspect < 1 ? Fov.HORIZONTAL : Fov.VERTICAL; + this.camera.setProjectionFov(45, aspect, 1.0, 10.0, fov); + } +} +``` + +Our app will use 10 downloaded assets, but it only requires 4 of them to be present for `App` +construction. We'll download the other 6 assets after construction. By using a progressive loading +strategy, we can reduce the perceived load time. + +Next we need to supply the URLs for various assets. This is actually a bit tricky, because different +clients have different capabilities for compressed textures. + +To help you download only the texture assets that you need, Filament provides a +`getSupportedFormatSuffix` function. This takes a space-separated list of desired format types +(`etc`, `s3tc`, or `astc`) that the app developer knows is available from the server. The function +performs an intersection of the *desired* set with the *supported* set, then returns an appropriate +string -- which might be empty. + +In our case, we know that our web server will have `etc` and `s3tc` variants for the IBL, `astc` and +`s3tc` variants for albedo, and `etc` variants for the other textures. The uncompressed variants +(empty string) are always available as a last resort. Go ahead and replace the **declare asset +URLs** comment with the following snippet. + +```js {fragment="declare asset URLs"} +const ibl_suffix = Filament.getSupportedFormatSuffix('etc s3tc'); +const albedo_suffix = Filament.getSupportedFormatSuffix('astc s3tc'); +const texture_suffix = Filament.getSupportedFormatSuffix('etc'); + +const environ = 'syferfontein_18d_clear_2k' +const ibl_url = `${environ}/${environ}_ibl${ibl_suffix}.ktx`; +const sky_small_url = `${environ}/${environ}_skybox_tiny.ktx`; +const sky_large_url = `${environ}/${environ}_skybox.ktx`; +const albedo_url = `albedo${albedo_suffix}.ktx`; +const ao_url = `ao${texture_suffix}.ktx`; +const metallic_url = `metallic${texture_suffix}.ktx`; +const normal_url = `normal${texture_suffix}.ktx`; +const roughness_url = `roughness${texture_suffix}.ktx`; +const filamat_url = 'textured.filamat'; +const filamesh_url = 'suzanne.filamesh'; +``` + +## Create skybox and IBL + +Next, let's create the low-resolution skybox and IBL in the `App` constructor. + +```js {fragment="create sky box and IBL"} +this.skybox = this.engine.createSkyFromKtx(sky_small_url); +this.scene.setSkybox(this.skybox); +this.indirectLight = this.engine.createIblFromKtx(ibl_url); +this.indirectLight.setIntensity(100000); +this.scene.setIndirectLight(this.indirectLight); +``` + +This allows users to see a reasonable background fairly quickly, before larger assets have finished +loading in. + +## Fetch assets asychronously + +Next we'll invoke the `Filament.fetch` function from within the app constructor. This function is +very similar to `Filament.init`. It takes a list of asset URLs and a callback function that triggers +when the assets have finished downloading. + +In our callback, we'll make several `setTextureParameter` calls on the material instance, then we'll +recreate the skybox using a higher-resolution texture. As a last step we unhide the renderable that +was created in the app constructor. + +```js {fragment="fetch larger assets"} +Filament.fetch([sky_large_url, albedo_url, roughness_url, metallic_url, normal_url, ao_url], () => { + const albedo = this.engine.createTextureFromKtx(albedo_url, {srgb: true}); + const roughness = this.engine.createTextureFromKtx(roughness_url); + const metallic = this.engine.createTextureFromKtx(metallic_url); + const normal = this.engine.createTextureFromKtx(normal_url); + const ao = this.engine.createTextureFromKtx(ao_url); + + const sampler = new Filament.TextureSampler( + Filament.MinFilter.LINEAR_MIPMAP_LINEAR, + Filament.MagFilter.LINEAR, + Filament.WrapMode.CLAMP_TO_EDGE); + + this.matinstance.setTextureParameter('albedo', albedo, sampler); + this.matinstance.setTextureParameter('roughness', roughness, sampler); + this.matinstance.setTextureParameter('metallic', metallic, sampler); + this.matinstance.setTextureParameter('normal', normal, sampler); + this.matinstance.setTextureParameter('ao', ao, sampler); + + // Replace low-res skybox with high-res skybox. + this.engine.destroySkybox(this.skybox); + this.skybox = this.engine.createSkyFromKtx(sky_large_url); + this.scene.setSkybox(this.skybox); + + this.scene.addEntity(this.suzanne); +}); +``` + +## Introduce trackball rotation + +Add the following script tag to your HTML file. This imports a small third-party library that +listens for drag events and computes a rotation matrix. + +```html + +``` + +Next, replace the **initialize gltumble** and **apply gltumble matrix** comments with the following +two code snippets. + +```js {fragment="initialize gltumble"} +this.trackball = new Trackball(canvas, {startSpin: 0.035}); +``` + +```js {fragment="apply gltumble matrix"} +const tcm = this.engine.getTransformManager(); +const inst = tcm.getInstance(this.suzanne); +tcm.setTransform(inst, this.trackball.getMatrix()); +inst.delete(); +``` + +That's it, we now have a fast-loading interactive demo. The complete JavaScript file is available +[here](tutorial_suzanne.js). + +[Filament release]: //github.com/google/filament/releases +[previous tutorial]: tutorial_redball.html +[Filament Material System]: https://google.github.io/filament/Materials.md.html +[this OBJ file]: https://github.com/google/filament/blob/master/assets/models/monkey/monkey.obj +[monkey folder]: https://github.com/google/filament/blob/master/assets/models/monkey + +[syferfontein_18d_clear_2k.hdr]: +//github.com/google/filament/blob/master/third_party/environments/syferfontein_18d_clear_2k.hdr diff --git a/web/docs/tutorial_triangle.md b/web/docs/tutorial_triangle.md index aeba4d5726..1cf2a6744b 100644 --- a/web/docs/tutorial_triangle.md +++ b/web/docs/tutorial_triangle.md @@ -39,7 +39,7 @@ class App { // TODO: create entities this.render = this.render.bind(this); this.resize = this.resize.bind(this); - window.addEventListener("resize", this.resize); + window.addEventListener('resize', this.resize); window.requestAnimationFrame(this.render); } render() { @@ -71,16 +71,20 @@ that define a PBR material. We'll learn more about material packages in the next ## Spawn a local server Because of CORS restrictions, your web app cannot fetch the material package directly from the -file system. One way around this is to create a temporary server using Python: +file system. One way around this is to create a temporary server using Python or node: ```bash python3 -m http.server # Python 3 python -m SimpleHTTPServer # Python 2.7 +npx http-server -p 8000 # nodejs ``` To see if this works, navigate to [http://localhost:8000](http://localhost:8000) and check if you can load the page without any errors appearing in the developer console. +Take care not to use Python's simple server in production since it does not serve WebAssembly files +with the correct MIME type. + ## Create the Engine and Scene We now have a basic skeleton that can respond to paint and resize events. Let's start adding @@ -257,5 +261,8 @@ this.camera.setProjection(Projection.ORTHO, -aspect, aspect, -1, 1, 0, 1); ``` You should now have a spinning triangle! The completed JavaScript is available -[here](tutorial_triangle.js). In the next tutorial, we'll take a closer look at Filament -materials and 3D rendering. +[here](tutorial_triangle.js). + +In the [next tutorial], we'll take a closer look at Filament materials and 3D rendering. + +[next tutorial]: tutorial_redball.html diff --git a/web/samples/CMakeLists.txt b/web/samples/CMakeLists.txt index ce76973c6f..a2efb34728 100644 --- a/web/samples/CMakeLists.txt +++ b/web/samples/CMakeLists.txt @@ -90,6 +90,7 @@ add_mesh("third_party/shader_ball/shader_ball.obj" "shader_ball.filamesh") # Generate IBL and skybox images using cmgen. set(CMGEN_ARGS -x . --format=ktx --size=256 --extract-blur=0.1) +set(CMGEN_ARGS_TINY -x . --format=ktx --size=64 --extract-blur=0.1) set(CMGEN_ARGS_S3TC ${CMGEN_ARGS} --compression=s3tc_rgba_dxt5) set(CMGEN_ARGS_ETC ${CMGEN_ARGS} --compression=etc_rgba8_rgba_40) function(add_envmap SOURCE TARGET) @@ -103,12 +104,14 @@ function(add_envmap SOURCE TARGET) set(target_envmap_etc "${SERVER_DIR}/${TARGET}/${TARGET}_ibl_etc.ktx") set(target_envmap_s3tc "${SERVER_DIR}/${TARGET}/${TARGET}_ibl_s3tc.ktx") - set(target_skyboxes ${target_skyboxes} ${target_skybox} PARENT_SCOPE) + set(target_skybox_tiny "${SERVER_DIR}/${TARGET}/${TARGET}_skybox_tiny.ktx") + + set(target_skyboxes ${target_skyboxes} ${target_skybox} ${target_skybox_tiny} PARENT_SCOPE) set(target_envmaps ${target_envmaps} ${target_envmap} ${target_envmap_etc} ${target_envmap_s3tc} PARENT_SCOPE) - add_custom_command(OUTPUT ${target_skybox} + add_custom_command(OUTPUT ${target_skybox} ${target_skybox_tiny} ${target_envmap} ${target_envmap_etc} ${target_envmap_s3tc} # First create an S3TC-encoded envmap, then rename it. @@ -119,6 +122,10 @@ function(add_envmap SOURCE TARGET) COMMAND cmgen ${CMGEN_ARGS_ETC} ${source_envmap} COMMAND mv ${target_envmap} ${target_envmap_etc} + # Create a low-resolution skybox, then rename it. + COMMAND cmgen ${CMGEN_ARGS_TINY} ${source_envmap} + COMMAND mv ${target_skybox} ${target_skybox_tiny} + # Finally, create KTX files for the uncompressed envmap. COMMAND cmgen ${CMGEN_ARGS} ${source_envmap}