3Dモデルの線画化についてメモ。
ちょっと前の記事で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>