3Dモデルを線画で表示

Three.jsとCSSで

3Dモデルの線画化についてメモ。

Blenderからエクスポート→GIMPで墨入れ→Inkscapeで仕上げ

ちょっと前の記事でThree.jsのソーベルで黒地に白線の3Dモデルを出しましたが、CSSで反転させる方法がわかりましたのでソースを載せます。

モデルはスカルプトソフトのDilayで作り、Blenderに取り込んでglTF形式で書き出しました。Three.jsのOBJLoaderでOBJ形式モデルも表示できるのですが、ファイルサイズの点でglTFの方が良いことがわかりました。

  • model.obj: 1.3MB
  • model.glb: 379.1KB

WebGLRendererの出力先<canvas>にCSSで"filter: invert(100%)“を設定しておきます。

<canvas id="myCanvas" style="width:100%; filter: invert(100%);"></canvas>
<script type="module">
import { WebGLRenderer } from '/js/build/three.module.js';
import { Scene } from '/js/build/three.module.js';
import { Color } from '/js/build/three.module.js';
import { DirectionalLight } from '/js/build/three.module.js';
import { AmbientLight } from '/js/build/three.module.js';
import { PerspectiveCamera } from '/js/build/three.module.js';
import { OrbitControls } from '/js/examples/jsm/controls/OrbitControls.js';
import { GLTFLoader } from "/js/examples/jsm/loaders/GLTFLoader.js";
import { EffectComposer } from '/js/examples/jsm/postprocessing/EffectComposer.js';
import { RenderPass } from '/js/examples/jsm/postprocessing/RenderPass.js';
import { ShaderPass } from '/js/examples/jsm/postprocessing/ShaderPass.js';
import { SobelOperatorShader } from '/js/examples/jsm/shaders/SobelOperatorShader.js';

window.addEventListener('load', main);
function main() {
    // 環境
    const canvas = document.querySelector('#myCanvas');
    const renderer = new WebGLRenderer({ canvas, antialias: true });
    renderer.setPixelRatio(2);
    const fov = 45;
    const aspect = 2;
    const near = 0.1;
    const far = 500;
    const camera = new PerspectiveCamera(fov, aspect, near, far);
    camera.position.z = 2.75;
    const controls = new OrbitControls(camera, canvas);
    const scene = new Scene();
    scene.background = new Color( 'white' );

    // ディレクショナルライト 前後
    const intensity = 0.5;
    const light1 = new DirectionalLight( 'white', intensity);
    light1.position.set( 0, 0, 1.0);
    const light2 = new DirectionalLight( 'whitesmoke', intensity * 0.1 );
    light2.position.set( 0, 0, -1.0);
    scene.add(light1)
    scene.add(light2)

    //glTFモデル読み込み
    const loader = new GLTFLoader();
    loader.load('/asset/2019/07-22/model.glb',function(data){
        const gltf = data;
        const obj = gltf.scene;
        scene.add(obj);
    });

    // ポストプロセシング
    const composer = new EffectComposer( renderer );
    const renderPass = new RenderPass( scene, camera );
    composer.addPass( renderPass );

    // ソーベルエフェクト
    const effectSobel = new ShaderPass( SobelOperatorShader );
    const LineThickness = 1;
    effectSobel.uniforms[ 'resolution' ].value.x = window.innerWidth * window.devicePixelRatio * LineThickness;
    effectSobel.uniforms[ 'resolution' ].value.y = window.innerHeight * window.devicePixelRatio * LineThickness;
    composer.addPass( effectSobel );

    // 毎フレーム時に実行されるループイベント
    tick();
    function tick() {
        // レンダリング
        composer.render(scene, camera);
        requestAnimationFrame(tick);
    }
}
</script>
</div>

3D 

関連記事