Skip to content

Commit

Permalink
Manual: Fix remaining RGBFormat issues. (#23390)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mugen87 authored Jan 30, 2022
1 parent 28b4add commit f31cb9e
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 66 deletions.
60 changes: 31 additions & 29 deletions manual/en/indexed-textures.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ <h1>Indexed Textures for Picking and Color</h1>
the user select a country and show their selection?</p>
<p>The first idea that comes to mind is to generate geometry for each country.
We could <a href="picking.html">use a picking solution</a> like we covered before.
We'd build 3D geometry for each country. If the user clicks on the mesh for
We'd build 3D geometry for each country. If the user clicks on the mesh for
that country we'd know what country was clicked.</p>
<p>So, just to check that solution I tried generating 3D meshes of all the countries
using the same data I used to generate the outlines
using the same data I used to generate the outlines
<a href="align-html-elements-to-3d.html">in the previous article</a>.
The result was a 15.5meg binary GLTF (.glb) file. Making the user download 15.5meg
sounds like too much to me.</p>
Expand All @@ -53,25 +53,25 @@ <h1>Indexed Textures for Picking and Color</h1>
win. For a borders of Canada probably much less. </p>
<p>Another solution would be to use just actual data compression. For example gzipping
the file brought it down to 11meg. That's 30% less but arguably not enough.</p>
<p>We could store all the data as 16bit ranged values instead of 32bit float values.
<p>We could store all the data as 16bit ranged values instead of 32bit float values.
Or we could use something like <a href="https://google.github.io/draco/">draco compression</a>
and maybe that would be enough. I didn't check and I would encourage you to check
and maybe that would be enough. I didn't check and I would encourage you to check
yourself and tell me how it goes as I'd love to know. 😅</p>
<p>In my case I thought about <a href="picking.html">the GPU picking solution</a>
<p>In my case I thought about <a href="picking.html">the GPU picking solution</a>
we covered at the end of <a href="picking.html">the article on picking</a>. In
that solution we drew every mesh with a unique color that represented that
mesh's id. We then drew all the meshes and looked at the color that was clicked
on.</p>
<p>Taking inspiration from that we could pre-generate a map of countries where
each country's color is its index number in our array of countries. We could
then use a similar GPU picking technique. We'd draw the globe off screen using
this index texture. Looking at the color of the pixel the user clicks would
this index texture. Looking at the color of the pixel the user clicks would
tell us the country id.</p>
<p>So, I <a href="https://github.com/mrdoob/three.js/blob/master/manual/resources/tools/geo-picking/">wrote some code</a>
<p>So, I <a href="https://github.com/mrdoob/three.js/blob/master/manual/resources/tools/geo-picking/">wrote some code</a>
to generate such a texture. Here it is. </p>
<div class="threejs_center"><img src="../examples/resources/data/world/country-index-texture.png" style="width: 700px;"></div>

<p>Note: The data used to generate this texture comes from <a href="http://thematicmapping.org/downloads/world_borders.php">this website</a>
<p>Note: The data used to generate this texture comes from <a href="http://thematicmapping.org/downloads/world_borders.php">this website</a>
and is therefore licensed as <a href="http://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>.</p>
<p>It's only 217k, much better than the 14meg for the country meshes. In fact we could probably
even lower the resolution but 217k seems good enough for now.</p>
Expand Down Expand Up @@ -244,22 +244,22 @@ <h1>Indexed Textures for Picking and Color</h1>
<p></p>
<p>The code stills shows countries based on their area but if you
click one just that one will have a label.</p>
<p>So that seems like a reasonable solution for picking countries
<p>So that seems like a reasonable solution for picking countries
but what about highlighting the selected countries?</p>
<p>For that we can take inspiration from <em>paletted graphics</em>.</p>
<p><a href="https://en.wikipedia.org/wiki/Palette_%28computing%29">Paletted graphics</a>
or <a href="https://en.wikipedia.org/wiki/Indexed_color">Indexed Color</a> is
what older systems like the Atari 800, Amiga, NES,
or <a href="https://en.wikipedia.org/wiki/Indexed_color">Indexed Color</a> is
what older systems like the Atari 800, Amiga, NES,
Super Nintendo, and even older IBM PCs used. Instead of storing bitmaps
as RGB colors 8bits per color, 24 bytes per pixel or more, they stored
as RGBA colors 8bits per color, 32 bytes per pixel or more, they stored
bitmaps as 8bit values or less. The value for each pixel was an index
into a palette. So for example a value
of 3 in the image means "display color 3". What color color#3 is is
defined somewhere else called a "palette".</p>
<p>In JavaScript you can think of it like this</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const face7x7PixelImageData = [
0, 1, 1, 1, 1, 1, 0,
1, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 1,
1, 0, 2, 0, 2, 0, 1,
1, 0, 0, 0, 0, 0, 1,
1, 0, 3, 3, 3, 0, 1,
Expand All @@ -284,8 +284,8 @@ <h1>Indexed Textures for Picking and Color</h1>
texture we can color each individual country. For example by setting
the entire palette texture to black and then for one country's entry
in the palette a different color, we can highlight just that country.</p>
<p>To do paletted index graphics requires some custom shader code.
Let's modify the default shaders in three.js.
<p>To do paletted index graphics requires some custom shader code.
Let's modify the default shaders in three.js.
That way we can use lighting and other features if we want.</p>
<p>Like we covered in <a href="optimize-lots-of-objects-animated.html">the article on animating lots of objects</a>
we can modify the default shaders by adding a function to a material's
Expand Down Expand Up @@ -331,14 +331,14 @@ <h1>Indexed Textures for Picking and Color</h1>
}
</pre>
<p><a href="https://github.com/mrdoob/three.js/tree/dev/src/renderers/shaders/ShaderChunk">Digging through all those snippets</a>
we find that three.js uses a variable called <code class="notranslate" translate="no">diffuseColor</code> to manage the
we find that three.js uses a variable called <code class="notranslate" translate="no">diffuseColor</code> to manage the
base material color. It sets this in the <code class="notranslate" translate="no">&lt;color_fragment&gt;</code> <a href="https://github.com/mrdoob/three.js/blob/dev/src/renderers/shaders/ShaderChunk/color_fragment.glsl.js">snippet</a>
so we should be able to modify it after that point.</p>
<p><code class="notranslate" translate="no">diffuseColor</code> at that point in the shader should already be the color from
our outline texture so we can look up the color from a palette texture
<p><code class="notranslate" translate="no">diffuseColor</code> at that point in the shader should already be the color from
our outline texture so we can look up the color from a palette texture
and mix them for the final result.</p>
<p>Like we <a href="optimize-lots-of-objects-animated.html">did before</a> we'll make an array
of search and replacement strings and apply them to the shader in
of search and replacement strings and apply them to the shader in
<a href="/docs/#api/en/materials/Material.onBeforeCompile"><code class="notranslate" translate="no">Material.onBeforeCompile</code></a>.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">{
const loader = new THREE.TextureLoader();
Expand Down Expand Up @@ -389,7 +389,7 @@ <h1>Indexed Textures for Picking and Color</h1>
</pre>
<p>Above can see above we add 3 uniforms, <code class="notranslate" translate="no">indexTexture</code>, <code class="notranslate" translate="no">paletteTexture</code>,
and <code class="notranslate" translate="no">paletteTextureWidth</code>. We get a color from the <code class="notranslate" translate="no">indexTexture</code>
and convert it to an index. <code class="notranslate" translate="no">vUv</code> is the texture coordinates provided by
and convert it to an index. <code class="notranslate" translate="no">vUv</code> is the texture coordinates provided by
three.js. We then use that index to get a color out of the palette texture.
We then mix the result with the current <code class="notranslate" translate="no">diffuseColor</code>. The <code class="notranslate" translate="no">diffuseColor</code>
at this point is our black and white outline texture so if we add the 2 colors
Expand All @@ -407,21 +407,21 @@ <h1>Indexed Textures for Picking and Color</h1>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const maxNumCountries = 512;
const paletteTextureWidth = maxNumCountries;
const paletteTextureHeight = 1;
const palette = new Uint8Array(paletteTextureWidth * 3);
const palette = new Uint8Array(paletteTextureWidth * 4);
const paletteTexture = new THREE.DataTexture(
palette, paletteTextureWidth, paletteTextureHeight, THREE.RGBFormat);
palette, paletteTextureWidth, paletteTextureHeight);
paletteTexture.minFilter = THREE.NearestFilter;
paletteTexture.magFilter = THREE.NearestFilter;
</pre>
<p>A <a href="/docs/#api/en/textures/DataTexture"><code class="notranslate" translate="no">DataTexture</code></a> let's us give a texture raw data. In this case
we're giving it 512 RGB colors, 3 bytes each where each byte is
we're giving it 512 RGBA colors, 4 bytes each where each byte is
red, green, and blue respectively using values that go from 0 to 255.</p>
<p>Let's fill it with random colors just to see it work</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">for (let i = 1; i &lt; palette.length; ++i) {
palette[i] = Math.random() * 256;
}
// set the ocean color (index #0)
palette.set([100, 200, 255], 0);
palette.set([100, 200, 255, 255], 0);
paletteTexture.needsUpdate = true;
</pre>
<p>Anytime we want three.js to update the palette texture with
Expand Down Expand Up @@ -454,11 +454,13 @@ <h1>Indexed Textures for Picking and Color</h1>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const tempColor = new THREE.Color();
function get255BasedColor(color) {
tempColor.set(color);
return tempColor.toArray().map(v =&gt; v * 255);
const base = tempColor.toArray().map(v =&gt; v * 255);
base.push(255); // alpha
return base;
}
</pre>
<p>Calling it like this <code class="notranslate" translate="no">color = get255BasedColor('red')</code> will
return an array like <code class="notranslate" translate="no">[255, 0, 0]</code>.</p>
return an array like <code class="notranslate" translate="no">[255, 0, 0, 255]</code>.</p>
<p>Next let's use it to make a few colors and fill out the
palette.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const selectedColor = get255BasedColor('red');
Expand All @@ -467,7 +469,7 @@ <h1>Indexed Textures for Picking and Color</h1>
resetPalette();

function setPaletteColor(index, color) {
palette.set(color, index * 3);
palette.set(color, index * 4);
}

function resetPalette() {
Expand Down Expand Up @@ -628,11 +630,11 @@ <h1>Indexed Textures for Picking and Color</h1>
</div>
</div>
</div>

<script src="/manual/resources/prettify.js"></script>
<script src="/manual/resources/lesson.js"></script>




</body></html>
</body></html>
13 changes: 7 additions & 6 deletions manual/examples/indexed-textures-picking-and-highlighting.html
Original file line number Diff line number Diff line change
Expand Up @@ -99,17 +99,19 @@
pickingScene.background = new THREE.Color(0);

const tempColor = new THREE.Color();
function get255BasedColor(color) {
function get255BasedColor(color) {
tempColor.set(color);
return tempColor.toArray().map(v => v * 255);
const base = tempColor.toArray().map(v => v * 255);
base.push(255); // alpha
return base;
}

const maxNumCountries = 512;
const paletteTextureWidth = maxNumCountries;
const paletteTextureHeight = 1;
const palette = new Uint8Array(paletteTextureWidth * 3);
const palette = new Uint8Array(paletteTextureWidth * 4);
const paletteTexture = new THREE.DataTexture(
palette, paletteTextureWidth, paletteTextureHeight, THREE.RGBFormat);
palette, paletteTextureWidth, paletteTextureHeight);
paletteTexture.minFilter = THREE.NearestFilter;
paletteTexture.magFilter = THREE.NearestFilter;

Expand All @@ -119,7 +121,7 @@
resetPalette();

function setPaletteColor(index, color) {
palette.set(color, index * 3);
palette.set(color, index * 4);
}

function resetPalette() {
Expand Down Expand Up @@ -441,4 +443,3 @@
main();
</script>
</html>

12 changes: 6 additions & 6 deletions manual/examples/indexed-textures-picking-debounced.html
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,16 @@
const tempColor = new THREE.Color();
function get255BasedColor(color) {
tempColor.set(color);
return tempColor.toArray().map(v => v * 255);
const base = tempColor.toArray().map(v => v * 255);
base.push(255); // alpha
return base;
}

const maxNumCountries = 512;
const paletteTextureWidth = maxNumCountries;
const paletteTextureHeight = 1;
const palette = new Uint8Array(paletteTextureWidth * 3);
const paletteTexture = new THREE.DataTexture(
palette, paletteTextureWidth, paletteTextureHeight, THREE.RGBFormat);
const palette = new Uint8Array(paletteTextureWidth * 4);
const paletteTexture = new THREE.DataTexture(palette, paletteTextureWidth, paletteTextureHeight);
paletteTexture.minFilter = THREE.NearestFilter;
paletteTexture.magFilter = THREE.NearestFilter;

Expand All @@ -120,7 +121,7 @@
resetPalette();

function setPaletteColor(index, color) {
palette.set(color, index * 3);
palette.set(color, index * 4);
}

function resetPalette() {
Expand Down Expand Up @@ -469,4 +470,3 @@
main();
</script>
</html>

8 changes: 3 additions & 5 deletions manual/examples/indexed-textures-random-colors.html
Original file line number Diff line number Diff line change
Expand Up @@ -101,16 +101,15 @@
const maxNumCountries = 512;
const paletteTextureWidth = maxNumCountries;
const paletteTextureHeight = 1;
const palette = new Uint8Array(paletteTextureWidth * 3);
const paletteTexture = new THREE.DataTexture(
palette, paletteTextureWidth, paletteTextureHeight, THREE.RGBFormat);
const palette = new Uint8Array(paletteTextureWidth * 4);
const paletteTexture = new THREE.DataTexture(palette, paletteTextureWidth, paletteTextureHeight);
paletteTexture.minFilter = THREE.NearestFilter;
paletteTexture.magFilter = THREE.NearestFilter;
for (let i = 1; i < palette.length; ++i) {
palette[i] = Math.random() * 256;
}
// set the ocean color (index #0)
palette.set([100, 200, 255], 0);
palette.set([100, 200, 255, 255], 0);
paletteTexture.needsUpdate = true;

{
Expand Down Expand Up @@ -418,4 +417,3 @@
main();
</script>
</html>

22 changes: 12 additions & 10 deletions manual/ja/indexed-textures.html
Original file line number Diff line number Diff line change
Expand Up @@ -235,14 +235,14 @@ <h1>圧縮テクスチャのピッキングとカラー</h1>
<p>国を選択する合理的な解決策のように思えますが、選択された国を強調表示するにはどうでしょうか?</p>
<p><em>パレットグラフィックス</em> からインスピレーションを得る事ができます。</p>
<p><a href="https://en.wikipedia.org/wiki/Palette_%28computing%29">パレットグラフィックス</a><a href="https://en.wikipedia.org/wiki/Indexed_color">インデックスカラー</a>はAtari 800、Amiga、ファミコン、スーパーファミコン、IBMの古いPCなどの古いシステムで使われていました。
ビットマップをRGBカラー8ビット、1ピクセル24バイト以上で格納するのではなく、ビットマップを8ビット以下の値で格納していました。
ビットマップをRGBAカラー8ビット、1ピクセル32バイト以上で格納するのではなく、ビットマップを8ビット以下の値で格納していました。
各ピクセルの値はパレットへのインデックスです。
そのため例えば画像内の値が3であれば "color 3を表示する" という事になります。
color 3が何色かは "パレット" と呼ばれる別の場所で定義されています。</p>
<p>JavaScriptでは次のようなコードにできます。</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const face7x7PixelImageData = [
0, 1, 1, 1, 1, 1, 0,
1, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 1,
1, 0, 2, 0, 2, 0, 1,
1, 0, 0, 0, 0, 0, 1,
1, 0, 3, 3, 3, 0, 1,
Expand Down Expand Up @@ -377,20 +377,20 @@ <h1>圧縮テクスチャのピッキングとカラー</h1>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const maxNumCountries = 512;
const paletteTextureWidth = maxNumCountries;
const paletteTextureHeight = 1;
const palette = new Uint8Array(paletteTextureWidth * 3);
const palette = new Uint8Array(paletteTextureWidth * 4);
const paletteTexture = new THREE.DataTexture(
palette, paletteTextureWidth, paletteTextureHeight, THREE.RGBFormat);
palette, paletteTextureWidth, paletteTextureHeight);
paletteTexture.minFilter = THREE.NearestFilter;
paletteTexture.magFilter = THREE.NearestFilter;
</pre>
<p><a href="/docs/#api/ja/textures/DataTexture"><code class="notranslate" translate="no">DataTexture</code></a> はテクスチャの生データを与える事ができます。
今回はは512のRGBカラーを3バイトずつ与え、それぞれのバイトが赤、緑、青で0〜255の値を使用します。</p>
今回はは512のRGBAカラーを4バイトずつ与え、それぞれのバイトが赤、緑、青で0〜255の値を使用します。</p>
<p>ランダムなカラーで塗りつぶしましょう!</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">for (let i = 1; i &lt; palette.length; ++i) {
palette[i] = Math.random() * 256;
}
// set the ocean color (index #0)
palette.set([100, 200, 255], 0);
palette.set([100, 200, 255, 255], 0);
paletteTexture.needsUpdate = true;
</pre>
<p>パレットテクスチャを <code class="notranslate" translate="no">palette</code> 配列の内容で更新したい時は、常に <code class="notranslate" translate="no">paletteTexture.needsUpdate</code><code class="notranslate" translate="no">true</code> にする必要があります。</p>
Expand Down Expand Up @@ -419,7 +419,9 @@ <h1>圧縮テクスチャのピッキングとカラー</h1>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const tempColor = new THREE.Color();
function get255BasedColor(color) {
tempColor.set(color);
return tempColor.toArray().map(v =&gt; v * 255);
const base = tempColor.toArray().map(v =&gt; v * 255);
base.push(255); // alpha
return base;
}
</pre>
<p>このように <code class="notranslate" translate="no">color = get255BasedColor('red')</code> を呼び出すと <code class="notranslate" translate="no">[255, 0, 0]</code> のような配列が返されます。</p>
Expand All @@ -430,7 +432,7 @@ <h1>圧縮テクスチャのピッキングとカラー</h1>
resetPalette();

function setPaletteColor(index, color) {
palette.set(color, index * 3);
palette.set(color, index * 4);
}

function resetPalette() {
Expand Down Expand Up @@ -586,11 +588,11 @@ <h1>圧縮テクスチャのピッキングとカラー</h1>
</div>
</div>
</div>

<script src="/manual/resources/prettify.js"></script>
<script src="/manual/resources/lesson.js"></script>




</body></html>
</body></html>
Loading

0 comments on commit f31cb9e

Please sign in to comment.