Pārlūkot izejas kodu

Manual: Remove 3D LUT guide. (#27977)

Michael Herzog 1 gadu atpakaļ
vecāks
revīzija
0be2d3ff6e

+ 0 - 444
manual/en/post-processing-3dlut.html

@@ -1,444 +0,0 @@
-<!DOCTYPE html><html lang="en"><head>
-    <meta charset="utf-8">
-    <title>Post Processing 3DLUT</title>
-    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-    <meta name="twitter:card" content="summary_large_image">
-    <meta name="twitter:site" content="@threejs">
-    <meta name="twitter:title" content="Three.js – Post Processing 3DLUT">
-    <meta property="og:image" content="https://threejs.org/files/share.png">
-    <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
-    <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
-
-    <link rel="stylesheet" href="../resources/lesson.css">
-    <link rel="stylesheet" href="../resources/lang.css">
-<script type="importmap">
-{
-  "imports": {
-    "three": "../../build/three.module.js"
-  }
-}
-</script>
-  </head>
-  <body>
-    <div class="container">
-      <div class="lesson-title">
-        <h1>Post Processing 3DLUT</h1>
-      </div>
-      <div class="lesson">
-        <div class="lesson-main">
-          <p>In the last article we went over <a href="post-processing.html">post processing</a>.
-One of the common ways to post process is called a LUT or 3DLUT. LUT stands for LookUp Table. A 3DLUT is therefore a 3 dimensional look up table.</p>
-<p>How it works is we make a cube of colors. Then we index the cube using the colors of our source image. For each pixel in the original image we look up a position in the cube based on the red, green, and blue colors of the original pixel. The value we pull out of the 3DLUT is the new color.</p>
-<p>In Javascript we might do it like this. Imagine the colors are specified in integers from 0 to 255 and we have a large 3 dimensional array 256x256x256 in size. Then for to translate a color through the look up table</p>
-<pre class="prettyprint showlinemods notranslate notranslate" translate="no">const newColor = lut[origColor.red][origColor.green][origColor.bue]
-</pre><p>Of course a 256x256x256 array would be rather large but as we pointed out in <a href="textures.html">the article on textures</a> textures are referenced from values of 0.0 to 1.0 regardless of the dimensions of the texture.</p>
-<p>Let's imagine an 8x8x8 cube.</p>
-<div class="threejs_center"><img src="../resources/images/3dlut-rgb.svg" class="noinvertdark" style="width: 500px"></div>
-
-<p>First we might fill in the corners with 0,0,0 corner being pure black, the opposite 1,1,1 corner pure white. 1,0,0 being pure <span style="color:red;">red</span>. 0,1,0 being pure <span style="color:green;">green</span> and 0,0,1 being <span style="color:blue;">blue</span>. </p>
-<div class="threejs_center"><img src="../resources/images/3dlut-axis.svg" class="noinvertdark" style="width: 500px"></div>
-
-<p>We'd add in the colors down each axis.</p>
-<div class="threejs_center"><img src="../resources/images/3dlut-edges.svg" class="noinvertdark" style="width: 500px"></div>
-
-<p>And the colors on edges that use 2 or more channels.</p>
-<div class="threejs_center"><img src="../resources/images/3dlut-standard.svg" class="noinvertdark" style="width: 500px"></div>
-
-<p>And finally fill in all the colors in between. This is an "identity" 3DLUT. It produces the exact same output as input. If you look up a color you'll get the same color out.</p>
-<div class="threejs_center"><object type="image/svg+xml" data="resources/images/3dlut-standard-lookup.svg" class="noinvertdark" data-diagram="lookup" style="width: 600px"></object></div>
-
-<p>If we change the cube to shades of amber though then as we look up colors, we look up the same locations in the 3D lookup table but they produce different output.</p>
-<div class="threejs_center"><object type="image/svg+xml" data="resources/images/3dlut-amber-lookup.svg" class="noinvertdark" data-diagram="lookup" style="width: 600px"></object></div>
-
-<p>Using this techinque by supplying a different lookup table we can apply all kinds of effects. Basically any effect that can be computed based only on a single color input. Those effects include adjusting hue, contrast, saturation, color cast, tint, brightness, exposure, levels, curves, posterize, shadows, highlghts, and many others. Even better they can all be combined into a single look up table.</p>
-<p>To use it we need a scene to apply it to. Let's throw together a quick scene. We'll start with a glTF file and display it like we covered in <a href="load-gltf.html">the article on loading a glTF</a>. The model we're loading is <a href="https://sketchfab.com/models/a1d315908e9f45e5a3bc618bdfd2e7ee">this model</a> by <a href="https://sketchfab.com/sarath.irn.kat005">The Ice Wolves</a>. It uses no lights so I removed the lights.</p>
-<p>We'll also add a background image like we covered in <a href="backgrounds.html">backgrounds and skyboxs</a>.</p>
-<p></p><div translate="no" class="threejs_example_container notranslate">
-  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/postprocessing-3dlut-prep.html"></iframe></div>
-  <a class="threejs_center" href="/manual/examples/postprocessing-3dlut-prep.html" target="_blank">click here to open in a separate window</a>
-</div>
-
-<p></p>
-<p>Now that we have a scene we need a 3DLUT. The simplest 3DLUT is a 2x2x2 identity LUT where <em>identity</em> means nothing happens. It's like multiplying by 1 or doing nothing, even though we're looking up colors in the LUT each color in maps to the same color out.</p>
-<div class="threejs_center"><img src="../resources/images/3dlut-standard-2x2.svg" class="noinvertdark" style="width: 200px"></div>
-
-<p>WebGL1 doesn't support 3D textures so we'll use 4x2 2D texture and treat it as a 3D texture inside a custom shader where each slice of the cube is spread out horizontally across the texture.</p>
-<p>Here's the code to make 4x2 2D texture with the colors required for an identity LUT.</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const makeIdentityLutTexture = function() {
-  const identityLUT = new Uint8Array([
-      0,   0,   0, 255,  // black
-    255,   0,   0, 255,  // red
-      0,   0, 255, 255,  // blue
-    255,   0, 255, 255,  // magenta
-      0, 255,   0, 255,  // green
-    255, 255,   0, 255,  // yellow
-      0, 255, 255, 255,  // cyan
-    255, 255, 255, 255,  // white
-  ]);
-
-  return function(filter) {
-    const texture = new THREE.DataTexture(identityLUT, 4, 2, THREE.RGBAFormat);
-    texture.minFilter = filter;
-    texture.magFilter = filter;
-    texture.needsUpdate = true;
-    texture.flipY = false;
-    return texture;
-  };
-}();
-</pre>
-<p>Let's make 2 of them, one filtered and one not</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const lutTextures = [
-  { name: 'identity', size: 2, texture: makeIdentityLutTexture(THREE.LinearFilter) },
-  { name: 'identity not filtered', size: 2, texture: makeIdentityLutTexture(THREE.NearestFilter) },
-];
-</pre>
-<p>Taking the example using a custom shader from <a href="post-processing.html">the article on post processing</a> lets use these 2 custom shaders instead.</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const lutShader = {
-  uniforms: {
-    tDiffuse: { value: null },
-    lutMap:  { value: null },
-    lutMapSize: { value: 1, },
-  },
-  vertexShader: `
-    varying vec2 vUv;
-    void main() {
-      vUv = uv;
-      gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
-    }
-  `,
-  fragmentShader: `
-    #include &lt;common&gt;
-
-    #define FILTER_LUT true
-
-    uniform sampler2D tDiffuse;
-    uniform sampler2D lutMap;
-    uniform float lutMapSize;
-
-    varying vec2 vUv;
-
-    vec4 sampleAs3DTexture(sampler2D tex, vec3 texCoord, float size) {
-      float sliceSize = 1.0 / size;                  // space of 1 slice
-      float slicePixelSize = sliceSize / size;       // space of 1 pixel
-      float width = size - 1.0;
-      float sliceInnerSize = slicePixelSize * width; // space of size pixels
-      float zSlice0 = floor( texCoord.z * width);
-      float zSlice1 = min( zSlice0 + 1.0, width);
-      float xOffset = slicePixelSize * 0.5 + texCoord.x * sliceInnerSize;
-      float yRange = (texCoord.y * width + 0.5) / size;
-      float s0 = xOffset + (zSlice0 * sliceSize);
-
-      #ifdef FILTER_LUT
-
-        float s1 = xOffset + (zSlice1 * sliceSize);
-        vec4 slice0Color = texture2D(tex, vec2(s0, yRange));
-        vec4 slice1Color = texture2D(tex, vec2(s1, yRange));
-        float zOffset = mod(texCoord.z * width, 1.0);
-        return mix(slice0Color, slice1Color, zOffset);
-
-      #else
-
-        return texture2D(tex, vec2( s0, yRange));
-
-      #endif
-    }
-
-    void main() {
-      vec4 originalColor = texture2D(tDiffuse, vUv);
-      gl_FragColor = sampleAs3DTexture(lutMap, originalColor.xyz, lutMapSize);
-    }
-  `,
-};
-
-const lutNearestShader = {
-  uniforms: {...lutShader.uniforms},
-  vertexShader: lutShader.vertexShader,
-  fragmentShader: lutShader.fragmentShader.replace('#define FILTER_LUT', '//'),
-};
-</pre>
-<p>You can see in the fragment shader there is this line</p>
-<pre class="prettyprint showlinemods notranslate lang-glsl" translate="no">#define FILTER_LUT true
-</pre>
-<p>To generate the second shader we comment out that line.</p>
-<p>Then we use them to make 2 custom effects</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const effectLUT = new THREE.ShaderPass(lutShader);
-const effectLUTNearest = new THREE.ShaderPass(lutNearestShader);
-</pre>
-<p>Translating our existing code that draws the background as a separate scene we a <code class="notranslate" translate="no">RenderPass</code> for both the scene drawing the glTF and the scene drawing the background.</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const renderModel = new THREE.RenderPass(scene, camera);
-renderModel.clear = false;  // so we don't clear out the background
-const renderBG = new THREE.RenderPass(sceneBG, cameraBG);
-</pre>
-<p>and we can setup our <code class="notranslate" translate="no">EffectComposer</code> to use all the passes</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const composer = new THREE.EffectComposer(renderer);
-
-composer.addPass(renderBG);
-composer.addPass(renderModel);
-composer.addPass(effectLUT);
-composer.addPass(effectLUTNearest);
-composer.addPass(outputPass);
-</pre>
-<p>Let's make some GUI code to select one lut or the other</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const lutNameIndexMap = {};
-lutTextures.forEach((info, ndx) =&gt; {
-  lutNameIndexMap[info.name] = ndx;
-});
-
-const lutSettings = {
-  lut: lutNameIndexMap.identity,
-};
-const gui = new GUI({ width: 300 });
-gui.add(lutSettings, 'lut', lutNameIndexMap);
-</pre>
-<p>The last thing to do is turn on one effect or the other, depending on whether or not we want filtering, set the effect to use the selected texture, and render via the <code class="notranslate" translate="no">EffectComposer</code></p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const lutInfo = lutTextures[lutSettings.lut];
-
-const effect = lutInfo.filter ? effectLUT : effectLUTNearest;
-effectLUT.enabled = lutInfo.filter;
-effectLUTNearest.enabled = !lutInfo.filter;
-
-const lutTexture = lutInfo.texture;
-effect.uniforms.lutMap.value = lutTexture;
-effect.uniforms.lutMapSize.value = lutInfo.size;
-
-composer.render(delta);
-</pre>
-<p>Given it's the identity 3DLUT nothing changes</p>
-<p></p><div translate="no" class="threejs_example_container notranslate">
-  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/postprocessing-3dlut-identity.html"></iframe></div>
-  <a class="threejs_center" href="/manual/examples/postprocessing-3dlut-identity.html" target="_blank">click here to open in a separate window</a>
-</div>
-
-<p></p>
-<p>but we select the unfiltered LUT we get something much more interesting</p>
-<div class="threejs_center"><img src="../resources/images/unfiltered-3dlut.jpg" style="width: 500px"></div>
-
-<p>Why does this happen? Because with filtering on, the GPU linearly interpolates between the colors. With filtering off it does no interpolation so looking up colors in the 3DLUT only gives one of the exact colors in the 3DLUT.</p>
-<p>So how do we go about making more interesting 3DLUTs?</p>
-<p>First decide on the resolution of the table you want and generate the slices of the lookup cube using a simple script.</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const ctx = document.querySelector('canvas').getContext('2d');
-
-function drawColorCubeImage(ctx, size) {
-  const canvas = ctx.canvas;
-  canvas.width = size * size;
-  canvas.height = size;
-
-  for (let zz = 0; zz &lt; size; ++zz) {
-    for (let yy = 0; yy &lt; size; ++yy) {
-      for (let xx = 0; xx &lt; size; ++xx) {
-        const r = Math.floor(xx / (size - 1) * 255);
-        const g = Math.floor(yy / (size - 1) * 255);
-        const b = Math.floor(zz / (size - 1) * 255);
-        ctx.fillStyle = `rgb(${r},${g},${b})`;
-        ctx.fillRect(zz * size + xx, yy, 1, 1);
-      }
-    }
-  }
-  document.querySelector('#width').textContent = canvas.width;
-  document.querySelector('#height').textContent = canvas.height;
-}
-
-drawColorCubeImage(ctx, 8);
-</pre>
-<p>and we need a canvas </p>
-<pre class="prettyprint showlinemods notranslate lang-html" translate="no">&lt;canvas&gt;&lt;/canvas&gt;
-</pre>
-<p>then we can generate a identity 3d lookup table for any size.</p>
-<p></p><div translate="no" class="threejs_example_container notranslate">
-  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/3dlut-base-cube-maker.html"></iframe></div>
-  <a class="threejs_center" href="/manual/examples/3dlut-base-cube-maker.html" target="_blank">click here to open in a separate window</a>
-</div>
-
-<p></p>
-<p>The larger the resolution the more fine adjustments we can make but being a cube of data the size required grows quickly. A size 8 cube only requires 2k but a size 64 cube requires 1meg. So use the smallest that reproduces the effect you want.</p>
-<p>Let's set the size to 16 and then click save the file which gives us this file.</p>
-<div class="threejs_center"><img src="../resources/images/identity-lut-s16.png"></div>
-
-<p>We also need to capture an image of the thing we want to apply the LUT to, in this case the scene we created above before applying any effects. Note that normally we could right click on the scene above and pick "Save As..." but the <a href="/docs/#examples/controls/OrbitControls"><code class="notranslate" translate="no">OrbitControls</code></a> might be preventing right clicking depending on your OS. In my case I used my OSes screen capture feature to get a screenshot.</p>
-<div class="threejs_center"><img src="../resources/images/3dlut-screen-capture.jpg" style="width: 600px"></div>
-
-<p>We then go it into an image editor, in my case Photoshop, load up the sample image, and paste the 3DLUT in the top left corner</p>
-<blockquote>
-<p>note: I first tried dragging and dropping the lut file on top of the image
-in Photoshop but that didn't work. Photoshop made the image twice as large.
-I'm guessing it was trying to match DPI or something. Loading the lut file
-separately and then copying and pasting it into the screen capture worked.</p>
-</blockquote>
-<div class="threejs_center"><img src="../resources/images/3dlut-photoshop-before.jpg" style="width: 600px"></div>
-
-<p>We then use any of the color based full image adjustments to adjust the image. For Photoshop most of the adjustments we can use are available under the Image-&gt;Adjustments menu.</p>
-<div class="threejs_center"><img src="../resources/images/3dlut-photoshop-after.jpg" style="width: 600px"></div>
-
-<p>After we've adjusted the image to our liking you can see the 3DLUT slices we placed in the top left corner have the same adjustments applied.</p>
-<p>Okay but how do we use it?</p>
-<p>First I saved it as a png <code class="notranslate" translate="no">3dlut-red-only-s16.png</code>. To save memory we could have cropped it to just the 16x256 top left corner of the LUT table but just for fun we'll crop it after loading. The good thing about using this method is we can get some idea of the effective of the LUT just by looking at the .png file. The bad thing is of course wasted bandwidth.</p>
-<p>Here's some code to load it. The code starts with an identity lut so the texture is usable immediately. It then loads the image, copies out only the 3DLUT part into a canvas, gets the data from the canvas, set it on the texture and sets <code class="notranslate" translate="no">needsUpdate</code> to true to tell THREE.js to get the new data.</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const makeLUTTexture = function() {
-  const imgLoader = new THREE.ImageLoader();
-  const ctx = document.createElement('canvas').getContext('2d');
-
-  return function(info) {
-    const lutSize = info.size;
-    const width = lutSize * lutSize;
-    const height = lutSize;
-    const texture = new THREE.DataTexture(new Uint8Array(width * height), width, height);
-    texture.minFilter = texture.magFilter = info.filter ? THREE.LinearFilter : THREE.NearestFilter;
-    texture.flipY = false;
-
-    if (info.url) {
-
-      imgLoader.load(info.url, function(image) {
-        ctx.canvas.width = width;
-        ctx.canvas.height = height;
-        ctx.drawImage(image, 0, 0);
-        const imageData = ctx.getImageData(0, 0, width, height);
-
-        texture.image.data = new Uint8Array(imageData.data.buffer);
-        texture.image.width = width;
-        texture.image.height = height;
-        texture.needsUpdate = true;
-      });
-    }
-
-    return texture;
-  };
-}();
-</pre>
-<p>Let's use it to load the lut png we just created.</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const lutTextures = [
-  { name: 'identity',           size: 2, filter: true , },
-  { name: 'identity no filter', size: 2, filter: false, },
-+  { name: 'custom',          url: 'resources/images/lut/3dlut-red-only-s16.png' },
-];
-
-+lutTextures.forEach((info) =&gt; {
-+  // if not size set get it from the filename
-+  if (!info.size) {
-+    // assumes filename ends in '-s&lt;num&gt;[n]'
-+    // where &lt;num&gt; is the size of the 3DLUT cube
-+    // and [n] means 'no filtering' or 'nearest'
-+    //
-+    // examples:
-+    //    'foo-s16.png' = size:16, filter: true
-+    //    'bar-s8n.png' = size:8, filter: false
-+    const m = /-s(\d+)(n*)\.[^.]+$/.exec(info.url);
-+    if (m) {
-+      info.size = parseInt(m[1]);
-+      info.filter = info.filter === undefined ? m[2] !== 'n' : info.filter;
-+    }
-+  }
-+
-+  info.texture = makeLUTTexture(info);
-+});
-</pre>
-<p>Above you can see we encoded the size of the LUT into the end of the filename. This makes it easier to pass around LUTs as pngs.</p>
-<p>While we're at it lets add a bunch more existing lut png files.</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const lutTextures = [
-  { name: 'identity',           size: 2, filter: true , },
-  { name: 'identity no filter', size: 2, filter: false, },
-  { name: 'custom',          url: 'resources/images/lut/3dlut-red-only-s16.png' },
-+  { name: 'monochrome',      url: 'resources/images/lut/monochrome-s8.png' },
-+  { name: 'sepia',           url: 'resources/images/lut/sepia-s8.png' },
-+  { name: 'saturated',       url: 'resources/images/lut/saturated-s8.png', },
-+  { name: 'posterize',       url: 'resources/images/lut/posterize-s8n.png', },
-+  { name: 'posterize-3-rgb', url: 'resources/images/lut/posterize-3-rgb-s8n.png', },
-+  { name: 'posterize-3-lab', url: 'resources/images/lut/posterize-3-lab-s8n.png', },
-+  { name: 'posterize-4-lab', url: 'resources/images/lut/posterize-4-lab-s8n.png', },
-+  { name: 'posterize-more',  url: 'resources/images/lut/posterize-more-s8n.png', },
-+  { name: 'inverse',         url: 'resources/images/lut/inverse-s8.png', },
-+  { name: 'color negative',  url: 'resources/images/lut/color-negative-s8.png', },
-+  { name: 'high contrast',   url: 'resources/images/lut/high-contrast-bw-s8.png', },
-+  { name: 'funky contrast',  url: 'resources/images/lut/funky-contrast-s8.png', },
-+  { name: 'nightvision',     url: 'resources/images/lut/nightvision-s8.png', },
-+  { name: 'thermal',         url: 'resources/images/lut/thermal-s8.png', },
-+  { name: 'b/w',             url: 'resources/images/lut/black-white-s8n.png', },
-+  { name: 'hue +60',         url: 'resources/images/lut/hue-plus-60-s8.png', },
-+  { name: 'hue +180',        url: 'resources/images/lut/hue-plus-180-s8.png', },
-+  { name: 'hue -60',         url: 'resources/images/lut/hue-minus-60-s8.png', },
-+  { name: 'red to cyan',     url: 'resources/images/lut/red-to-cyan-s8.png' },
-+  { name: 'blues',           url: 'resources/images/lut/blues-s8.png' },
-+  { name: 'infrared',        url: 'resources/images/lut/infrared-s8.png' },
-+  { name: 'radioactive',     url: 'resources/images/lut/radioactive-s8.png' },
-+  { name: 'goolgey',         url: 'resources/images/lut/googley-s8.png' },
-+  { name: 'bgy',             url: 'resources/images/lut/bgy-s8.png' },
-];
-</pre>
-<p>And here's a bunch of luts to choose from.</p>
-<p></p><div translate="no" class="threejs_example_container notranslate">
-  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/postprocessing-3dlut.html"></iframe></div>
-  <a class="threejs_center" href="/manual/examples/postprocessing-3dlut.html" target="_blank">click here to open in a separate window</a>
-</div>
-
-<p></p>
-<p>One last thing, just for fun, it turns out there's a standard LUT format defined by Adobe. If you <a href="https://www.google.com/search?q=lut+files">search on the net you can find lots of these LUT files</a>.</p>
-<p>I wrote a quick loader. Unfortunately there's 4 variations of the format but I could only find examples of 1 variation so I couldn't easily test that all variations work.</p>
-<p>I also wrote a quick drag and drop library. Let's use both to make it so you can drag and drop an Adobe LUT file to see it take affect.</p>
-<p>First we need the 2 libraries</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">import * as lutParser from './resources/lut-reader.js';
-import * as dragAndDrop from './resources/drag-and-drop.js';
-</pre>
-<p>Then we can use them like this</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">dragAndDrop.setup({msg: 'Drop LUT File here'});
-dragAndDrop.onDropFile(readLUTFile);
-
-function ext(s) {
-  const period = s.lastIndexOf('.');
-  return s.slice(period + 1);
-}
-
-function readLUTFile(file) {
-  const reader = new FileReader();
-  reader.onload = (e) =&gt; {
-    const type = ext(file.name);
-    const lut = lutParser.lutTo2D3Drgba8(lutParser.parse(e.target.result, type));
-    const {size, data, name} = lut;
-    const texture = new THREE.DataTexture(data, size * size, size);
-    texture.minFilter = THREE.LinearFilter;
-    texture.needsUpdate = true;
-    texture.flipY = false;
-    const lutTexture = {
-      name: (name &amp;&amp; name.toLowerCase().trim() !== 'untitled')
-          ? name
-          : file.name,
-      size: size,
-      filter: true,
-      texture,
-    };
-    lutTextures.push(lutTexture);
-    lutSettings.lut = lutTextures.length - 1;
-    updateGUI();
-  };
-
-  reader.readAsText(file);
-}
-</pre>
-<p>so you should be able to <a href="https://www.google.com/search?q=lut+files">download an Adobe LUT</a> and then drag and drop it on the example below.</p>
-<p></p><div translate="no" class="threejs_example_container notranslate">
-  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/postprocessing-3dlut-w-loader.html"></iframe></div>
-  <a class="threejs_center" href="/manual/examples/postprocessing-3dlut-w-loader.html" target="_blank">click here to open in a separate window</a>
-</div>
-
-<p></p>
-<p>Note that Adobe LUTs are not designed for online usage. They are large files. You can convert them to smaller files and save as our PNG format by dragging and dropping on the sample below, choosing a size and clicking "Save...".</p>
-<p>The sample below is just a modification of the code above. We only draw the background picture, no glTF file. That picture is an identity lut image created from the script above. We then use the effect to apply whatever LUT file is loaded so the result is the image we'd need to reproduce the LUT file as a PNG.</p>
-<p></p><div translate="no" class="threejs_example_container notranslate">
-  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/postprocessing-adobe-lut-to-png-converter.html"></iframe></div>
-  <a class="threejs_center" href="/manual/examples/postprocessing-adobe-lut-to-png-converter.html" target="_blank">click here to open in a separate window</a>
-</div>
-
-<p></p>
-<p>One thing completely skipped is how the shader itself works. Hopefully we can cover a little more GLSL in the future. For now, if you're curious, you can follow the links in the <a href="post-processing.html">post processing article</a> as well as maybe <a href="https://www.youtube.com/watch?v=rfQ8rKGTVlg#t=24m30s">take a look at this video</a>.</p>
-<script type="module" src="../resources/threejs-post-processing-3dlut.js"></script>
-
-
-        </div>
-      </div>
-    </div>
-
-  <script src="../resources/prettify.js"></script>
-  <script src="../resources/lesson.js"></script>
-
-
-
-
-</body></html>

+ 0 - 341
manual/examples/postprocessing-3dlut-identity.html

@@ -1,341 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-  <head>
-    <title>Three.js - postprocessing - 3DLUT</title>
-    <meta charset="utf-8">
-    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-    <style>
-    html, body {
-        margin: 0;
-        height: 100%;
-    }
-    #c {
-        width: 100%;
-        height: 100%;
-        display: block;
-    }
-  </style>
-  </head>
-  <body>
-    <canvas id="c"></canvas>
-  </body>
-<script type="importmap">
-{
-  "imports": {
-    "three": "../../build/three.module.js",
-    "three/addons/": "../../examples/jsm/"
-  }
-}
-</script>
-
-<script type="module">
-import * as THREE from 'three';
-import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
-import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
-import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
-import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
-import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
-import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
-import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
-
-function main() {
-
-	const canvas = document.querySelector( '#c' );
-	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
-
-	const fov = 45;
-	const aspect = 2; // the canvas default
-	const near = 0.1;
-	const far = 100;
-	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
-	camera.position.set( 0, 10, 20 );
-
-	const controls = new OrbitControls( camera, canvas );
-	controls.target.set( 0, 5, 0 );
-	controls.update();
-
-	const makeIdentityLutTexture = function () {
-
-		const identityLUT = new Uint8Array( [
-			0, 0, 0, 255, // black
-			255, 0, 0, 255, // red
-			0, 0, 255, 255, // blue
-			255, 0, 255, 255, // magenta
-			0, 255, 0, 255, // green
-			255, 255, 0, 255, // yellow
-			0, 255, 255, 255, // cyan
-			255, 255, 255, 255, // white
-		] );
-
-		return function ( filter ) {
-
-			const texture = new THREE.DataTexture( identityLUT, 4, 2 );
-			texture.minFilter = filter;
-			texture.magFilter = filter;
-			texture.needsUpdate = true;
-			texture.flipY = false;
-			return texture;
-
-		};
-
-	}();
-
-	const lutTextures = [
-		{
-			name: 'identity',
-			size: 2,
-			filter: true,
-			texture: makeIdentityLutTexture( THREE.LinearFilter ),
-		},
-		{
-			name: 'identity not filtered',
-			size: 2,
-			filter: false,
-			texture: makeIdentityLutTexture( THREE.NearestFilter ),
-		},
-	];
-
-	const lutNameIndexMap = {};
-	lutTextures.forEach( ( info, ndx ) => {
-
-		lutNameIndexMap[ info.name ] = ndx;
-
-	} );
-
-	const lutSettings = {
-		lut: lutNameIndexMap.identity,
-	};
-	const gui = new GUI( { width: 300 } );
-	gui.add( lutSettings, 'lut', lutNameIndexMap );
-
-	const scene = new THREE.Scene();
-
-	const sceneBG = new THREE.Scene();
-	const cameraBG = new THREE.OrthographicCamera( - 1, 1, 1, - 1, - 1, 1 );
-
-	let bgMesh;
-	let bgTexture;
-	{
-
-		const loader = new THREE.TextureLoader();
-		bgTexture = loader.load( 'resources/images/beach.jpg' );
-		bgTexture.colorSpace = THREE.SRGBColorSpace;
-		const planeGeo = new THREE.PlaneGeometry( 2, 2 );
-		const planeMat = new THREE.MeshBasicMaterial( {
-			map: bgTexture,
-			depthTest: false,
-		} );
-		bgMesh = new THREE.Mesh( planeGeo, planeMat );
-		sceneBG.add( bgMesh );
-
-	}
-
-	function frameArea( sizeToFitOnScreen, boxSize, boxCenter, camera ) {
-
-		const halfSizeToFitOnScreen = sizeToFitOnScreen * 0.5;
-		const halfFovY = THREE.MathUtils.degToRad( camera.fov * .5 );
-		const distance = halfSizeToFitOnScreen / Math.tan( halfFovY );
-		// compute a unit vector that points in the direction the camera is now
-		// in the xz plane from the center of the box
-		const direction = ( new THREE.Vector3() )
-			.subVectors( camera.position, boxCenter )
-			.multiply( new THREE.Vector3( 1, 0, 1 ) )
-			.normalize();
-
-		// move the camera to a position distance units way from the center
-		// in whatever direction the camera was from the center already
-		camera.position.copy( direction.multiplyScalar( distance ).add( boxCenter ) );
-
-		// pick some near and far values for the frustum that
-		// will contain the box.
-		camera.near = boxSize / 100;
-		camera.far = boxSize * 100;
-
-		camera.updateProjectionMatrix();
-
-		// point the camera to look at the center of the box
-		camera.lookAt( boxCenter.x, boxCenter.y, boxCenter.z );
-
-	}
-
-	{
-
-		const gltfLoader = new GLTFLoader();
-		gltfLoader.load( 'resources/models/3dbustchallange_submission/scene.gltf', ( gltf ) => {
-
-			const root = gltf.scene;
-			scene.add( root );
-
-			// fix materials from r114
-			root.traverse( ( { material } ) => {
-
-				if ( material ) {
-
-					material.depthWrite = true;
-
-				}
-
-			} );
-
-			root.updateMatrixWorld();
-			// compute the box that contains all the stuff
-			// from root and below
-			const box = new THREE.Box3().setFromObject( root );
-
-			const boxSize = box.getSize( new THREE.Vector3() ).length();
-			const boxCenter = box.getCenter( new THREE.Vector3() );
-			frameArea( boxSize * 0.4, boxSize, boxCenter, camera );
-
-			// update the Trackball controls to handle the new size
-			controls.maxDistance = boxSize * 10;
-			controls.target.copy( boxCenter );
-			controls.update();
-
-		} );
-
-	}
-
-	const lutShader = {
-		uniforms: {
-			tDiffuse: { value: null }, // the previous pass's result
-			lutMap: { value: null },
-			lutMapSize: { value: 1, },
-		},
-		vertexShader: `
-      varying vec2 vUv;
-      void main() {
-        vUv = uv;
-        gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
-      }
-    `,
-		fragmentShader: `
-      #include <common>
-
-      #define FILTER_LUT true
-
-      uniform sampler2D tDiffuse;
-      uniform sampler2D lutMap;
-      uniform float lutMapSize;
-
-      varying vec2 vUv;
-
-      vec4 sampleAs3DTexture(sampler2D tex, vec3 texCoord, float size) {
-        float sliceSize = 1.0 / size;                  // space of 1 slice
-        float slicePixelSize = sliceSize / size;       // space of 1 pixel
-        float width = size - 1.0;
-        float sliceInnerSize = slicePixelSize * width; // space of size pixels
-        float zSlice0 = floor( texCoord.z * width);
-        float zSlice1 = min( zSlice0 + 1.0, width);
-        float xOffset = slicePixelSize * 0.5 + texCoord.x * sliceInnerSize;
-        float yRange = (texCoord.y * width + 0.5) / size;
-        float s0 = xOffset + (zSlice0 * sliceSize);
-
-        #ifdef FILTER_LUT
-
-          float s1 = xOffset + (zSlice1 * sliceSize);
-          vec4 slice0Color = texture2D(tex, vec2(s0, yRange));
-          vec4 slice1Color = texture2D(tex, vec2(s1, yRange));
-          float zOffset = mod(texCoord.z * width, 1.0);
-          return mix(slice0Color, slice1Color, zOffset);
-
-        #else
-
-          return texture2D(tex, vec2( s0, yRange));
-
-        #endif
-      }
-
-      void main() {
-        vec4 originalColor = texture2D(tDiffuse, vUv);
-        gl_FragColor = sampleAs3DTexture(lutMap, originalColor.xyz, lutMapSize);
-      }
-    `,
-	};
-
-	const lutNearestShader = {
-		uniforms: { ...lutShader.uniforms },
-		vertexShader: lutShader.vertexShader,
-		fragmentShader: lutShader.fragmentShader.replace( '#define FILTER_LUT', '//' ),
-	};
-
-	const effectLUT = new ShaderPass( lutShader );
-	const effectLUTNearest = new ShaderPass( lutNearestShader );
-
-	const renderModel = new RenderPass( scene, camera );
-	renderModel.clear = false; // so we don't clear out the background
-	const renderBG = new RenderPass( sceneBG, cameraBG );
-	const outputPass = new OutputPass();
-
-	const composer = new EffectComposer( renderer );
-
-	composer.addPass( renderBG );
-	composer.addPass( renderModel );
-	composer.addPass( effectLUT );
-	composer.addPass( effectLUTNearest );
-	composer.addPass( outputPass );
-
-	function resizeRendererToDisplaySize( renderer ) {
-
-		const canvas = renderer.domElement;
-		const width = canvas.clientWidth * window.devicePixelRatio | 0;
-		const height = canvas.clientHeight * window.devicePixelRatio | 0;
-
-		const needResize = canvas.width !== width || canvas.height !== height;
-		if ( needResize ) {
-
-			renderer.setSize( width, height, false );
-
-		}
-
-		return needResize;
-
-	}
-
-	let then = 0;
-	function render( now ) {
-
-		now *= 0.001; // convert to seconds
-		const delta = now - then;
-		then = now;
-
-		if ( resizeRendererToDisplaySize( renderer ) ) {
-
-			const canvas = renderer.domElement;
-			const canvasAspect = canvas.clientWidth / canvas.clientHeight;
-			camera.aspect = canvasAspect;
-			camera.updateProjectionMatrix();
-			composer.setSize( canvas.width, canvas.height );
-
-			// scale the background plane to keep the image's
-			// aspect correct.
-			// Note the image may not have loaded yet.
-			const imageAspect = bgTexture.image ? bgTexture.image.width / bgTexture.image.height : 1;
-			const aspect = imageAspect / canvasAspect;
-			bgMesh.scale.x = aspect > 1 ? aspect : 1;
-			bgMesh.scale.y = aspect > 1 ? 1 : 1 / aspect;
-
-		}
-
-		const lutInfo = lutTextures[ lutSettings.lut ];
-
-		const effect = lutInfo.filter ? effectLUT : effectLUTNearest;
-		effectLUT.enabled = lutInfo.filter;
-		effectLUTNearest.enabled = ! lutInfo.filter;
-
-		const lutTexture = lutInfo.texture;
-		effect.uniforms.lutMap.value = lutTexture;
-		effect.uniforms.lutMapSize.value = lutInfo.size;
-
-		composer.render( delta );
-
-		requestAnimationFrame( render );
-
-	}
-
-	requestAnimationFrame( render );
-
-}
-
-main();
-</script>
-</html>

+ 0 - 190
manual/examples/postprocessing-3dlut-prep.html

@@ -1,190 +0,0 @@
-<!-- Licensed under a BSD license. See license.html for license -->
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
-    <title>Three.js - Post Processing 3DLUT (not) - prep</title>
-    <style>
-    html, body {
-        margin: 0;
-        height: 100%;
-    }
-    #c {
-        width: 100%;
-        height: 100%;
-        display: block;
-    }
-    </style>
-  </head>
-  <body>
-    <canvas id="c"></canvas>
-  </body>
-<script type="importmap">
-{
-  "imports": {
-    "three": "../../build/three.module.js",
-    "three/addons/": "../../examples/jsm/"
-  }
-}
-</script>
-
-<script type="module">
-import * as THREE from 'three';
-import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
-import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
-
-function main() {
-
-	const canvas = document.querySelector( '#c' );
-	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
-	renderer.autoClearColor = false;
-
-	const fov = 45;
-	const aspect = 2; // the canvas default
-	const near = 0.1;
-	const far = 100;
-	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
-	camera.position.set( 0, 10, 20 );
-
-	const controls = new OrbitControls( camera, canvas );
-	controls.target.set( 0, 5, 0 );
-	controls.update();
-
-	const scene = new THREE.Scene();
-
-	const sceneBG = new THREE.Scene();
-	const cameraBG = new THREE.OrthographicCamera( - 1, 1, 1, - 1, - 1, 1 );
-
-	let bgMesh;
-	let bgTexture;
-	{
-
-		const loader = new THREE.TextureLoader();
-		bgTexture = loader.load( 'resources/images/beach.jpg' );
-		bgTexture.colorSpace = THREE.SRGBColorSpace;
-		const planeGeo = new THREE.PlaneGeometry( 2, 2 );
-		const planeMat = new THREE.MeshBasicMaterial( {
-			map: bgTexture,
-			depthTest: false,
-		} );
-		bgMesh = new THREE.Mesh( planeGeo, planeMat );
-		sceneBG.add( bgMesh );
-
-	}
-
-	function frameArea( sizeToFitOnScreen, boxSize, boxCenter, camera ) {
-
-		const halfSizeToFitOnScreen = sizeToFitOnScreen * 0.5;
-		const halfFovY = THREE.MathUtils.degToRad( camera.fov * .5 );
-		const distance = halfSizeToFitOnScreen / Math.tan( halfFovY );
-		// compute a unit vector that points in the direction the camera is now
-		// in the xz plane from the center of the box
-		const direction = ( new THREE.Vector3() )
-			.subVectors( camera.position, boxCenter )
-			.multiply( new THREE.Vector3( 1, 0, 1 ) )
-			.normalize();
-
-		// move the camera to a position distance units way from the center
-		// in whatever direction the camera was from the center already
-		camera.position.copy( direction.multiplyScalar( distance ).add( boxCenter ) );
-
-		// pick some near and far values for the frustum that
-		// will contain the box.
-		camera.near = boxSize / 100;
-		camera.far = boxSize * 100;
-
-		camera.updateProjectionMatrix();
-
-		// point the camera to look at the center of the box
-		camera.lookAt( boxCenter.x, boxCenter.y, boxCenter.z );
-
-	}
-
-	{
-
-		const gltfLoader = new GLTFLoader();
-		gltfLoader.load( 'resources/models/3dbustchallange_submission/scene.gltf', ( gltf ) => {
-
-			const root = gltf.scene;
-			scene.add( root );
-
-			// fix materials from r114
-			root.traverse( ( { material } ) => {
-
-				if ( material ) {
-
-					material.depthWrite = true;
-
-				}
-
-			} );
-
-			// compute the box that contains all the stuff
-			// from root and below
-			const box = new THREE.Box3().setFromObject( root );
-
-			const boxSize = box.getSize( new THREE.Vector3() ).length();
-			const boxCenter = box.getCenter( new THREE.Vector3() );
-
-			// set the camera to frame the box
-			frameArea( boxSize * 0.4, boxSize, boxCenter, camera );
-
-			// update the Trackball controls to handle the new size
-			controls.maxDistance = boxSize * 10;
-			controls.target.copy( boxCenter );
-			controls.update();
-
-		} );
-
-	}
-
-	function resizeRendererToDisplaySize( renderer ) {
-
-		const canvas = renderer.domElement;
-		const width = canvas.clientWidth;
-		const height = canvas.clientHeight;
-		const needResize = canvas.width !== width || canvas.height !== height;
-		if ( needResize ) {
-
-			renderer.setSize( width, height, false );
-
-		}
-
-		return needResize;
-
-	}
-
-	function render() {
-
-		if ( resizeRendererToDisplaySize( renderer ) ) {
-
-			const canvas = renderer.domElement;
-			const canvasAspect = canvas.clientWidth / canvas.clientHeight;
-			camera.aspect = canvasAspect;
-			camera.updateProjectionMatrix();
-
-			// scale the background plane to keep the image's
-			// aspect correct.
-			// Note the image may not have loaded yet.
-			const imageAspect = bgTexture.image ? bgTexture.image.width / bgTexture.image.height : 1;
-			const aspect = imageAspect / canvasAspect;
-			bgMesh.scale.x = aspect > 1 ? aspect : 1;
-			bgMesh.scale.y = aspect > 1 ? 1 : 1 / aspect;
-
-		}
-
-		renderer.render( sceneBG, cameraBG );
-		renderer.render( scene, camera );
-
-		requestAnimationFrame( render );
-
-	}
-
-	requestAnimationFrame( render );
-
-}
-
-main();
-</script>
-</html>

+ 0 - 465
manual/examples/postprocessing-3dlut-w-loader.html

@@ -1,465 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-  <head>
-    <title>Three.js - postprocessing - 3DLUT w/loader</title>
-    <meta charset="utf-8">
-    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-    <style>
-    html, body {
-        margin: 0;
-        height: 100%;
-    }
-    #c {
-        width: 100%;
-        height: 100%;
-        display: block;
-    }
-  </style>
-  </head>
-  <body>
-    <canvas id="c"></canvas>
-  </body>
-<script type="importmap">
-{
-  "imports": {
-    "three": "../../build/three.module.js",
-    "three/addons/": "../../examples/jsm/"
-  }
-}
-</script>
-
-<script type="module">
-import * as THREE from 'three';
-import * as lutParser from './resources/lut-reader.js';
-import * as dragAndDrop from './resources/drag-and-drop.js';
-import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
-import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
-import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
-import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
-import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
-import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
-import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
-
-function main() {
-
-	const canvas = document.querySelector( '#c' );
-	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
-
-	const fov = 45;
-	const aspect = 2; // the canvas default
-	const near = 0.1;
-	const far = 100;
-	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
-	camera.position.set( 0, 10, 20 );
-
-	const controls = new OrbitControls( camera, canvas );
-	controls.target.set( 0, 5, 0 );
-	controls.update();
-
-	const lutTextures = [
-		{ name: 'identity', size: 2, filter: true, },
-		{ name: 'identity no filter', size: 2, filter: false, },
-		{ name: 'custom', url: 'resources/images/lut/3dlut-red-only-s16.png' },
-		{ name: 'monochrome', url: 'resources/images/lut/monochrome-s8.png' },
-		{ name: 'sepia', url: 'resources/images/lut/sepia-s8.png' },
-		{ name: 'saturated', url: 'resources/images/lut/saturated-s8.png', },
-		{ name: 'posterize', url: 'resources/images/lut/posterize-s8n.png', },
-		{ name: 'posterize-3-rgb', url: 'resources/images/lut/posterize-3-rgb-s8n.png', },
-		{ name: 'posterize-3-lab', url: 'resources/images/lut/posterize-3-lab-s8n.png', },
-		{ name: 'posterize-4-lab', url: 'resources/images/lut/posterize-4-lab-s8n.png', },
-		{ name: 'posterize-more', url: 'resources/images/lut/posterize-more-s8n.png', },
-		{ name: 'inverse', url: 'resources/images/lut/inverse-s8.png', },
-		{ name: 'color negative', url: 'resources/images/lut/color-negative-s8.png', },
-		{ name: 'high contrast', url: 'resources/images/lut/high-contrast-bw-s8.png', },
-		{ name: 'funky contrast', url: 'resources/images/lut/funky-contrast-s8.png', },
-		{ name: 'nightvision', url: 'resources/images/lut/nightvision-s8.png', },
-		{ name: 'thermal', url: 'resources/images/lut/thermal-s8.png', },
-		{ name: 'b/w', url: 'resources/images/lut/black-white-s8n.png', },
-		{ name: 'hue +60', url: 'resources/images/lut/hue-plus-60-s8.png', },
-		{ name: 'hue +180', url: 'resources/images/lut/hue-plus-180-s8.png', },
-		{ name: 'hue -60', url: 'resources/images/lut/hue-minus-60-s8.png', },
-		{ name: 'red to cyan', url: 'resources/images/lut/red-to-cyan-s8.png' },
-		{ name: 'blues', url: 'resources/images/lut/blues-s8.png' },
-		{ name: 'infrared', url: 'resources/images/lut/infrared-s8.png' },
-		{ name: 'radioactive', url: 'resources/images/lut/radioactive-s8.png' },
-		{ name: 'goolgey', url: 'resources/images/lut/googley-s8.png' },
-		{ name: 'bgy', url: 'resources/images/lut/bgy-s8.png' },
-	];
-
-	const makeIdentityLutTexture = function () {
-
-		const identityLUT = new Uint8Array( [
-			0, 0, 0, 255, // black
-			255, 0, 0, 255, // red
-			0, 0, 255, 255, // blue
-			255, 0, 255, 255, // magenta
-			0, 255, 0, 255, // green
-			255, 255, 0, 255, // yellow
-			0, 255, 255, 255, // cyan
-			255, 255, 255, 255, // white
-		] );
-
-		return function ( filter ) {
-
-			const texture = new THREE.DataTexture( identityLUT, 4, 2 );
-			texture.minFilter = texture.magFilter = filter ? THREE.LinearFilter : THREE.NearestFilter;
-			texture.needsUpdate = true;
-			texture.flipY = false;
-			return texture;
-
-		};
-
-	}();
-
-	const makeLUTTexture = function () {
-
-		const imgLoader = new THREE.ImageLoader();
-		const ctx = document.createElement( 'canvas' ).getContext( '2d' );
-
-		return function ( info ) {
-
-			const lutSize = info.size;
-			const width = lutSize * lutSize;
-			const height = lutSize;
-			const texture = new THREE.DataTexture( new Uint8Array( width * height ), width, height );
-			texture.minFilter = texture.magFilter = info.filter ? THREE.LinearFilter : THREE.NearestFilter;
-			texture.flipY = false;
-
-			if ( info.url ) {
-
-				imgLoader.load( info.url, function ( image ) {
-
-					ctx.canvas.width = width;
-					ctx.canvas.height = height;
-					ctx.drawImage( image, 0, 0 );
-					const imageData = ctx.getImageData( 0, 0, width, height );
-
-					texture.image.data = new Uint8Array( imageData.data.buffer );
-					texture.image.width = width;
-					texture.image.height = height;
-					texture.needsUpdate = true;
-
-				} );
-
-			}
-
-			return texture;
-
-		};
-
-	}();
-
-	lutTextures.forEach( ( info ) => {
-
-		// if not size set get it from the filename
-		if ( ! info.size ) {
-
-			// assumes filename ends in '-s<num>[n]'
-			// where <num> is the size of the 3DLUT cube
-			// and [n] means 'no filtering' or 'nearest'
-			//
-			// examples:
-			//    'foo-s16.png' = size:16, filter: true
-			//    'bar-s8n.png' = size:8, filter: false
-			const m = /-s(\d+)(n*)\.[^.]+$/.exec( info.url );
-			if ( m ) {
-
-				info.size = parseInt( m[ 1 ] );
-				info.filter = info.filter === undefined ? m[ 2 ] !== 'n' : info.filter;
-
-			}
-
-			info.texture = makeLUTTexture( info );
-
-		} else {
-
-			info.texture = makeIdentityLutTexture( info.filter );
-
-		}
-
-	} );
-
-	const lutNameIndexMap = {};
-	lutTextures.forEach( ( info, ndx ) => {
-
-		lutNameIndexMap[ info.name ] = ndx;
-
-	} );
-
-	const lutSettings = {
-		lut: lutNameIndexMap.custom,
-	};
-	const gui = new GUI( { width: 300 } );
-	gui.add( lutSettings, 'lut', lutNameIndexMap );
-
-	const scene = new THREE.Scene();
-
-	const sceneBG = new THREE.Scene();
-	const cameraBG = new THREE.OrthographicCamera( - 1, 1, 1, - 1, - 1, 1 );
-
-	let bgMesh;
-	let bgTexture;
-	{
-
-		const loader = new THREE.TextureLoader();
-		bgTexture = loader.load( 'resources/images/beach.jpg' );
-		bgTexture.colorSpace = THREE.SRGBColorSpace;
-		const planeGeo = new THREE.PlaneGeometry( 2, 2 );
-		const planeMat = new THREE.MeshBasicMaterial( {
-			map: bgTexture,
-			depthTest: false,
-		} );
-		bgMesh = new THREE.Mesh( planeGeo, planeMat );
-		sceneBG.add( bgMesh );
-
-	}
-
-	function frameArea( sizeToFitOnScreen, boxSize, boxCenter, camera ) {
-
-		const halfSizeToFitOnScreen = sizeToFitOnScreen * 0.5;
-		const halfFovY = THREE.MathUtils.degToRad( camera.fov * .5 );
-		const distance = halfSizeToFitOnScreen / Math.tan( halfFovY );
-		// compute a unit vector that points in the direction the camera is now
-		// in the xz plane from the center of the box
-		const direction = ( new THREE.Vector3() )
-			.subVectors( camera.position, boxCenter )
-			.multiply( new THREE.Vector3( 1, 0, 1 ) )
-			.normalize();
-
-		// move the camera to a position distance units way from the center
-		// in whatever direction the camera was from the center already
-		camera.position.copy( direction.multiplyScalar( distance ).add( boxCenter ) );
-
-		// pick some near and far values for the frustum that
-		// will contain the box.
-		camera.near = boxSize / 100;
-		camera.far = boxSize * 100;
-
-		camera.updateProjectionMatrix();
-
-		// point the camera to look at the center of the box
-		camera.lookAt( boxCenter.x, boxCenter.y, boxCenter.z );
-
-	}
-
-	{
-
-		const gltfLoader = new GLTFLoader();
-		gltfLoader.load( 'resources/models/3dbustchallange_submission/scene.gltf', ( gltf ) => {
-
-			const root = gltf.scene;
-			scene.add( root );
-
-			// fix materials from r114
-			root.traverse( ( { material } ) => {
-
-				if ( material ) {
-
-					material.depthWrite = true;
-
-				}
-
-			} );
-
-			root.updateMatrixWorld();
-			// compute the box that contains all the stuff
-			// from root and below
-			const box = new THREE.Box3().setFromObject( root );
-
-			const boxSize = box.getSize( new THREE.Vector3() ).length();
-			const boxCenter = box.getCenter( new THREE.Vector3() );
-			frameArea( boxSize * 0.4, boxSize, boxCenter, camera );
-
-			// update the Trackball controls to handle the new size
-			controls.maxDistance = boxSize * 10;
-			controls.target.copy( boxCenter );
-			controls.update();
-
-		} );
-
-	}
-
-	const lutShader = {
-		uniforms: {
-			tDiffuse: { value: null },
-			lutMap: { value: null },
-			lutMapSize: { value: 1, },
-		},
-		vertexShader: `
-      varying vec2 vUv;
-      void main() {
-        vUv = uv;
-        gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
-      }
-    `,
-		fragmentShader: `
-      #include <common>
-
-      #define FILTER_LUT true
-
-      uniform sampler2D tDiffuse;
-      uniform sampler2D lutMap;
-      uniform float lutMapSize;
-
-      varying vec2 vUv;
-
-      vec4 sampleAs3DTexture(sampler2D tex, vec3 texCoord, float size) {
-        float sliceSize = 1.0 / size;                  // space of 1 slice
-        float slicePixelSize = sliceSize / size;       // space of 1 pixel
-        float width = size - 1.0;
-        float sliceInnerSize = slicePixelSize * width; // space of size pixels
-        float zSlice0 = floor( texCoord.z * width);
-        float zSlice1 = min( zSlice0 + 1.0, width);
-        float xOffset = slicePixelSize * 0.5 + texCoord.x * sliceInnerSize;
-        float yRange = (texCoord.y * width + 0.5) / size;
-        float s0 = xOffset + (zSlice0 * sliceSize);
-
-        #ifdef FILTER_LUT
-
-          float s1 = xOffset + (zSlice1 * sliceSize);
-          vec4 slice0Color = texture2D(tex, vec2(s0, yRange));
-          vec4 slice1Color = texture2D(tex, vec2(s1, yRange));
-          float zOffset = mod(texCoord.z * width, 1.0);
-          return mix(slice0Color, slice1Color, zOffset);
-
-        #else
-
-          return texture2D(tex, vec2( s0, yRange));
-
-        #endif
-      }
-
-      void main() {
-        vec4 originalColor = texture2D(tDiffuse, vUv);
-        gl_FragColor = sampleAs3DTexture(lutMap, originalColor.xyz, lutMapSize);
-      }
-    `,
-	};
-
-	const lutNearestShader = {
-		uniforms: { ...lutShader.uniforms },
-		vertexShader: lutShader.vertexShader,
-		fragmentShader: lutShader.fragmentShader.replace( '#define FILTER_LUT', '//' ),
-	};
-
-	const effectLUT = new ShaderPass( lutShader );
-	const effectLUTNearest = new ShaderPass( lutNearestShader );
-
-	const renderModel = new RenderPass( scene, camera );
-	renderModel.clear = false; // so we don't clear out the background
-	const renderBG = new RenderPass( sceneBG, cameraBG );
-	const outputPass = new OutputPass();
-
-	const composer = new EffectComposer( renderer );
-
-	composer.addPass( renderBG );
-	composer.addPass( renderModel );
-	composer.addPass( effectLUT );
-	composer.addPass( effectLUTNearest );
-	composer.addPass( outputPass );
-
-	function resizeRendererToDisplaySize( renderer ) {
-
-		const canvas = renderer.domElement;
-		const width = canvas.clientWidth * window.devicePixelRatio | 0;
-		const height = canvas.clientHeight * window.devicePixelRatio | 0;
-
-		const needResize = canvas.width !== width || canvas.height !== height;
-		if ( needResize ) {
-
-			renderer.setSize( width, height, false );
-
-		}
-
-		return needResize;
-
-	}
-
-	let then = 0;
-	function render( now ) {
-
-		now *= 0.001; // convert to seconds
-		const delta = now - then;
-		then = now;
-
-		if ( resizeRendererToDisplaySize( renderer ) ) {
-
-			const canvas = renderer.domElement;
-			const canvasAspect = canvas.clientWidth / canvas.clientHeight;
-			camera.aspect = canvasAspect;
-			camera.updateProjectionMatrix();
-			composer.setSize( canvas.width, canvas.height );
-
-			// scale the background plane to keep the image's
-			// aspect correct.
-			// Note the image may not have loaded yet.
-			const imageAspect = bgTexture.image ? bgTexture.image.width / bgTexture.image.height : 1;
-			const aspect = imageAspect / canvasAspect;
-			bgMesh.scale.x = aspect > 1 ? aspect : 1;
-			bgMesh.scale.y = aspect > 1 ? 1 : 1 / aspect;
-
-		}
-
-		const lutInfo = lutTextures[ lutSettings.lut ];
-
-		const effect = lutInfo.filter ? effectLUT : effectLUTNearest;
-		effectLUT.enabled = lutInfo.filter;
-		effectLUTNearest.enabled = ! lutInfo.filter;
-
-		const lutTexture = lutInfo.texture;
-		effect.uniforms.lutMap.value = lutTexture;
-		effect.uniforms.lutMapSize.value = lutInfo.size;
-
-		composer.render( delta );
-
-		requestAnimationFrame( render );
-
-	}
-
-	requestAnimationFrame( render );
-
-	dragAndDrop.setup( { msg: 'Drop LUT File here' } );
-	dragAndDrop.onDropFile( readLUTFile );
-
-	function ext( s ) {
-
-		const period = s.lastIndexOf( '.' );
-		return s.slice( period + 1 );
-
-	}
-
-	function readLUTFile( file ) {
-
-		const reader = new FileReader();
-		reader.onload = ( e ) => {
-
-			const type = ext( file.name );
-			const lut = lutParser.lutTo2D3Drgba8( lutParser.parse( e.target.result, type ) );
-			const { size, data, name } = lut;
-			const texture = new THREE.DataTexture( data, size * size, size );
-			texture.magFilter = THREE.LinearFilter;
-			texture.minFilter = THREE.LinearFilter;
-			texture.needsUpdate = true;
-			texture.flipY = false;
-			const lutTexture = {
-				name: ( name && name.toLowerCase().trim() !== 'untitled' )
-					? name
-					: file.name,
-				size: size,
-				filter: true,
-				texture,
-			};
-			lutTextures.push( lutTexture );
-			lutSettings.lut = lutTextures.length - 1;
-
-		};
-
-		reader.readAsText( file );
-
-	}
-
-}
-
-main();
-</script>
-</html>

+ 0 - 423
manual/examples/postprocessing-3dlut.html

@@ -1,423 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-  <head>
-    <title>Three.js - postprocessing - 3DLUT</title>
-    <meta charset="utf-8">
-    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-    <style>
-    html, body {
-        margin: 0;
-        height: 100%;
-    }
-    #c {
-        width: 100%;
-        height: 100%;
-        display: block;
-    }
-  </style>
-  </head>
-  <body>
-    <canvas id="c"></canvas>
-  </body>
-<script type="importmap">
-{
-  "imports": {
-    "three": "../../build/three.module.js",
-    "three/addons/": "../../examples/jsm/"
-  }
-}
-</script>
-
-<script type="module">
-import * as THREE from 'three';
-import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
-import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
-import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
-import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
-import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
-import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
-import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
-
-function main() {
-
-	const canvas = document.querySelector( '#c' );
-	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
-
-	const fov = 45;
-	const aspect = 2; // the canvas default
-	const near = 0.1;
-	const far = 100;
-	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
-	camera.position.set( 0, 10, 20 );
-
-	const controls = new OrbitControls( camera, canvas );
-	controls.target.set( 0, 5, 0 );
-	controls.update();
-
-	const lutTextures = [
-		{ name: 'identity', size: 2, filter: true, },
-		{ name: 'identity no filter', size: 2, filter: false, },
-		{ name: 'custom', url: 'resources/images/lut/3dlut-red-only-s16.png' },
-		{ name: 'monochrome', url: 'resources/images/lut/monochrome-s8.png' },
-		{ name: 'sepia', url: 'resources/images/lut/sepia-s8.png' },
-		{ name: 'saturated', url: 'resources/images/lut/saturated-s8.png', },
-		{ name: 'posterize', url: 'resources/images/lut/posterize-s8n.png', },
-		{ name: 'posterize-3-rgb', url: 'resources/images/lut/posterize-3-rgb-s8n.png', },
-		{ name: 'posterize-3-lab', url: 'resources/images/lut/posterize-3-lab-s8n.png', },
-		{ name: 'posterize-4-lab', url: 'resources/images/lut/posterize-4-lab-s8n.png', },
-		{ name: 'posterize-more', url: 'resources/images/lut/posterize-more-s8n.png', },
-		{ name: 'inverse', url: 'resources/images/lut/inverse-s8.png', },
-		{ name: 'color negative', url: 'resources/images/lut/color-negative-s8.png', },
-		{ name: 'high contrast', url: 'resources/images/lut/high-contrast-bw-s8.png', },
-		{ name: 'funky contrast', url: 'resources/images/lut/funky-contrast-s8.png', },
-		{ name: 'nightvision', url: 'resources/images/lut/nightvision-s8.png', },
-		{ name: 'thermal', url: 'resources/images/lut/thermal-s8.png', },
-		{ name: 'b/w', url: 'resources/images/lut/black-white-s8n.png', },
-		{ name: 'hue +60', url: 'resources/images/lut/hue-plus-60-s8.png', },
-		{ name: 'hue +180', url: 'resources/images/lut/hue-plus-180-s8.png', },
-		{ name: 'hue -60', url: 'resources/images/lut/hue-minus-60-s8.png', },
-		{ name: 'red to cyan', url: 'resources/images/lut/red-to-cyan-s8.png' },
-		{ name: 'blues', url: 'resources/images/lut/blues-s8.png' },
-		{ name: 'infrared', url: 'resources/images/lut/infrared-s8.png' },
-		{ name: 'radioactive', url: 'resources/images/lut/radioactive-s8.png' },
-		{ name: 'goolgey', url: 'resources/images/lut/googley-s8.png' },
-		{ name: 'bgy', url: 'resources/images/lut/bgy-s8.png' },
-	];
-
-	const makeIdentityLutTexture = function () {
-
-		const identityLUT = new Uint8Array( [
-			0, 0, 0, 255, // black
-			255, 0, 0, 255, // red
-			0, 0, 255, 255, // blue
-			255, 0, 255, 255, // magenta
-			0, 255, 0, 255, // green
-			255, 255, 0, 255, // yellow
-			0, 255, 255, 255, // cyan
-			255, 255, 255, 255, // white
-		] );
-
-		return function ( filter ) {
-
-			const texture = new THREE.DataTexture( identityLUT, 4, 2 );
-			texture.minFilter = texture.magFilter = filter ? THREE.LinearFilter : THREE.NearestFilter;
-			texture.needsUpdate = true;
-			texture.flipY = false;
-			return texture;
-
-		};
-
-	}();
-
-	const makeLUTTexture = function () {
-
-		const imgLoader = new THREE.ImageLoader();
-		const ctx = document.createElement( 'canvas' ).getContext( '2d' );
-
-		return function ( info ) {
-
-			const lutSize = info.size;
-			const width = lutSize * lutSize;
-			const height = lutSize;
-			const texture = new THREE.DataTexture( new Uint8Array( width * height ), width, height );
-			texture.minFilter = texture.magFilter = info.filter ? THREE.LinearFilter : THREE.NearestFilter;
-			texture.flipY = false;
-
-			if ( info.url ) {
-
-				imgLoader.load( info.url, function ( image ) {
-
-					ctx.canvas.width = width;
-					ctx.canvas.height = height;
-					ctx.drawImage( image, 0, 0 );
-					const imageData = ctx.getImageData( 0, 0, width, height );
-
-					texture.image.data = new Uint8Array( imageData.data.buffer );
-					texture.image.width = width;
-					texture.image.height = height;
-					texture.needsUpdate = true;
-
-				} );
-
-			}
-
-			return texture;
-
-		};
-
-	}();
-
-	lutTextures.forEach( ( info ) => {
-
-		// if not size set get it from the filename
-		if ( ! info.size ) {
-
-			// assumes filename ends in '-s<num>[n]'
-			// where <num> is the size of the 3DLUT cube
-			// and [n] means 'no filtering' or 'nearest'
-			//
-			// examples:
-			//    'foo-s16.png' = size:16, filter: true
-			//    'bar-s8n.png' = size:8, filter: false
-			const m = /-s(\d+)(n*)\.[^.]+$/.exec( info.url );
-			if ( m ) {
-
-				info.size = parseInt( m[ 1 ] );
-				info.filter = info.filter === undefined ? m[ 2 ] !== 'n' : info.filter;
-
-			}
-
-			info.texture = makeLUTTexture( info );
-
-		} else {
-
-			info.texture = makeIdentityLutTexture( info.filter );
-
-		}
-
-	} );
-
-	const lutNameIndexMap = {};
-	lutTextures.forEach( ( info, ndx ) => {
-
-		lutNameIndexMap[ info.name ] = ndx;
-
-	} );
-
-	const lutSettings = {
-		lut: lutNameIndexMap.custom,
-	};
-	const gui = new GUI( { width: 300 } );
-	gui.add( lutSettings, 'lut', lutNameIndexMap );
-
-	const scene = new THREE.Scene();
-
-	const sceneBG = new THREE.Scene();
-	const cameraBG = new THREE.OrthographicCamera( - 1, 1, 1, - 1, - 1, 1 );
-
-	let bgMesh;
-	let bgTexture;
-	{
-
-		const loader = new THREE.TextureLoader();
-		bgTexture = loader.load( 'resources/images/beach.jpg' );
-		bgTexture.colorSpace = THREE.SRGBColorSpace;
-		const planeGeo = new THREE.PlaneGeometry( 2, 2 );
-		const planeMat = new THREE.MeshBasicMaterial( {
-			map: bgTexture,
-			depthTest: false,
-		} );
-		bgMesh = new THREE.Mesh( planeGeo, planeMat );
-		sceneBG.add( bgMesh );
-
-	}
-
-	function frameArea( sizeToFitOnScreen, boxSize, boxCenter, camera ) {
-
-		const halfSizeToFitOnScreen = sizeToFitOnScreen * 0.5;
-		const halfFovY = THREE.MathUtils.degToRad( camera.fov * .5 );
-		const distance = halfSizeToFitOnScreen / Math.tan( halfFovY );
-		// compute a unit vector that points in the direction the camera is now
-		// in the xz plane from the center of the box
-		const direction = ( new THREE.Vector3() )
-			.subVectors( camera.position, boxCenter )
-			.multiply( new THREE.Vector3( 1, 0, 1 ) )
-			.normalize();
-
-		// move the camera to a position distance units way from the center
-		// in whatever direction the camera was from the center already
-		camera.position.copy( direction.multiplyScalar( distance ).add( boxCenter ) );
-
-		// pick some near and far values for the frustum that
-		// will contain the box.
-		camera.near = boxSize / 100;
-		camera.far = boxSize * 100;
-
-		camera.updateProjectionMatrix();
-
-		// point the camera to look at the center of the box
-		camera.lookAt( boxCenter.x, boxCenter.y, boxCenter.z );
-
-	}
-
-	{
-
-		const gltfLoader = new GLTFLoader();
-		gltfLoader.load( 'resources/models/3dbustchallange_submission/scene.gltf', ( gltf ) => {
-
-			const root = gltf.scene;
-			scene.add( root );
-
-			// fix materials from r114
-			root.traverse( ( { material } ) => {
-
-				if ( material ) {
-
-					material.depthWrite = true;
-
-				}
-
-			} );
-
-			root.updateMatrixWorld();
-			// compute the box that contains all the stuff
-			// from root and below
-			const box = new THREE.Box3().setFromObject( root );
-
-			const boxSize = box.getSize( new THREE.Vector3() ).length();
-			const boxCenter = box.getCenter( new THREE.Vector3() );
-			frameArea( boxSize * 0.4, boxSize, boxCenter, camera );
-
-			// update the Trackball controls to handle the new size
-			controls.maxDistance = boxSize * 10;
-			controls.target.copy( boxCenter );
-			controls.update();
-
-		} );
-
-	}
-
-	const lutShader = {
-		uniforms: {
-			tDiffuse: { value: null },
-			lutMap: { value: null },
-			lutMapSize: { value: 1, },
-		},
-		vertexShader: `
-      varying vec2 vUv;
-      void main() {
-        vUv = uv;
-        gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
-      }
-    `,
-		fragmentShader: `
-      #include <common>
-
-      #define FILTER_LUT true
-
-      uniform sampler2D tDiffuse;
-      uniform sampler2D lutMap;
-      uniform float lutMapSize;
-
-      varying vec2 vUv;
-
-      vec4 sampleAs3DTexture(sampler2D tex, vec3 texCoord, float size) {
-        float sliceSize = 1.0 / size;                  // space of 1 slice
-        float slicePixelSize = sliceSize / size;       // space of 1 pixel
-        float width = size - 1.0;
-        float sliceInnerSize = slicePixelSize * width; // space of size pixels
-        float zSlice0 = floor( texCoord.z * width);
-        float zSlice1 = min( zSlice0 + 1.0, width);
-        float xOffset = slicePixelSize * 0.5 + texCoord.x * sliceInnerSize;
-        float yRange = (texCoord.y * width + 0.5) / size;
-        float s0 = xOffset + (zSlice0 * sliceSize);
-
-        #ifdef FILTER_LUT
-
-          float s1 = xOffset + (zSlice1 * sliceSize);
-          vec4 slice0Color = texture2D(tex, vec2(s0, yRange));
-          vec4 slice1Color = texture2D(tex, vec2(s1, yRange));
-          float zOffset = mod(texCoord.z * width, 1.0);
-          return mix(slice0Color, slice1Color, zOffset);
-
-        #else
-
-          return texture2D(tex, vec2( s0, yRange));
-
-        #endif
-      }
-
-      void main() {
-        vec4 originalColor = texture2D(tDiffuse, vUv);
-        gl_FragColor = sampleAs3DTexture(lutMap, originalColor.xyz, lutMapSize);
-      }
-    `,
-	};
-
-	const lutNearestShader = {
-		uniforms: { ...lutShader.uniforms },
-		vertexShader: lutShader.vertexShader,
-		fragmentShader: lutShader.fragmentShader.replace( '#define FILTER_LUT', '//' ),
-	};
-
-	const effectLUT = new ShaderPass( lutShader );
-	const effectLUTNearest = new ShaderPass( lutNearestShader );
-
-	const renderModel = new RenderPass( scene, camera );
-	renderModel.clear = false; // so we don't clear out the background
-	const renderBG = new RenderPass( sceneBG, cameraBG );
-	const outputPass = new OutputPass();
-
-	const composer = new EffectComposer( renderer );
-
-	composer.addPass( renderBG );
-	composer.addPass( renderModel );
-	composer.addPass( effectLUT );
-	composer.addPass( effectLUTNearest );
-	composer.addPass( outputPass );
-
-	function resizeRendererToDisplaySize( renderer ) {
-
-		const canvas = renderer.domElement;
-		const width = canvas.clientWidth * window.devicePixelRatio | 0;
-		const height = canvas.clientHeight * window.devicePixelRatio | 0;
-
-		const needResize = canvas.width !== width || canvas.height !== height;
-		if ( needResize ) {
-
-			renderer.setSize( width, height, false );
-
-		}
-
-		return needResize;
-
-	}
-
-	let then = 0;
-	function render( now ) {
-
-		now *= 0.001; // convert to seconds
-		const delta = now - then;
-		then = now;
-
-		if ( resizeRendererToDisplaySize( renderer ) ) {
-
-			const canvas = renderer.domElement;
-			const canvasAspect = canvas.clientWidth / canvas.clientHeight;
-			camera.aspect = canvasAspect;
-			camera.updateProjectionMatrix();
-			composer.setSize( canvas.width, canvas.height );
-
-			// scale the background plane to keep the image's
-			// aspect correct.
-			// Note the image may not have loaded yet.
-			const imageAspect = bgTexture.image ? bgTexture.image.width / bgTexture.image.height : 1;
-			const aspect = imageAspect / canvasAspect;
-			bgMesh.scale.x = aspect > 1 ? aspect : 1;
-			bgMesh.scale.y = aspect > 1 ? 1 : 1 / aspect;
-
-		}
-
-		const lutInfo = lutTextures[ lutSettings.lut ];
-
-		const effect = lutInfo.filter ? effectLUT : effectLUTNearest;
-		effectLUT.enabled = lutInfo.filter;
-		effectLUTNearest.enabled = ! lutInfo.filter;
-
-		const lutTexture = lutInfo.texture;
-		effect.uniforms.lutMap.value = lutTexture;
-		effect.uniforms.lutMapSize.value = lutInfo.size;
-
-		composer.render( delta );
-
-		requestAnimationFrame( render );
-
-	}
-
-	requestAnimationFrame( render );
-
-}
-
-main();
-</script>
-</html>

+ 0 - 285
manual/examples/postprocessing-adobe-lut-to-png-converter.html

@@ -1,285 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-  <head>
-    <title>Three.js - postprocessing - 3DLUT w/loader</title>
-    <meta charset="utf-8">
-    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-    <style>
-    html, body {
-      min-height: 100%;
-      font-family: monospace;
-      background: #222;
-      color: white;
-    }
-    canvas {
-      min-width: 512px;
-      min-height: 64px;
-      image-rendering: pixelated;
-    }
-    #cube {
-      max-width: calc(100% - 20px);
-      overflow: auto;
-    }
-  </style>
-  </head>
-  <body>
-    <h1>Adobe LUT to PNG converter</h1>
-    <p>Drag and drop a LUT file here</p>
-    <div>size:<input id="size" type="number" value="8" min="2" max="64"/></div>
-    <p id="result"></p>
-    <p><button type="button">Save...</button></p>
-    <div id="cube"><canvas id="c"></canvas></div>
-  </body>
-<script type="importmap">
-{
-  "imports": {
-    "three": "../../build/three.module.js",
-    "three/addons/": "../../examples/jsm/"
-  }
-}
-</script>
-
-<script type="module">
-import * as THREE from 'three';
-import * as lutParser from './resources/lut-reader.js';
-import * as dragAndDrop from './resources/drag-and-drop.js';
-import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
-import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
-import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
-
-function main() {
-
-	const canvas = document.querySelector( '#c' );
-	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
-
-	const makeIdentityLutTexture = function () {
-
-		const identityLUT = new Uint8Array( [
-			0, 0, 0, 255, // black
-			255, 0, 0, 255, // red
-			0, 0, 255, 255, // blue
-			255, 0, 255, 255, // magenta
-			0, 255, 0, 255, // green
-			255, 255, 0, 255, // yellow
-			0, 255, 255, 255, // cyan
-			255, 255, 255, 255, // white
-		] );
-
-		return function ( filter ) {
-
-			const texture = new THREE.DataTexture( identityLUT, 4, 2 );
-			texture.minFilter = filter;
-			texture.magFilter = filter;
-			texture.needsUpdate = true;
-			texture.flipY = false;
-			return texture;
-
-		};
-
-	}();
-
-	const sceneBG = new THREE.Scene();
-	const cameraBG = new THREE.OrthographicCamera( - 1, 1, 1, - 1, - 1, 1 );
-
-	const ctx = document.createElement( 'canvas' ).getContext( '2d' );
-	function drawColorCubeImage( ctx, size ) {
-
-		const canvas = ctx.canvas;
-		canvas.width = size * size;
-		canvas.height = size;
-
-		for ( let zz = 0; zz < size; ++ zz ) {
-
-			for ( let yy = 0; yy < size; ++ yy ) {
-
-				for ( let xx = 0; xx < size; ++ xx ) {
-
-					const r = Math.floor( xx / ( size - 1 ) * 255 );
-					const g = Math.floor( yy / ( size - 1 ) * 255 );
-					const b = Math.floor( zz / ( size - 1 ) * 255 );
-					ctx.fillStyle = `rgb(${r},${g},${b})`;
-					ctx.fillRect( zz * size + xx, yy, 1, 1 );
-
-				}
-
-			}
-
-		}
-
-	}
-
-	const idTexture = new THREE.CanvasTexture( ctx.canvas );
-	idTexture.magFilter = THREE.NearestFilter;
-	idTexture.minFilter = THREE.NearestFilter;
-
-	{
-
-		const planeGeo = new THREE.PlaneGeometry( 2, 2 );
-		const planeMat = new THREE.MeshBasicMaterial( {
-			map: idTexture,
-			depthTest: false,
-		} );
-		sceneBG.add( new THREE.Mesh( planeGeo, planeMat ) );
-
-	}
-
-	const lutShader = {
-		uniforms: {
-			tDiffuse: { value: null },
-			lutMap: { value: null },
-			lutMapSize: { value: 1, },
-		},
-		vertexShader: `
-      varying vec2 vUv;
-      void main() {
-        vUv = uv;
-        gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
-      }
-    `,
-		fragmentShader: `
-      #include <common>
-
-      #define FILTER_LUT true
-
-      uniform sampler2D tDiffuse;
-      uniform sampler2D lutMap;
-      uniform float lutMapSize;
-
-      varying vec2 vUv;
-
-      vec4 sampleAs3DTexture(sampler2D tex, vec3 texCoord, float size) {
-        float sliceSize = 1.0 / size;                  // space of 1 slice
-        float slicePixelSize = sliceSize / size;       // space of 1 pixel
-        float width = size - 1.0;
-        float sliceInnerSize = slicePixelSize * width; // space of size pixels
-        float zSlice0 = floor( texCoord.z * width);
-        float zSlice1 = min( zSlice0 + 1.0, width);
-        float xOffset = slicePixelSize * 0.5 + texCoord.x * sliceInnerSize;
-        float yRange = (texCoord.y * width + 0.5) / size;
-        float s0 = xOffset + (zSlice0 * sliceSize);
-
-        #ifdef FILTER_LUT
-
-          float s1 = xOffset + (zSlice1 * sliceSize);
-          vec4 slice0Color = texture2D(tex, vec2(s0, yRange));
-          vec4 slice1Color = texture2D(tex, vec2(s1, yRange));
-          float zOffset = mod(texCoord.z * width, 1.0);
-          return mix(slice0Color, slice1Color, zOffset);
-
-        #else
-
-          return texture2D(tex, vec2( s0, yRange));
-
-        #endif
-      }
-
-      void main() {
-        vec4 originalColor = texture2D(tDiffuse, vUv);
-        gl_FragColor = sampleAs3DTexture(lutMap, originalColor.xyz, lutMapSize);
-      }
-    `,
-	};
-
-	const effectLUT = new ShaderPass( lutShader );
-
-	const renderBG = new RenderPass( sceneBG, cameraBG );
-
-	const rtParameters = {
-		minFilter: THREE.NearestFilter,
-		magFilter: THREE.NearestFilter
-	};
-	const composer = new EffectComposer( renderer, new THREE.WebGLRenderTarget( 1, 1, rtParameters ) );
-
-	composer.addPass( renderBG );
-	composer.addPass( effectLUT );
-
-	let name = 'identity';
-	const lutTexture = makeIdentityLutTexture( THREE.LinearFilter );
-	effectLUT.uniforms.lutMap.value = lutTexture;
-	effectLUT.uniforms.lutMapSize.value = 2;
-
-	const sizeElem = document.querySelector( '#size' );
-	sizeElem.addEventListener( 'change', render );
-
-	function render() {
-
-		const size = parseInt( sizeElem.value );
-		renderer.setSize( size * size, size, false );
-		composer.setSize( size * size, size );
-
-		drawColorCubeImage( ctx, size );
-		idTexture.needsUpdate = true;
-
-		composer.render( 0 );
-
-	}
-
-	render();
-
-	dragAndDrop.setup( { msg: 'Drop LUT File here' } );
-	dragAndDrop.onDropFile( readLUTFile );
-
-	function ext( s ) {
-
-		const period = s.lastIndexOf( '.' );
-		return s.slice( period + 1 );
-
-	}
-
-	function readLUTFile( file ) {
-
-		const reader = new FileReader();
-		reader.onload = ( e ) => {
-
-			const type = ext( file.name );
-			const lut = lutParser.lutTo2D3Drgba8( lutParser.parse( e.target.result, type ) );
-
-			effectLUT.uniforms.lutMapSize.value = lut.size;
-
-			lutTexture.image.data = lut.data;
-			lutTexture.image.width = lut.size * lut.size;
-			lutTexture.image.height = lut.size;
-			lutTexture.needsUpdate = true;
-
-			render();
-			name = `${file.name || lut.name || 'untitled'}`;
-			document.querySelector( '#result' ).textContent = `loaded: ${name}`;
-
-		};
-
-		reader.readAsText( file );
-
-	}
-
-	const saveData = ( function () {
-
-		const a = document.createElement( 'a' );
-		document.body.appendChild( a );
-		a.style.display = 'none';
-		return function saveData( blob, fileName ) {
-
-			const url = window.URL.createObjectURL( blob );
-			a.href = url;
-			a.download = fileName;
-			a.click();
-
-		};
-
-	}() );
-
-	document.querySelector( 'button' ).addEventListener( 'click', () => {
-
-		render();
-		renderer.domElement.toBlob( ( blob ) => {
-
-			saveData( blob, `${name}-s${renderer.domElement.height}.png` );
-
-		} );
-
-	} );
-
-}
-
-main();
-</script>
-</html>

+ 0 - 42
manual/fr/post-processing-3dlut.html

@@ -1,42 +0,0 @@
-<!DOCTYPE html><html lang="fr"><head>
-    <meta charset="utf-8">
-    <title>Post Processing 3DLUT</title>
-    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-    <meta name="twitter:card" content="summary_large_image">
-    <meta name="twitter:site" content="@threejs">
-    <meta name="twitter:title" content="Three.js – Post Processing 3DLUT">
-    <meta property="og:image" content="https://threejs.org/files/share.png">
-    <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
-    <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
-
-    <link rel="stylesheet" href="../resources/lesson.css">
-    <link rel="stylesheet" href="../resources/lang.css">
-<script type="importmap">
-{
-  "imports": {
-    "three": "../../build/three.module.js"
-  }
-}
-</script>
-  </head>
-  <body>
-    <div class="container">
-      <div class="lesson-title">
-        <h1>Post Processing 3DLUT</h1>
-      </div>
-      <div class="lesson">
-        <div class="lesson-main">
-          <p>Désolé, cet article n'a pas encore été traduit. <a href="https://github.com/mrdoob/three.js">Les traductions sont le bienvenue</a>! 😄</p>
-<p><a href="/manual/en/post-processing-3dlut.html">Voici l'article anglais originel pour le moment</a>.</p>
-
-        </div>
-      </div>
-    </div>
-
-  <script src="../resources/prettify.js"></script>
-  <script src="../resources/lesson.js"></script>
-
-
-
-
-</body></html>

+ 0 - 488
manual/ja/post-processing-3dlut.html

@@ -1,488 +0,0 @@
-<!DOCTYPE html><html lang="ja"><head>
-    <meta charset="utf-8">
-    <title>の3DLUTポストプロセス</title>
-    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-    <meta name="twitter:card" content="summary_large_image">
-    <meta name="twitter:site" content="@threejs">
-    <meta name="twitter:title" content="Three.js – の3DLUTポストプロセス">
-    <meta property="og:image" content="https://threejs.org/files/share.png">
-    <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
-    <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
-
-    <link rel="stylesheet" href="../resources/lesson.css">
-    <link rel="stylesheet" href="../resources/lang.css">
-<script type="importmap">
-{
-  "imports": {
-    "three": "../../build/three.module.js"
-  }
-}
-</script>
-  </head>
-  <body>
-    <div class="container">
-      <div class="lesson-title">
-        <h1>の3DLUTポストプロセス</h1>
-      </div>
-      <div class="lesson">
-        <div class="lesson-main">
-          <p>前回の記事では<a href="post-processing.html">ポストプロセス</a>の説明をしました。
-ポストプロセスの一般的な方法の1つにLUT(ラット)や3DLUT(3次元ラット)と呼ばれるものがあります。
-LUTはルックアップテーブル(参照対応表)の略です。したがって、3DLUTは3次元のルックアップテーブルです。</p>
-<p>3DLUTがどのように機能するかというとカラーのキューブを作ります。
-元となる画像のカラーを使い、キューブにインデックスを作成します。
-元画像の各ピクセルに対して、赤、緑、青のカラーに基づいてキューブの位置を調べます。
-キューブの位置が3DLUTから引き出した新しいカラーとなります。</p>
-<p>Javascriptでは次のようにします。
-カラーは0〜255までの整数で指定されており、サイズが256 x 256 x 256の大きな3次元配列があると想像して下さい。
-ルックアップテーブルを通してカラーを変換します。</p>
-<pre class="prettyprint showlinemods notranslate notranslate" translate="no">const newColor = lut[origColor.red][origColor.green][origColor.bue]
-</pre><p>もちろん、256 x 256 x 256の配列はかなり大きいですが、<a href="textures.html">テクスチャの記事</a>で指摘したようにテクスチャの寸法に関係なく0.0~1.0の値を参照します。</p>
-<p>8 × 8 × 8のキューブを想像してみましょう。</p>
-<div class="threejs_center"><img src="../resources/images/3dlut-rgb.svg" class="noinvertdark" style="width: 500px"></div>
-
-<p>最初に0, 0, 0の位置の角は黒にし、反対の1, 1, 1の角は白にします。
-1, 0, 0は<span style="color:red;">赤</span>です。
-0, 1, 0は<span style="color:green;">緑</span>で0, 0, 1は<span style="color:blue;">青</span>にします。</p>
-<div class="threejs_center"><img src="../resources/images/3dlut-axis.svg" class="noinvertdark" style="width: 500px"></div>
-
-<p>各軸線にカラーを追加していきます。</p>
-<div class="threejs_center"><img src="../resources/images/3dlut-edges.svg" class="noinvertdark" style="width: 500px"></div>
-
-<p>2チャンネル以上を使用するエッジのカラーです。</p>
-<div class="threejs_center"><img src="../resources/images/3dlut-standard.svg" class="noinvertdark" style="width: 500px"></div>
-
-<p>最後に中間にあるカラーも全て埋めます。
-これは"同一性"の3DLUTです。入力と全く同じ出力を生成します。
-もし色を入力して調べれば、入力と同じカラーが出力されます。</p>
-<div class="threejs_center"><object type="image/svg+xml" data="resources/images/3dlut-standard-lookup.svg" class="noinvertdark" data-diagram="lookup" style="width: 600px"></object></div>
-
-<p>キューブをシェーダーで琥珀色に変更し3Dルックアップテーブルの同じ場所を調べると、異なる出力が得られます。</p>
-<div class="threejs_center"><object type="image/svg+xml" data="resources/images/3dlut-amber-lookup.svg" class="noinvertdark" data-diagram="lookup" style="width: 600px"></object></div>
-
-<p>別のルックアップテーブルを提供してこの技術を使用すると、全種類の効果を適用できます。
-基本的には単一のカラー入力のみを計算できる効果です。
-これらの効果には色相、コントラスト、彩度、カラーキャスト、色合い、明るさ、露出、レベル、カーブ、ポスタライズ、シャドウ、ハイライト、その他多くの調整が含まれます。
-これが優れている点は全て1つのルックアップテーブルにまとめられてます。</p>
-<p>これを使用するには適用するシーンが必要です。
-ちょっとしたシーンにこれを適用してみましょう。
-まずは<a href="load-gltf.html">glTFを読み込む記事</a>で取り上げたようにglTFファイルを表示する所から始めてみます。
-載せているモデルは<a href="https://sketchfab.com/sarath.irn.kat005">氷の狼</a>の<a href="https://sketchfab.com/models/a1d315908e9f45e5a3bc618bdfd2e7ee">このモデル</a>です。
-ライトは使わないので削除しました。</p>
-<p><a href="backgrounds.html">背景とスカイボックス</a>で説明したような背景画像も追加します。</p>
-<p></p><div translate="no" class="threejs_example_container notranslate">
-  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/postprocessing-3dlut-prep.html"></iframe></div>
-  <a class="threejs_center" href="/manual/examples/postprocessing-3dlut-prep.html" target="_blank">ここをクリックして別のウィンドウで開きます</a>
-</div>
-
-<p></p>
-<p>シーンがあるので3DLUTが必要です。
-最も単純な3DLUTは2 x 2 x 2の同一性LUTです。<em>同一性</em>とは何も起こらない事を意味します。
-1を掛けるようなもので、LUTでカラーを調べているにも関わらず、入力カラーと同じ出力カラーがマップされてます。</p>
-<div class="threejs_center"><img src="../resources/images/3dlut-standard-2x2.svg" class="noinvertdark" style="width: 200px"></div>
-
-<p>WebGL1は3Dテクスチャは非サポートのため、4 x 2の2Dテクスチャを使用しカスタムシェーダーの中で3Dテクスチャとして扱います。
-カスタムシェーダーではキューブの各切片がテクスチャ全体に水平に広がっています。</p>
-<p>以下はidentityLUTに必要なカラーで4 x 2の2Dテクスチャを作るコードです。</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const makeIdentityLutTexture = function() {
-  const identityLUT = new Uint8Array([
-      0,   0,   0, 255,  // black
-    255,   0,   0, 255,  // red
-      0,   0, 255, 255,  // blue
-    255,   0, 255, 255,  // magenta
-      0, 255,   0, 255,  // green
-    255, 255,   0, 255,  // yellow
-      0, 255, 255, 255,  // cyan
-    255, 255, 255, 255,  // white
-  ]);
-
-  return function(filter) {
-    const texture = new THREE.DataTexture(identityLUT, 4, 2, THREE.RGBAFormat);
-    texture.minFilter = filter;
-    texture.magFilter = filter;
-    texture.needsUpdate = true;
-    texture.flipY = false;
-    return texture;
-  };
-}();
-</pre>
-<p>フィルターをかけたテクステャ、かけていないテクステャの2つを作ります。</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const lutTextures = [
-  { name: 'identity', size: 2, texture: makeIdentityLutTexture(THREE.LinearFilter) },
-  { name: 'identity not filtered', size: 2, texture: makeIdentityLutTexture(THREE.NearestFilter) },
-];
-</pre>
-<p><a href="post-processing.html">ポストプロセスの記事</a>のカスタムシェーダーを使った例を参考に、2つのカスタムシェーダーを使ってみましょう。</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const lutShader = {
-  uniforms: {
-    tDiffuse: { value: null },
-    lutMap:  { value: null },
-    lutMapSize: { value: 1, },
-  },
-  vertexShader: `
-    varying vec2 vUv;
-    void main() {
-      vUv = uv;
-      gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
-    }
-  `,
-  fragmentShader: `
-    #include &lt;common&gt;
-
-    #define FILTER_LUT true
-
-    uniform sampler2D tDiffuse;
-    uniform sampler2D lutMap;
-    uniform float lutMapSize;
-
-    varying vec2 vUv;
-
-    vec4 sampleAs3DTexture(sampler2D tex, vec3 texCoord, float size) {
-      float sliceSize = 1.0 / size;                  // space of 1 slice
-      float slicePixelSize = sliceSize / size;       // space of 1 pixel
-      float width = size - 1.0;
-      float sliceInnerSize = slicePixelSize * width; // space of size pixels
-      float zSlice0 = floor( texCoord.z * width);
-      float zSlice1 = min( zSlice0 + 1.0, width);
-      float xOffset = slicePixelSize * 0.5 + texCoord.x * sliceInnerSize;
-      float yRange = (texCoord.y * width + 0.5) / size;
-      float s0 = xOffset + (zSlice0 * sliceSize);
-
-      #ifdef FILTER_LUT
-
-        float s1 = xOffset + (zSlice1 * sliceSize);
-        vec4 slice0Color = texture2D(tex, vec2(s0, yRange));
-        vec4 slice1Color = texture2D(tex, vec2(s1, yRange));
-        float zOffset = mod(texCoord.z * width, 1.0);
-        return mix(slice0Color, slice1Color, zOffset);
-
-      #else
-
-        return texture2D(tex, vec2( s0, yRange));
-
-      #endif
-    }
-
-    void main() {
-      vec4 originalColor = texture2D(tDiffuse, vUv);
-      gl_FragColor = sampleAs3DTexture(lutMap, originalColor.xyz, lutMapSize);
-    }
-  `,
-};
-
-const lutNearestShader = {
-  uniforms: {...lutShader.uniforms},
-  vertexShader: lutShader.vertexShader,
-  fragmentShader: lutShader.fragmentShader.replace('#define FILTER_LUT', '//'),
-};
-</pre>
-<p>フラグメントシェーダーの中に次のような行があるのが分かります。</p>
-<pre class="prettyprint showlinemods notranslate lang-glsl" translate="no">#define FILTER_LUT true
-</pre>
-<p>2番目のシェーダーを生成するためにその行をコメントアウトします。</p>
-<p>これらを使用して2つのカスタムエフェクトを作成します。</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const effectLUT = new THREE.ShaderPass(lutShader);
-const effectLUTNearest = new THREE.ShaderPass(lutNearestShader);
-</pre>
-<p>背景を別のシーンに描画する既存コードを変更し、glTFと背景を描画するシーンの両方に <code class="notranslate" translate="no">RenderPass</code> を適用します。</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const renderModel = new THREE.RenderPass(scene, camera);
-renderModel.clear = false;  // so we don't clear out the background
-const renderBG = new THREE.RenderPass(sceneBG, cameraBG);
-</pre>
-<p>全てのパスを使用するように <code class="notranslate" translate="no">EffectComposer</code> を設定できます。</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const composer = new THREE.EffectComposer(renderer);
-
-composer.addPass(renderBG);
-composer.addPass(renderModel);
-composer.addPass(effectLUT);
-composer.addPass(effectLUTNearest);
-composer.addPass(gammaPass);
-</pre>
-<p>LUTを選択するためのGUIコードを作ってみましょう。</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const lutNameIndexMap = {};
-lutTextures.forEach((info, ndx) =&gt; {
-  lutNameIndexMap[info.name] = ndx;
-});
-
-const lutSettings = {
-  lut: lutNameIndexMap.identity,
-};
-const gui = new GUI({ width: 300 });
-gui.add(lutSettings, 'lut', lutNameIndexMap);
-</pre>
-<p>最後にfilterするかに応じてeffectをオンにし、選択したテクスチャを使用するようにeffectを設定して、<code class="notranslate" translate="no">EffectComposer</code> を通してレンダリングします。</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const lutInfo = lutTextures[lutSettings.lut];
-
-const effect = lutInfo.filter ? effectLUT : effectLUTNearest;
-effectLUT.enabled = lutInfo.filter;
-effectLUTNearest.enabled = !lutInfo.filter;
-
-const lutTexture = lutInfo.texture;
-effect.uniforms.lutMap.value = lutTexture;
-effect.uniforms.lutMapSize.value = lutInfo.size;
-
-composer.render(delta);
-</pre>
-<p>同一性の3DLUTである事を考えると何も変わりません。</p>
-<p></p><div translate="no" class="threejs_example_container notranslate">
-  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/postprocessing-3dlut-identity.html"></iframe></div>
-  <a class="threejs_center" href="/manual/examples/postprocessing-3dlut-identity.html" target="_blank">ここをクリックして別のウィンドウで開きます</a>
-</div>
-
-<p></p>
-<p>しかし、GUIでidentity not filteredを選択すると興味深い結果になります。</p>
-<div class="threejs_center"><img src="../resources/images/unfiltered-3dlut.jpg" style="width: 500px"></div>
-
-<p>なぜこのようなことが起こるのでしょうか?
-filterをオンにするとGPUはカラーの中間を線形補間します。
-filterをオフにすると補間は行わなわれず、3DLUT内のカラーを探しても3DLUT内の正確なカラーの1つしか得られません。</p>
-<p>もっと面白い3DLUTを作るにはどうすれば良いでしょうか?</p>
-<p>まず必要なテーブルの解像度を決定し、簡単なスクリプトを使用しルックアップキューブの切片を生成します。</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const ctx = document.querySelector('canvas').getContext('2d');
-
-function drawColorCubeImage(ctx, size) {
-  const canvas = ctx.canvas;
-  canvas.width = size * size;
-  canvas.height = size;
-
-  for (let zz = 0; zz &lt; size; ++zz) {
-    for (let yy = 0; yy &lt; size; ++yy) {
-      for (let xx = 0; xx &lt; size; ++xx) {
-        const r = Math.floor(xx / (size - 1) * 255);
-        const g = Math.floor(yy / (size - 1) * 255);
-        const b = Math.floor(zz / (size - 1) * 255);
-        ctx.fillStyle = `rgb(${r},${g},${b})`;
-        ctx.fillRect(zz * size + xx, yy, 1, 1);
-      }
-    }
-  }
-  document.querySelector('#width').textContent = canvas.width;
-  document.querySelector('#height').textContent = canvas.height;
-}
-
-drawColorCubeImage(ctx, 8);
-</pre>
-<p>キャンバスが必要です。</p>
-<pre class="prettyprint showlinemods notranslate lang-html" translate="no">&lt;canvas&gt;&lt;/canvas&gt;
-</pre>
-<p>これで任意のサイズで同一性の3Dルックアップテーブルを生成できます。</p>
-<p></p><div translate="no" class="threejs_example_container notranslate">
-  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/3dlut-base-cube-maker.html"></iframe></div>
-  <a class="threejs_center" href="/manual/examples/3dlut-base-cube-maker.html" target="_blank">ここをクリックして別のウィンドウで開きます</a>
-</div>
-
-<p></p>
-<p>解像度が大きいほど微調整が可能ですが、キューブのデータであるため必要なサイズはすぐに大きくなります。
-サイズ8のキューブでは2KBしか必要ありませんが、サイズ64のキューブでは1MB必要です。
-したがって、望む効果を再現する最小のものを使用して下さい。</p>
-<p>サイズを16に設定しSaveをクリックすると以下のようなファイルができます。</p>
-<div class="threejs_center"><img src="../resources/images/identity-lut-s16.png"></div>
-
-<p>また、LUTを適用したい部分の画像キャプチャをする必要があります。
-通常は上記のシーンを右クリックして "名前を付けて保存... "を選択できますが、<a href="/docs/#examples/controls/OrbitControls"><code class="notranslate" translate="no">OrbitControls</code></a> がOSによっては右クリック防止してるかもしれない事に注意して下さい。
-私の場合は、スクリーンショットを取得するためにOSのスクリーンキャプチャ機能を使用しました。</p>
-<div class="threejs_center"><img src="../resources/images/3dlut-screen-capture.jpg" style="width: 600px"></div>
-
-<p>次に画像エディタ(私の場合はPhotoshop)で上記の画像を読み込み、左上に3DLUTの画像を貼り付けます。</p>
-<blockquote>
-<p>備考: 最初にPhotoshop上でLUTファイルをドラッグ&ドロップしてみましたが、上手くいきませんでした。
-Photoshopで2倍の大きさにしてみました。
-DPIか何かに合わせようとしているのかもしれません。
-LUTファイルを個別に読み込み、コピーして画面キャプチャに貼り付けると上手くいきました。</p>
-</blockquote>
-<div class="threejs_center"><img src="../resources/images/3dlut-photoshop-before.jpg" style="width: 600px"></div>
-
-<p>カラーベースのフルイメージ調整を使い画像調整します。
-Photoshopの場合、使用できる調整のほとんどは画像 → 調整メニューにあります。</p>
-<div class="threejs_center"><img src="../resources/images/3dlut-photoshop-after.jpg" style="width: 600px"></div>
-
-<p>好みに合わせて画像を調整して、左上に配置した3DLUTスライスにも同じ調整が適用されているのが分かります。</p>
-<p>分かりましたがどうやって使うのでしょうか?</p>
-<p>最初にpngを<code class="notranslate" translate="no">3dlut-red-only-s16.png</code>で保存しました。
-メモリを節約するために左上にLUTテーブルを16 x 256でトリミングしましたが、もっと楽しむためにロード後にトリミングしておきます。
-これの良い点はpngファイルを見ると、LUTの効果をある程度把握できます。
-悪い点はもちろん帯域の無駄遣いです。</p>
-<p>以下はそれをロードするためのコードです。
-このコードはテクスチャをすぐに使用できるように、同一性のLUTから始まります。
-次に画像をロードし3D LUT部分だけをキャンバスにコピーします。
-キャンバスからデータを取得してテクスチャに設定し、<code class="notranslate" translate="no">needsUpdate</code> をtrueに設定して新しいデータを取得させます。</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const makeLUTTexture = function() {
-  const imgLoader = new THREE.ImageLoader();
-  const ctx = document.createElement('canvas').getContext('2d');
-
-  return function(info) {
-    const lutSize = info.size;
-    const width = lutSize * lutSize;
-    const height = lutSize;
-    const texture = new THREE.DataTexture(new Uint8Array(width * height), width, height);
-    texture.minFilter = texture.magFilter = info.filter ? THREE.LinearFilter : THREE.NearestFilter;
-    texture.flipY = false;
-
-    if (info.url) {
-
-      imgLoader.load(info.url, function(image) {
-        ctx.canvas.width = width;
-        ctx.canvas.height = height;
-        ctx.drawImage(image, 0, 0);
-        const imageData = ctx.getImageData(0, 0, width, height);
-
-        texture.image.data = new Uint8Array(imageData.data.buffer);
-        texture.image.width = width;
-        texture.image.height = height;
-        texture.needsUpdate = true;
-      });
-    }
-
-    return texture;
-  };
-}();
-</pre>
-<p>先ほど作成したLUTのpngを読み込むのに使ってみましょう。</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const lutTextures = [
-  { name: 'identity',           size: 2, filter: true , },
-  { name: 'identity no filter', size: 2, filter: false, },
-+  { name: 'custom',          url: 'resources/images/lut/3dlut-red-only-s16.png' },
-];
-
-+lutTextures.forEach((info) =&gt; {
-+  // if not size set get it from the filename
-+  if (!info.size) {
-+    // assumes filename ends in '-s&lt;num&gt;[n]'
-+    // where &lt;num&gt; is the size of the 3DLUT cube
-+    // and [n] means 'no filtering' or 'nearest'
-+    //
-+    // examples:
-+    //    'foo-s16.png' = size:16, filter: true
-+    //    'bar-s8n.png' = size:8, filter: false
-+    const m = /-s(\d+)(n*)\.[^.]+$/.exec(info.url);
-+    if (m) {
-+      info.size = parseInt(m[1]);
-+      info.filter = info.filter === undefined ? m[2] !== 'n' : info.filter;
-+    }
-+  }
-+
-+  info.texture = makeLUTTexture(info);
-+});
-</pre>
-<p>上記ではLUTのサイズをファイル名の最後にエンコードしてます。
-これでLUTをpngとして渡すのが簡単になります。</p>
-<p>既存のLUTのpngファイルをたくさん追加しておきましょう。</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const lutTextures = [
-  { name: 'identity',           size: 2, filter: true , },
-  { name: 'identity no filter', size: 2, filter: false, },
-  { name: 'custom',          url: 'resources/images/lut/3dlut-red-only-s16.png' },
-+  { name: 'monochrome',      url: 'resources/images/lut/monochrome-s8.png' },
-+  { name: 'sepia',           url: 'resources/images/lut/sepia-s8.png' },
-+  { name: 'saturated',       url: 'resources/images/lut/saturated-s8.png', },
-+  { name: 'posterize',       url: 'resources/images/lut/posterize-s8n.png', },
-+  { name: 'posterize-3-rgb', url: 'resources/images/lut/posterize-3-rgb-s8n.png', },
-+  { name: 'posterize-3-lab', url: 'resources/images/lut/posterize-3-lab-s8n.png', },
-+  { name: 'posterize-4-lab', url: 'resources/images/lut/posterize-4-lab-s8n.png', },
-+  { name: 'posterize-more',  url: 'resources/images/lut/posterize-more-s8n.png', },
-+  { name: 'inverse',         url: 'resources/images/lut/inverse-s8.png', },
-+  { name: 'color negative',  url: 'resources/images/lut/color-negative-s8.png', },
-+  { name: 'high contrast',   url: 'resources/images/lut/high-contrast-bw-s8.png', },
-+  { name: 'funky contrast',  url: 'resources/images/lut/funky-contrast-s8.png', },
-+  { name: 'nightvision',     url: 'resources/images/lut/nightvision-s8.png', },
-+  { name: 'thermal',         url: 'resources/images/lut/thermal-s8.png', },
-+  { name: 'b/w',             url: 'resources/images/lut/black-white-s8n.png', },
-+  { name: 'hue +60',         url: 'resources/images/lut/hue-plus-60-s8.png', },
-+  { name: 'hue +180',        url: 'resources/images/lut/hue-plus-180-s8.png', },
-+  { name: 'hue -60',         url: 'resources/images/lut/hue-minus-60-s8.png', },
-+  { name: 'red to cyan',     url: 'resources/images/lut/red-to-cyan-s8.png' },
-+  { name: 'blues',           url: 'resources/images/lut/blues-s8.png' },
-+  { name: 'infrared',        url: 'resources/images/lut/infrared-s8.png' },
-+  { name: 'radioactive',     url: 'resources/images/lut/radioactive-s8.png' },
-+  { name: 'goolgey',         url: 'resources/images/lut/googley-s8.png' },
-+  { name: 'bgy',             url: 'resources/images/lut/bgy-s8.png' },
-];
-</pre>
-<p>そして、ここにはたくさんのLUTがあります。</p>
-<p></p><div translate="no" class="threejs_example_container notranslate">
-  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/postprocessing-3dlut.html"></iframe></div>
-  <a class="threejs_center" href="/manual/examples/postprocessing-3dlut.html" target="_blank">ここをクリックして別のウィンドウで開きます</a>
-</div>
-
-<p></p>
-<p>最後にもう1つ、ただのお遊びですがAdobeが定義した標準LUTフォーマットがあります。
-<a href="https://www.google.com/search?q=lut+files">ネットで検索するとたくさんのLUTファイル</a>が見つかります。</p>
-<p>クイックローダーを書いてみました。
-フォーマットの種類は4つありますが、残念ながら私は1種類の例しか見つけられなかったので、全ての種類が動作するかを簡単にテストできませんでした。</p>
-<p>ドラッグ&ドロップライブラリも書いてみます。
-両方を使いAdobe LUTファイルをドラッグ&ドロップして効果を確認できるようにしてみましょう。</p>
-<p>まず2つのライブラリが必要です。</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">import * as lutParser from './resources/lut-reader.js';
-import * as dragAndDrop from './resources/drag-and-drop.js';
-</pre>
-<p>そして次のように利用できます。</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">dragAndDrop.setup({msg: 'Drop LUT File here'});
-dragAndDrop.onDropFile(readLUTFile);
-
-function ext(s) {
-  const period = s.lastIndexOf('.');
-  return s.slice(period + 1);
-}
-
-function readLUTFile(file) {
-  const reader = new FileReader();
-  reader.onload = (e) =&gt; {
-    const type = ext(file.name);
-    const lut = lutParser.lutTo2D3Drgba8(lutParser.parse(e.target.result, type));
-    const {size, data, name} = lut;
-    const texture = new THREE.DataTexture(data, size * size, size);
-    texture.minFilter = THREE.LinearFilter;
-    texture.needsUpdate = true;
-    texture.flipY = false;
-    const lutTexture = {
-      name: (name &amp;&amp; name.toLowerCase().trim() !== 'untitled')
-          ? name
-          : file.name,
-      size: size,
-      filter: true,
-      texture,
-    };
-    lutTextures.push(lutTexture);
-    lutSettings.lut = lutTextures.length - 1;
-    updateGUI();
-  };
-
-  reader.readAsText(file);
-}
-</pre>
-<p><a href="https://www.google.com/search?q=lut+files">Adobe LUTをダウンロード</a>し、下の例にドラッグ&ドロップできます。</p>
-<p></p><div translate="no" class="threejs_example_container notranslate">
-  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/postprocessing-3dlut-w-loader.html"></iframe></div>
-  <a class="threejs_center" href="/manual/examples/postprocessing-3dlut-w-loader.html" target="_blank">ここをクリックして別のウィンドウで開きます</a>
-</div>
-
-<p></p>
-<p>Adobe LUTはWeb上のオンライン利用を想定して設計されていません。
-これらは大きなファイルです。
-下のサンプルの上にドラッグ&ドロップしてサイズを選択し、"Save... "をクリックし小さなファイルに変換し、PNG形式で保存できます。</p>
-<p>以下のサンプルは上記のコードを変更したものです。
-背景の絵を描くだけでglTFファイルはありません。
-同一性のLUT画像です。</p>
-<p>この画像は上記スクリプトから作成された同一性のLUT画像です。
-次に読み込まれたLUTファイルを適用するための効果を使用しているので、結果はLUTファイルをPNGとして再現するために必要な画像になります。</p>
-<p></p><div translate="no" class="threejs_example_container notranslate">
-  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/postprocessing-adobe-lut-to-png-converter.html"></iframe></div>
-  <a class="threejs_center" href="/manual/examples/postprocessing-adobe-lut-to-png-converter.html" target="_blank">ここをクリックして別のウィンドウで開きます</a>
-</div>
-
-<p></p>
-<p>1つ解説を完全に飛ばしてるのは、シェーダー自体がどのように動作するかです。
-将来的にはもう少しGLSLをカバーできると良いと思います。
-今の所は興味があれば<a href="post-processing.html">ポストプロセスの記事</a>のリンクを見たり<a href="https://www.youtube.com/watch?v=rfQ8rKGTVlg#t=24m30s">この動画を見て下さい</a>。</p>
-<script type="module" src="../resources/threejs-post-processing-3dlut.js"></script>
-
-        </div>
-      </div>
-    </div>
-
-  <script src="../resources/prettify.js"></script>
-  <script src="../resources/lesson.js"></script>
-
-
-
-
-</body></html>

+ 0 - 446
manual/ko/post-processing-3dlut.html

@@ -1,446 +0,0 @@
-<!DOCTYPE html><html lang="ko"><head>
-    <meta charset="utf-8">
-    <title>3DLUT로 후처리하기</title>
-    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-    <meta name="twitter:card" content="summary_large_image">
-    <meta name="twitter:site" content="@threejs">
-    <meta name="twitter:title" content="Three.js – 3DLUT로 후처리하기">
-    <meta property="og:image" content="https://threejs.org/files/share.png">
-    <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
-    <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
-
-    <link rel="stylesheet" href="../resources/lesson.css">
-    <link rel="stylesheet" href="../resources/lang.css">
-<script type="importmap">
-{
-  "imports": {
-    "three": "../../build/three.module.js"
-  }
-}
-</script>
-    <link rel="stylesheet" href="/manual/ko/lang.css">
-  </head>
-  <body>
-    <div class="container">
-      <div class="lesson-title">
-        <h1>3DLUT로 후처리하기</h1>
-      </div>
-      <div class="lesson">
-        <div class="lesson-main">
-          <p>이전 글에서는 <a href="post-processing.html">후처리(Post processing)</a>에 관해 알아보았습니다. 보통 후처리는 LUT 또는 3DLUT라고 부르기도 합니다. LUT는 룩업 테이블(Look-Up Table, 순람표)의 줄임말이고, 3DLUT는 3차원 룩업 테이블의 줄임말입니다.</p>
-<p>3DLUT는 2D 이미지를 특정한 색상 정육면체를 매핑한다고 생각하면 쉽습니다. 먼저 원본 이미지의 색상을 정육면체의 인덱스 값과 매칭시킵니다. 원본 이미지의 픽셀 하나당 해당 픽셀 색상의 빨강(red), 초록(green), 파랑(blue) 값을 이용해 정육면체의 특정 지점을 가리키는(look-up) 3D 벡터 인덱스를 만드는 것이죠. 이 인덱스를 통해 3DLUT에서 뽑아낸 값을 새로운 색으로 사용하는 겁니다.</p>
-<p>자바스크립트의 경우 아래처럼 구현할 수 있습니다. RGB 각 색상값을 0부터 255의 정수로 표현한 3차원 256x256x256 배열로 룩업 테이블을 구현하고, 이 룩업 테이블에서 RGB 색상값을 이용해 새로운 색상값을 선택하는 거죠.</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const newColor = lut[origColor.red][origColor.green][origColor.blue]
-</pre>
-<p>물론 256x256x256 배열은 큰 배열입니다. <a href="textures.html">텍스처에 관한 글</a>에서 배웠듯 텍스처는 크기에 상관 없이 0.0에서 1.0로 값을 지정합니다.</p>
-<p>8x8x8 정육면체를 예로 들어보죠.</p>
-<div class="threejs_center"><img src="../resources/images/3dlut-rgb.svg" class="noinvertdark" style="width: 500px"></div>
-
-<p>먼저 0,0,0 부분을 검정색으로 채웁니다. 맞은편의 1,1,1 부분은 하얀색, 1,0,0 부분은 <span style="color:red;">빨강</span>, 0,1,0은 <span style="color:green;">초록</span>, 0,0,1은 <span style="color:blue;">파랑</span>으로 채웁니다.</p>
-<div class="threejs_center"><img src="../resources/images/3dlut-axis.svg" class="noinvertdark" style="width: 500px"></div>
-
-<p>그리고 각 축을 따라 색을 채워넣습니다.</p>
-<div class="threejs_center"><img src="../resources/images/3dlut-edges.svg" class="noinvertdark" style="width: 500px"></div>
-
-<p>빈 모서리를 2개 이상의 색상 채널을 사용하는 색으로 채웁니다(초록 + 빨강, 파랑 + 빨강 등).</p>
-<div class="threejs_center"><img src="../resources/images/3dlut-standard.svg" class="noinvertdark" style="width: 500px"></div>
-
-<p>마지막으로 빈 공간을 채웁니다. 이 형태가 3DLUT 기본 구조입니다. 지금은 효과를 주기 전과 후의 차이가 없습니다. 색상값을 인덱스로 사용해 새로운 색상값을 선택하면, 정확히 같은 색상값이 나오기 때문이죠.</p>
-<div class="threejs_center"><object type="image/svg+xml" data="resources/images/3dlut-standard-lookup.svg" class="noinvertdark" data-diagram="lookup" style="width: 600px"></object></div>
-
-<p>이 정육면체를 호박색 쉐이드로 바꾸면 같은 인덱스를 참조하지만 전혀 다른 결과가 나옵니다.</p>
-<div class="threejs_center"><object type="image/svg+xml" data="resources/images/3dlut-amber-lookup.svg" class="noinvertdark" data-diagram="lookup" style="width: 600px"></object></div>
-
-<p>이 기법을 사용하면 룩업 테이블을 교체하는 것으로 많은 효과를 구현할 수 있습니다. 색상 계산 기반의 효과는 대부분 하나의 색상값만을 사용합니다. 색상, 대비, 채도, 컬러 캐스트(color cast), 틴트(tint), 밝기, 노출도, 레벨, 커브, 포스터화, 그림자, 강조, 등 거의 모든 효과를 색상값 계산을 기반으로 구현하죠. 또 이 모든 효과를 하나의 룩업 테이블로 합칠 수도 있습니다.</p>
-<p>룩업 테이블을 사용하려면 먼저 적용할 장면이 필요하니 간단한 장면을 하나 만들어보겠습니다. <a href="load-gltf.html">glTF 불러오기</a>에서 배웠듯 glTF 파일을 불러와 사용하겠습니다. 예제에 사용할 모델은 <a href="https://sketchfab.com/sarath.irn.kat005">The Ice Wolves</a>의 <a href="https://sketchfab.com/models/a1d315908e9f45e5a3bc618bdfd2e7ee">작품</a>입니다.</p>
-<p><a href="backgrounds.html">배경과 하늘 상자</a>에서 배웠던 대로 배경도 추가하겠습니다.</p>
-<p></p><div translate="no" class="threejs_example_container notranslate">
-  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/postprocessing-3dlut-prep.html"></iframe></div>
-  <a class="threejs_center" href="/manual/examples/postprocessing-3dlut-prep.html" target="_blank">새 탭에서 보기</a>
-</div>
-
-<p></p>
-<p>이제 장면을 구현했으니 3DLUT를 만들어야 합니다. 가장 간단한 3DLUT는 2x2x2 identity LUT로, 여기서 <em>identity(동일한)</em>은 아무런 변화도 없음을 의미합니다. 1을 곱하거나 아무것도 안 하는 경우와 같죠. LUT 안의 색상값을 사용한다고 해도 입력된 값과 정확히 같은 값을 반환할 테니까요.</p>
-<div class="threejs_center"><img src="../resources/images/3dlut-standard-2x2.svg" class="noinvertdark" style="width: 200px"></div>
-
-<p>WebGL1은 3D 텍스쳐를 지원하지 않습니다. 따라서 3D 텍스처를 썰어 펼쳐 놓은 형태의 4x2짜리 2D 텍스처를 대신 사용하겠습니다.</p>
-<p>아래는 4x2 2D 텍스처로 identity LUT를 구현한 것입니다.</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const makeIdentityLutTexture = function() {
-  const identityLUT = new Uint8Array([
-      0,   0,   0, 255,  // black
-    255,   0,   0, 255,  // red
-      0,   0, 255, 255,  // blue
-    255,   0, 255, 255,  // magenta
-      0, 255,   0, 255,  // green
-    255, 255,   0, 255,  // yellow
-      0, 255, 255, 255,  // cyan
-    255, 255, 255, 255,  // white
-  ]);
-
-  return function(filter) {
-    const texture = new THREE.DataTexture(identityLUT, 4, 2, THREE.RGBAFormat);
-    texture.minFilter = filter;
-    texture.magFilter = filter;
-    texture.needsUpdate = true;
-    texture.flipY = false;
-    return texture;
-  };
-}();
-</pre>
-<p>필터가 들어간 것, 안 들어간 것 총 2개를 만들겠습니다.</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const lutTextures = [
-  { name: 'identity', size: 2, texture: makeIdentityLutTexture(THREE.LinearFilter) },
-  { name: 'identity not filtered', size: 2, texture: makeIdentityLutTexture(THREE.NearestFilter) },
-];
-</pre>
-<p><a href="post-processing.html">후처리에 관한 글</a>에서 작성했던 코드를 가져와 이 쉐이더들을 대신 쓰도록 합니다.</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const lutShader = {
-  uniforms: {
-    tDiffuse: { value: null },
-    lutMap:  { value: null },
-    lutMapSize: { value: 1, },
-  },
-  vertexShader: `
-    varying vec2 vUv;
-    void main() {
-      vUv = uv;
-      gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
-    }
-  `,
-  fragmentShader: `
-    #include &lt;common&gt;
-
-    #define FILTER_LUT true
-
-    uniform sampler2D tDiffuse;
-    uniform sampler2D lutMap;
-    uniform float lutMapSize;
-
-    varying vec2 vUv;
-
-    vec4 sampleAs3DTexture(sampler2D tex, vec3 texCoord, float size) {
-      float sliceSize = 1.0 / size;                  // space of 1 slice
-      float slicePixelSize = sliceSize / size;       // space of 1 pixel
-      float width = size - 1.0;
-      float sliceInnerSize = slicePixelSize * width; // space of size pixels
-      float zSlice0 = floor( texCoord.z * width);
-      float zSlice1 = min( zSlice0 + 1.0, width);
-      float xOffset = slicePixelSize * 0.5 + texCoord.x * sliceInnerSize;
-      float yRange = (texCoord.y * width + 0.5) / size;
-      float s0 = xOffset + (zSlice0 * sliceSize);
-
-      #ifdef FILTER_LUT
-
-        float s1 = xOffset + (zSlice1 * sliceSize);
-        vec4 slice0Color = texture2D(tex, vec2(s0, yRange));
-        vec4 slice1Color = texture2D(tex, vec2(s1, yRange));
-        float zOffset = mod(texCoord.z * width, 1.0);
-        return mix(slice0Color, slice1Color, zOffset);
-
-      #else
-
-        return texture2D(tex, vec2( s0, yRange));
-
-      #endif
-    }
-
-    void main() {
-      vec4 originalColor = texture2D(tDiffuse, vUv);
-      gl_FragColor = sampleAs3DTexture(lutMap, originalColor.xyz, lutMapSize);
-    }
-  `,
-};
-
-const lutNearestShader = {
-  uniforms: {...lutShader.uniforms},
-  vertexShader: lutShader.vertexShader,
-  fragmentShader: lutShader.fragmentShader.replace('#define FILTER_LUT', '//'),
-};
-</pre>
-<p>fragment 쉐이더의 다음 코드는</p>
-<pre class="prettyprint showlinemods notranslate lang-glsl" translate="no">#define FILTER_LUT true
-</pre>
-<p>주석 처리했던 두 번째 쉐이더를 생성하기 위한 것입니다.</p>
-<p>그리고 각 쉐이더로 <code class="notranslate" translate="no">Pass</code>를 만듭니다.</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const effectLUT = new THREE.ShaderPass(lutShader);
-const effectLUTNearest = new THREE.ShaderPass(lutNearestShader);
-</pre>
-<p>기존에 배경과 glTF를 별도 장면으로 분리했으므로 각 장면의 <code class="notranslate" translate="no">RenderPass</code>를 따로 생성합니다.</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const renderModel = new THREE.RenderPass(scene, camera);
-renderModel.clear = false;  // 배경을 지우지 않도록 합니다
-const renderBG = new THREE.RenderPass(sceneBG, cameraBG);
-</pre>
-<p>다음으로 사용할 pass*를 <code class="notranslate" translate="no">EffectComposer</code>에 추가합니다.</p>
-<p>※ 편의상 <code class="notranslate" translate="no">Pass</code> 인스턴스를 pass로 번역합니다.</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const composer = new THREE.EffectComposer(renderer);
-
-composer.addPass(renderBG);
-composer.addPass(renderModel);
-composer.addPass(effectLUT);
-composer.addPass(effectLUTNearest);
-composer.addPass(gammaPass);
-</pre>
-<p>GUI를 만들어 LUT를 바꿀 수 있도록 합니다.</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const lutNameIndexMap = {};
-lutTextures.forEach((info, ndx) =&gt; {
-  lutNameIndexMap[info.name] = ndx;
-});
-
-const lutSettings = {
-  lut: lutNameIndexMap.identity,
-};
-const gui = new GUI({ width: 300 });
-gui.add(lutSettings, 'lut', lutNameIndexMap);
-</pre>
-<p>마지막으로 필터링 여부에 따라 효과가 바뀌도록 설정합니다. LUT가 선택한 텍스처를 사용하도록 하고, <code class="notranslate" translate="no">EffectComposer</code>로 렌더링 합니다.</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const lutInfo = lutTextures[lutSettings.lut];
-
-const effect = lutInfo.filter ? effectLUT : effectLUTNearest;
-effectLUT.enabled = lutInfo.filter;
-effectLUTNearest.enabled = !lutInfo.filter;
-
-const lutTexture = lutInfo.texture;
-effect.uniforms.lutMap.value = lutTexture;
-effect.uniforms.lutMapSize.value = lutInfo.size;
-
-composer.render(delta);
-</pre>
-<p>identity 3DLUT를 선택했을 때는 아무런 변화가 없습니다.</p>
-<p></p><div translate="no" class="threejs_example_container notranslate">
-  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/postprocessing-3dlut-identity.html"></iframe></div>
-  <a class="threejs_center" href="/manual/examples/postprocessing-3dlut-identity.html" target="_blank">새 탭에서 보기</a>
-</div>
-
-<p></p>
-<p>하지만 필터가 identity not filtered LUT를 선택하면 재미있는 결과가 나옵니다.</p>
-<div class="threejs_center"><img src="../resources/images/unfiltered-3dlut.jpg" style="width: 500px"></div>
-
-<p>왜 이런 결과가 나온 걸까요? 필터링을 사용할 경우(linear), GPU는 선형적으로 색상값을 채워넣습니다. 필터링을 사용하지 않을 경우(nearest), 알아서 색상값을 채워넣지 않기에 3DLUT에서(근처의) 색상값이 있는 곳을 찾아 사용하는 것이죠.</p>
-<p>어느정도 이해했다면 더 다양한 3DLUT를 만들어봅시다.</p>
-<p>먼저 룩업 테이블의 해상도를 정하고 간단한 코드를 만들어 룩업 테이블 정육면체의 각 면을 만들겠습니다.</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const ctx = document.querySelector('canvas').getContext('2d');
-
-function drawColorCubeImage(ctx, size) {
-  const canvas = ctx.canvas;
-  canvas.width = size * size;
-  canvas.height = size;
-
-  for (let zz = 0; zz &lt; size; ++zz) {
-    for (let yy = 0; yy &lt; size; ++yy) {
-      for (let xx = 0; xx &lt; size; ++xx) {
-        const r = Math.floor(xx / (size - 1) * 255);
-        const g = Math.floor(yy / (size - 1) * 255);
-        const b = Math.floor(zz / (size - 1) * 255);
-        ctx.fillStyle = `rgb(${ r },${ g },${ b })`;
-        ctx.fillRect(zz * size + xx, yy, 1, 1);
-      }
-    }
-  }
-  document.querySelector('#width').textContent = canvas.width;
-  document.querySelector('#height').textContent = canvas.height;
-}
-
-drawColorCubeImage(ctx, 8);
-</pre>
-<p>캔버스 요소도 만듭니다.</p>
-<pre class="prettyprint showlinemods notranslate lang-html" translate="no">&lt;canvas&gt;&lt;/canvas&gt;
-</pre>
-<p>이제 어떤 identity 3D 룩업 테이블이든 만들 수 있습니다.</p>
-<p></p><div translate="no" class="threejs_example_container notranslate">
-  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/3dlut-base-cube-maker.html"></iframe></div>
-  <a class="threejs_center" href="/manual/examples/3dlut-base-cube-maker.html" target="_blank">새 탭에서 보기</a>
-</div>
-
-<p></p>
-<p>해상도가 높을수록 더 세밀한 효과를 줄 수 있지만 정육면체형 데이터의 크기는 기하급수적으로 늘어납니다. 크기 8x8 정육면체는 2kb 정도지만 64x64 정육면체는 약 1mb나 되죠. 그러니 충분히 효과를 구현할 수 있는 만큼만 사용하는 게 좋습니다.</p>
-<p>사이즈를 16으로 설정하고 <code class="notranslate" translate="no">Save...</code> 버튼을 클릭하면 아래와 같은 파일이 나옵니다.</p>
-<div class="threejs_center"><img src="../resources/images/identity-lut-s16.png"></div>
-
-<p>그리고 LUT를 적용할 화면을 캡쳐해야 합니다. 이 경우에는 이전에 만든 장면에 아무런 효과를 주지 않은 화면이겠죠. 대게 위 예제를 오른쪽 클릭해 "다른 이름으로 저장..."을 클릭하면 되지만, OS에 따라 마우스 우클릭이 동작하지 않을 수 있습니다. 제 경우 OS에 내장된 스크린샷 기능을 이용해 화면을 캡쳐했습니다*.</p>
-<p>※ Windows 10 RS5(레드스톤 5) 이상이라면 <code class="notranslate" translate="no">Windows + Shift + S</code>를 눌러 화면을 캡쳐할 수 있습니다. 역주.</p>
-<div class="threejs_center"><img src="../resources/images/3dlut-screen-capture.jpg" style="width: 600px"></div>
-
-<p>캡쳐본을 이미지 에디터에서 불러옵니다. 저는 포토샵을 사용해 샘플 이미지를 불러오고, 한쪽 귀퉁이에 3DLUT를 붙여 넣었습니다.</p>
-<blockquote>
-<p>참고: 제 경우 포토샵에서 캡쳐본 위에 lut 파일을 불러오려고 했을 때 이미지가 두 배 더 커졌습니다. 아마 DPI를 맞추거나 하는 이유 때문에 그런 거겠죠. lut 파일을 별도 탭에 불러와 캡쳐본 위에 복사 붙여 넣기 하니 정상적으로 불러와지더군요.</p>
-</blockquote>
-<div class="threejs_center"><img src="../resources/images/3dlut-photoshop-before.jpg" style="width: 600px"></div>
-
-<p>그리고 이미지에 부여하고 싶은 색상 효과를 부여합니다. 포토샵의 경우 대부분의 효과는 이미지(Image)-&gt;조정(Adjustments) 메뉴에 있습니다.</p>
-<div class="threejs_center"><img src="../resources/images/3dlut-photoshop-after.jpg" style="width: 600px"></div>
-
-<p>색상을 조정하면 3DLUT 이미지에도 같은 효과가 적용될 겁니다.</p>
-<p>자 그럼 이제 이걸 어떻게 쓸 수 있을까요?</p>
-<p>먼저 저는 3DLUT 이미지를 <code class="notranslate" translate="no">3dlut-red-only-s16.png</code>라는 이름으로 저장했습니다. 메모리를 아끼려면 이미지를 LUT 부분만 잘라 16x256로 맞추는 것이 좋지만, 그냥 재미삼아 이미지를 불러온 이후 자르겠습니다*. 이 방법의 장점은 귀찮게 이미지를 자르는 과정 없이 효과를 적용해보고 싶은 대로 바로바로 적용할 수 있다는 것이죠. 물론 대역폭을 낭비한다는 게 단점입니다.</p>
-<p>※ 포토샵 CC 이후 버젼을 사용한다면 레이어를 오른쪽 클릭해 <code class="notranslate" translate="no">PNG로 빠르게 내보내기</code> 메뉴로 해당 그룹 또는 레이어만 .png 파일로 내보낼 수 있습니다. 이미지를 귀찮게 자르는 과정 없이 .png 파일을 바로 생성할 수 있죠. 역주.</p>
-<p>아래는 이미지를 불러오는 코드입니다. 실제 코드에서는 텍스처를 불러왔을 때 바로 사용할 수 있도록 identity lut를 먼저 만들었습니다. 그 다음 이미지를 불러와 3DLUT 부분만 캔버스에 복사하고, 캔버스에서 가져온 데이터를 텍스처에 지정합니다. 또한 텍스처가 바뀌었을 때 바로 적용하도록 <code class="notranslate" translate="no">needsUpdate</code> 속성도 true로 설정합니다.</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const makeLUTTexture = function() {
-  const imgLoader = new THREE.ImageLoader();
-  const ctx = document.createElement('canvas').getContext('2d');
-
-  return function(info) {
-    const lutSize = info.size;
-    const width = lutSize * lutSize;
-    const height = lutSize;
-    const texture = new THREE.DataTexture(new Uint8Array(width * height), width, height);
-    texture.minFilter = texture.magFilter = info.filter ? THREE.LinearFilter : THREE.NearestFilter;
-    texture.flipY = false;
-
-    if (info.url) {
-
-      imgLoader.load(info.url, function(image) {
-        ctx.canvas.width = width;
-        ctx.canvas.height = height;
-        ctx.drawImage(image, 0, 0);
-        const imageData = ctx.getImageData(0, 0, width, height);
-
-        texture.image.data = new Uint8Array(imageData.data.buffer);
-        texture.image.width = width;
-        texture.image.height = height;
-        texture.needsUpdate = true;
-      });
-    }
-
-    return texture;
-  };
-}();
-</pre>
-<p>기존 코드가 LUT png 파일을 사용하도록 수정합니다.</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const lutTextures = [
-  { name: 'identity',           size: 2, filter: true , },
-  { name: 'identity no filter', size: 2, filter: false, },
-+  { name: 'custom',          url: 'resources/images/lut/3dlut-red-only-s16.png' },
-];
-
-+lutTextures.forEach((info) =&gt; {
-+  // 사이즈값이 없다면 사이즈 정보를 파일 이름에서 가져옵니다.
-+  if (!info.size) {
-+    /**
-+     * 파일 이름이 '-s&lt;숫자&gt;[n]' 이렇게 끝난다고 가정합니다.
-+     * &lt;숫자&gt;는 3DLUT 정육면체의 크기입니다.
-+     * [n]은 '필터링 없음' 또는 'nearest'를 의미합니다.
-+     *
-+     * 예시:
-+     *    'foo-s16.png' = 크기:16, 필터: true
-+     *    'bar-s8n.png' = 크기:8, 필터: false
-+     **/
-+    const m = /-s(\d+)(n*)\.[^.]+$/.exec(info.url);
-+    if (m) {
-+      info.size = parseInt(m[1]);
-+      info.filter = info.filter === undefined ? m[2] !== 'n' : info.filter;
-+    }
-+  }
-+
-+  info.texture = makeLUTTexture(info);
-+});
-</pre>
-<p>위 코드가 LUT의 사이즈를 파일 이름에 인코딩한 예입니다. 이러면 png로 LUT를 바꾸기가 훨씬 쉽죠.</p>
-<p>그냥은 좀 심심하니 lut png 파일을 더 많이 만들어봅시다.</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const lutTextures = [
-  { name: 'identity',           size: 2, filter: true , },
-  { name: 'identity no filter', size: 2, filter: false, },
-  { name: 'custom',          url: 'resources/images/lut/3dlut-red-only-s16.png' },
-+  { name: 'monochrome',      url: 'resources/images/lut/monochrome-s8.png' },
-+  { name: 'sepia',           url: 'resources/images/lut/sepia-s8.png' },
-+  { name: 'saturated',       url: 'resources/images/lut/saturated-s8.png', },
-+  { name: 'posterize',       url: 'resources/images/lut/posterize-s8n.png', },
-+  { name: 'posterize-3-rgb', url: 'resources/images/lut/posterize-3-rgb-s8n.png', },
-+  { name: 'posterize-3-lab', url: 'resources/images/lut/posterize-3-lab-s8n.png', },
-+  { name: 'posterize-4-lab', url: 'resources/images/lut/posterize-4-lab-s8n.png', },
-+  { name: 'posterize-more',  url: 'resources/images/lut/posterize-more-s8n.png', },
-+  { name: 'inverse',         url: 'resources/images/lut/inverse-s8.png', },
-+  { name: 'color negative',  url: 'resources/images/lut/color-negative-s8.png', },
-+  { name: 'high contrast',   url: 'resources/images/lut/high-contrast-bw-s8.png', },
-+  { name: 'funky contrast',  url: 'resources/images/lut/funky-contrast-s8.png', },
-+  { name: 'nightvision',     url: 'resources/images/lut/nightvision-s8.png', },
-+  { name: 'thermal',         url: 'resources/images/lut/thermal-s8.png', },
-+  { name: 'b/w',             url: 'resources/images/lut/black-white-s8n.png', },
-+  { name: 'hue +60',         url: 'resources/images/lut/hue-plus-60-s8.png', },
-+  { name: 'hue +180',        url: 'resources/images/lut/hue-plus-180-s8.png', },
-+  { name: 'hue -60',         url: 'resources/images/lut/hue-minus-60-s8.png', },
-+  { name: 'red to cyan',     url: 'resources/images/lut/red-to-cyan-s8.png' },
-+  { name: 'blues',           url: 'resources/images/lut/blues-s8.png' },
-+  { name: 'infrared',        url: 'resources/images/lut/infrared-s8.png' },
-+  { name: 'radioactive',     url: 'resources/images/lut/radioactive-s8.png' },
-+  { name: 'goolgey',         url: 'resources/images/lut/googley-s8.png' },
-+  { name: 'bgy',             url: 'resources/images/lut/bgy-s8.png' },
-];
-</pre>
-<p>아래 예제에서 여러 lut를 시험해볼 수 있습니다.</p>
-<p></p><div translate="no" class="threejs_example_container notranslate">
-  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/postprocessing-3dlut.html"></iframe></div>
-  <a class="threejs_center" href="/manual/examples/postprocessing-3dlut.html" target="_blank">새 탭에서 보기</a>
-</div>
-
-<p></p>
-<p>추가로 한 가지 덧붙이겠습니다. 인터넷을 뒤져보니 Adobe에서 만든 표준 LUT 형식이 있더군요. <a href="https://www.google.com/search?q=lut+files">인터넷에서 검색</a>해보면 이런 LUT 형식의 파일을 쉽게 찾을 수 있을 겁니다.</p>
-<p>이를 기반으로 간단하게 로더를 작성했습니다. 총 4가지 형식이 있다고는 하나, 제가 찾은 형식은 하나뿐이라 모든 형식에서 테스트하진 못했습니다.</p>
-<p>여기에 간단한 드래그-앤-드롭 라이브러리도 만들었습니다. 이 두 라이브러리를 이용해 여러분이 직접 LUT 파일을 적용할 수 있도록 말이죠.</p>
-<p>먼저 앞서 만든 두 라이브러리를 불러온 뒤</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">import * as lutParser from './resources/lut-reader.js';
-import * as dragAndDrop from './resources/drag-and-drop.js';
-</pre>
-<p>아래처럼 사용합니다.</p>
-<pre class="prettyprint showlinemods notranslate lang-js" translate="no">dragAndDrop.setup({ msg: 'Drop LUT File here' });
-dragAndDrop.onDropFile(readLUTFile);
-
-function ext(s) {
-  const period = s.lastIndexOf('.');
-  return s.slice(period + 1);
-}
-
-function readLUTFile(file) {
-  const reader = new FileReader();
-  reader.onload = (e) =&gt; {
-    const type = ext(file.name);
-    const lut = lutParser.lutTo2D3Drgba8(lutParser.parse(e.target.result, type));
-    const {size, data, name} = lut;
-    const texture = new THREE.DataTexture(data, size * size, size);
-    texture.minFilter = THREE.LinearFilter;
-    texture.needsUpdate = true;
-    texture.flipY = false;
-    const lutTexture = {
-      name: (name &amp;&amp; name.toLowerCase().trim() !== 'untitled')
-          ? name
-          : file.name,
-      size: size,
-      filter: true,
-      texture,
-    };
-    lutTextures.push(lutTexture);
-    lutSettings.lut = lutTextures.length - 1;
-    updateGUI();
-  };
-
-  reader.readAsText(file);
-}
-</pre>
-<p>이제 <a href="https://www.google.com/search?q=lut+files">Adobe LUT 파일</a>을 다운해 아래 예제에 드래그-앤-드롭으로 불러올 수 있을 겁니다.</p>
-<p></p><div translate="no" class="threejs_example_container notranslate">
-  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/postprocessing-3dlut-w-loader.html"></iframe></div>
-  <a class="threejs_center" href="/manual/examples/postprocessing-3dlut-w-loader.html" target="_blank">새 탭에서 보기</a>
-</div>
-
-<p></p>
-<p>다만 Adobe LUT는 온라인 환경에 최적화되지 않았습니다. 파일 용량이 꽤 큰 편이죠. 아래 예제를 사용하면 용량을 좀 더 줄일 수 있습니다. 드래그-앤-드롭으로 파일을 불러오고 크기를 선택한 뒤 "Save..." 버튼을 클릭하면 되죠.</p>
-<p>아래 예제는 단순히 위에서 썼던 예제를 조금 수정한 것입니다. glFT 파일 없이 배경만 렌더링한 것이죠. 배경 이미지는 아까 본 스크립트로 만든 identity lut 이미지입니다. 여기에 LUT 파일을 불러와 해당 LUT 파일을 PNG로 만드는 데 사용하는 것이죠.</p>
-<p></p><div translate="no" class="threejs_example_container notranslate">
-  <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/postprocessing-adobe-lut-to-png-converter.html"></iframe></div>
-  <a class="threejs_center" href="/manual/examples/postprocessing-adobe-lut-to-png-converter.html" target="_blank">새 탭에서 보기</a>
-</div>
-
-<p></p>
-<p>이 글에서는 쉐이더가 어떻게 작동하는지에 대해서는 아예 설명하지 않았습니다. 나중에 GLSL에 대해 더 다룰 기회가 있었으면 좋겠네요. 쉐이더의 작동 방식을 알고 싶다면 <a href="post-processing.html">후처리에 관한 글</a>에 있는 링크 또는 <a href="https://www.youtube.com/watch?v=rfQ8rKGTVlg#t=24m30s">이 유튜브 영상</a>을 참고하기 바랍니다.</p>
-<script type="module" src="../resources/threejs-post-processing-3dlut.js"></script>
-
-        </div>
-      </div>
-    </div>
-
-  <script src="../resources/prettify.js"></script>
-  <script src="../resources/lesson.js"></script>
-
-
-
-
-</body></html>

+ 0 - 6
manual/list.json

@@ -41,7 +41,6 @@
 			"Multiple Canvases, Multiple Scenes": "en/multiple-scenes",
 			"Picking Objects with the mouse": "en/picking",
 			"Post Processing": "en/post-processing",
-			"Applying a LUT File for effects": "en/post-processing-3dlut",
 			"Using Shadertoy shaders": "en/shadertoy",
 			"Aligning HTML Elements to 3D": "en/align-html-elements-to-3d",
 			"Using Indexed Textures for Picking and Color": "en/indexed-textures",
@@ -102,7 +101,6 @@
 			"Multiple Canvases, Multiple Scenes": "fr/multiple-scenes",
 			"Picking Objects with the mouse": "fr/picking",
 			"Post Processing": "fr/post-processing",
-			"Applying a LUT File for effects": "fr/post-processing-3dlut",
 			"Using Shadertoy shaders": "fr/shadertoy",
 			"Aligning HTML Elements to 3D": "fr/align-html-elements-to-3d",
 			"Using Indexed Textures for Picking and Color": "fr/indexed-textures",
@@ -163,7 +161,6 @@
 			"複数キャンバスと複数シーン": "ja/multiple-scenes",
 			"マウスでオブジェクトをピッキング": "ja/picking",
 			"ポストプロセス": "ja/post-processing",
-			"エフェクトにLUTファイルを適用する": "ja/post-processing-3dlut",
 			"Shadertoyのシェーダーを使う": "ja/shadertoy",
 			"HTML要素を3Dに揃える": "ja/align-html-elements-to-3d",
 			"圧縮テクスチャのピッキングとカラー": "ja/indexed-textures",
@@ -224,7 +221,6 @@
 			"다중 캔버스, 다중 장면 만들기": "ko/multiple-scenes",
 			"물체를 마우스로 피킹하기": "ko/picking",
 			"후처리": "ko/post-processing",
-			"LUT 파일로 후처리 효과 적용하기": "ko/post-processing-3dlut",
 			"쉐이더토이 쉐이더 활용하기": "ko/shadertoy",
 			"HTML 요소를 3D로 정렬하기": "ko/align-html-elements-to-3d",
 			"피킹과 색상에 인덱스 텍스처 사용하기": "ko/indexed-textures",
@@ -285,7 +281,6 @@
 			"Несколько холстов, несколько сцен": "ru/multiple-scenes",
 			"Picking Objects with the mouse": "ru/picking",
 			"Post Processing": "ru/post-processing",
-			"Applying a LUT File for effects": "ru/post-processing-3dlut",
 			"Using Shadertoy shaders": "ru/shadertoy",
 			"Aligning HTML Elements to 3D": "ru/align-html-elements-to-3d",
 			"Using Indexed Textures for Picking and Color": "ru/indexed-textures",
@@ -346,7 +341,6 @@
 			"多个画布, 多个场景": "zh/multiple-scenes",
 			"鼠标选取对象": "zh/picking",
 			"后期处理": "zh/post-processing",
-			"Applying a LUT File for effects": "zh/post-processing-3dlut",
 			"Using Shadertoy shaders": "zh/shadertoy",
 			"对齐HTML元素到3D对象": "zh/align-html-elements-to-3d",
 			"使用纹理索引来拾取和着色": "zh/indexed-textures",

+ 0 - 42
manual/ru/post-processing-3dlut.html

@@ -1,42 +0,0 @@
-<!DOCTYPE html><html lang="ru"><head>
-    <meta charset="utf-8">
-    <title>Post Processing 3DLUT</title>
-    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-    <meta name="twitter:card" content="summary_large_image">
-    <meta name="twitter:site" content="@threejs">
-    <meta name="twitter:title" content="Three.js – Post Processing 3DLUT">
-    <meta property="og:image" content="https://threejs.org/files/share.png">
-    <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
-    <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
-
-    <link rel="stylesheet" href="../resources/lesson.css">
-    <link rel="stylesheet" href="../resources/lang.css">
-<script type="importmap">
-{
-  "imports": {
-    "three": "../../build/three.module.js"
-  }
-}
-</script>
-  </head>
-  <body>
-    <div class="container">
-      <div class="lesson-title">
-        <h1>Post Processing 3DLUT</h1>
-      </div>
-      <div class="lesson">
-        <div class="lesson-main">
-          <p>К сожалению, страница ещё не переведена. <a href="https://github.com/mrdoob/three.js">Я всегда рад переводчикам</a>! 😄</p>
-<p><a href="/manual/en/post-processing-3dlut.html">А пока можете почитать статью на английском языке</a>.</p>
-
-        </div>
-      </div>
-    </div>
-
-  <script src="../resources/prettify.js"></script>
-  <script src="../resources/lesson.js"></script>
-
-
-
-
-</body></html>

+ 0 - 43
manual/zh/post-processing-3dlut.html

@@ -1,43 +0,0 @@
-<!DOCTYPE html><html lang="zh"><head>
-    <meta charset="utf-8">
-    <title>Post Processing 3DLUT</title>
-    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-    <meta name="twitter:card" content="summary_large_image">
-    <meta name="twitter:site" content="@threejs">
-    <meta name="twitter:title" content="Three.js – Post Processing 3DLUT">
-    <meta property="og:image" content="https://threejs.org/files/share.png">
-    <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
-    <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
-
-    <link rel="stylesheet" href="../resources/lesson.css">
-    <link rel="stylesheet" href="../resources/lang.css">
-<script type="importmap">
-{
-  "imports": {
-    "three": "../../build/three.module.js"
-  }
-}
-</script>
-    <link rel="stylesheet" href="/manual/zh/lang.css">
-  </head>
-  <body>
-    <div class="container">
-      <div class="lesson-title">
-        <h1>Post Processing 3DLUT</h1>
-      </div>
-      <div class="lesson">
-        <div class="lesson-main">
-          <p>抱歉,还没有中文翻译哦。 <a href="https://github.com/mrdoob/three.js">欢迎加入翻译</a>! 😄</p>
-<p><a href="/manual/en/post-processing-3dlut.html">英文原文链接</a>.</p>
-
-        </div>
-      </div>
-    </div>
-
-  <script src="../resources/prettify.js"></script>
-  <script src="../resources/lesson.js"></script>
-
-
-
-
-</body></html>