日記
SVG Gradient をSASS (LESS) で生成して CSS Gradient として扱う mixin
この記事では最終的に、linear-gradient 関数を SASS の mixin にまとめたコードを解説します。これは、Webkit 系ブラウザーや Firefox だけでなく Internet Explorer 9 でも SVG 経由で再現可能でとても便利です。
まず、利用例を紹介しますと、次のように mixin を利用することになります。
.selector{
@include linear-gradient("to bottom", "0FF", 0, "00F", 20, "0F0", 100);
}
それぞれの引数は、<方向>,<色1>,<位置1>,<色2>,<位置2>,<色3>,<位置3>…の順に指定しています。この時、諸事情により
- <方向>に指定できるのは
[to left | to right | to top | to bottom]の 4つのうちのいずれかだけにしています(策定中の仕様がいろいろ変わっていて大変なので…)。 - 色には
#は付けない。また、16進数のみ - 位置にはパーセンテージで渡す。単位は付けない
ようにしています。
そして、これをコンパイルすると次の CSS のコードが出力されます。
.selector {
-pie-background: linear-gradient(top, #0FF 0%,#00F 20%,#0F0 100%);
background-image: url(data:image/svg+xml,%3c%3fxml%20version%3d%221%2e0%22%3f%3e%3csvg%20xmlns%3d%22http%3a%2f%2fwww%2ew3%2eorg%2f2000%2fsvg%22%20width%3d%22100%25%22%20height%3d%22100%25%22%3e%3cdefs%3e%3clinearGradient%20id%3d%22G%22%20x2%3d%220%25%22%20y2%3d%22100%25%22%3e%3cstop%20style%3d%22stop%2dcolor%3a%230FF%22%20offset%3d%220%25%22%2f%3e%3cstop%20style%3d%22stop%2dcolor%3a%2300F%22%20offset%3d%2220%25%22%2f%3e%3cstop%20style%3d%22stop%2dcolor%3a%230F0%22%20offset%3d%22100%25%22%2f%3e%3c%2flinearGradient%3e%3c%2fdefs%3e%3crect%20width%3d%22100%25%22%20height%3d%22100%25%22%20fill%3d%22url%28%23G%29%22%2f%3e%3c%2fsvg%3e);
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #0FF),color-stop(20%, #00F),color-stop(100%, #0F0));
background-image: -webkit-linear-gradient(top, #0FF 0%,#00F 20%,#0F0 100%);
background-image: -moz-linear-gradient(top, #0FF 0%,#00F 20%,#0F0 100%);
background-image: -ms-linear-gradient(top, #0FF 0%,#00F 20%,#0F0 100%);
background-image: -o-linear-gradient(top, #0FF 0%,#00F 20%,#0F0 100%);
background-image: linear-gradient(to bottom, #0FF 0%,#00F 20%,#0F0 100%); }
なお、上記ソースコード内の dataURI は Internet Explorer 9 で linear-gradient とほぼ同じことをするための記述です。
では、この mixin の中身はどうなっているかを、順を追って解説します。この仕組みをそのまま利用すれば LESS 用の mixin へのコンバートも簡単です。
CSS の gradient 関数を利用すれば画像生成をすることができます。線形グラデーションを利用する際には、-接頭辞-linear-gradient() と古い Webkit の記法を併せて記述することが多いのではないでしょうか。
例えば次のように書くことになるでしょう。なお、この記事執筆現在での最新の linear-gradient の方向の指定は、top などから、to bottom などに変更になっています。
.selector {
background-image: -webkit-linear-gradient(top, #0FF 0%,#00F 20%,#0F0 100%);
background-image: -moz-linear-gradient(top, #0FF 0%,#00F 20%,#0F0 100%);
background-image: -ms-linear-gradient(top, #0FF 0%,#00F 20%,#0F0 100%);
background-image: -o-linear-gradient(top, #0FF 0%,#00F 20%,#0F0 100%);
background-image: linear-gradient(to bottom, #0FF 0%,#00F 20%,#0F0 100%); }
しかし、Internet Explorer 9 では CSS の gradient 関数には対応していません。(Internet Explorer 10 から対応される予定です)
そこで Internet Explorer 9 には SVG を併せて利用する方法が知られています。
.selector {
background-image: url(gradient.svg);
background-image: -webkit-linear-gradient(top, #0FF 0%,#00F 20%,#0F0 100%);
background-image: -moz-linear-gradient(top, #0FF 0%,#00F 20%,#0F0 100%);
background-image: -ms-linear-gradient(top, #0FF 0%,#00F 20%,#0F0 100%);
background-image: -o-linear-gradient(top, #0FF 0%,#00F 20%,#0F0 100%);
background-image: linear-gradient(to bottom, #0FF 0%,#00F 20%,#0F0 100%); }
上記で読み込まれている gradient.svg の内容は、次のとおりです。
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
<defs>
<linearGradient id="G" x2="0" y1="100%">
<stop style="stop-color:#0FF" offset="0%"/>
<stop style="stop-color:#00F" offset="20%"/>
<stop style="stop-color:#0F0" offset="100%"/>
</linearGradient>
</defs>
<rect width="100%" height="100%" fill="url(#G)"/>
</svg>
CSS の gradient 関数は、SVG に由来していることもあり、コードを見比べてみればどこが何を表しているのかはすぐにわかるのではないでしょうか。
しかし、外部ファイルにしてしまうと CSS における gradient 関数のような利便性は失われてしまいます。そこで dataURI を利用します。dataURI は、バイナリーデータを base64 にエンコードして使うことが多いのですが、SVG の中身はバイナリーではなく XML でありテキストデータです。ですので、base64 エンコードせずとも、URL エンコードしてやれば dataURI として利用することができます。
先程の SVG を URL エンコードすると次のようになります。
%3c%3fxml%20version%3d%221%2e0%22%3f%3e%3csvg%20xmlns%3d%22http%3a%2f%2fwww%2ew3%2eorg%2f2000%2fsvg%22%20width%3d%22100%25%22%20height%3d%22100%25%22%3e%3cdefs%3e%3clinearGradient%20id%3d%22G%22%20x2%3d%220%25%22%20y2%3d%22100%25%22%3e%3cstop%20style%3d%22stop%2dcolor%3a%230FF%22%20offset%3d%220%25%22%2f%3e%3cstop%20style%3d%22stop%2dcolor%3a%2300F%22%20offset%3d%2220%25%22%2f%3e%3cstop%20style%3d%22stop%2dcolor%3a%230F0%22%20offset%3d%22100%25%22%2f%3e%3c%2flinearGradient%3e%3c%2fdefs%3e%3crect%20width%3d%22100%25%22%20height%3d%22100%25%22%20fill%3d%22url%28%23G%29%22%2f%3e%3c%2fsvg%3e
<、>、スペースが %3c, %20, %3e などに置き換わっているだけです。ですので、URL エンコードは、base64 エンコードと違い、ある程度内容を読むことができます。これならば、SASS の mixin に利用できるわけです。
上記の URL エンコード化した SVG の中を見てみると、途中に色(0FFなど)やオフセット(0など)がそのまま入っていることがわかります。抜粋すると例えば次などです。
%3cstop%20style%3d%22stop%2dcolor%3a%230FF%22%20offset%3d%220%25%22%2f%3e
そして、ここに mixin の引数として入力した値をそのまま入れてやればいいのです。以上の結果から冒頭で紹介した mixin の本体は次のようになります。
@mixin linear-gradient($angle, $color1, $offset1, $color2 ,$offset2:100, $color3:null, $offset3:100, $color4:null, $offset4:100, $color5:null, $offset5:100){
$angle_old:'';
$angle_webkit:'';
$angle_svg:'';
$color-stop1_css:'#'#{$color1}' '#{$offset1}'%';
$color-stop2_css:',#'#{$color2}' '#{$offset2}'%';
$color-stop3_css:'';
$color-stop4_css:'';
$color-stop5_css:'';
$color-stop1_svg:'%3cstop%20style%3d%22stop%2dcolor%3a%23'#{$color1}'%22%20offset%3d%22'#{$offset1}'%25%22%2f%3e';
$color-stop2_svg:'%3cstop%20style%3d%22stop%2dcolor%3a%23'#{$color2}'%22%20offset%3d%22'#{$offset2}'%25%22%2f%3e';
$color-stop3_svg:'';
$color-stop4_svg:'';
$color-stop5_svg:'';
$color-stop1_webkit:'color-stop('#{$offset1}'%, #'#{$color1}')';
$color-stop2_webkit:',color-stop('#{$offset2}'%, #'#{$color2}')';
$color-stop3_webkit:'';
$color-stop4_webkit:'';
$color-stop5_webkit:'';
@if $angle == "to bottom"{
$angle_old:'top';
$angle_webkit:'left top, left bottom';
$angle_svg:'%20x2%3d%220%25%22%20y2%3d%22100%25%22';
}
@if $angle == "to left"{
$angle_old:'right,';
$angle_webkit:'right top, left top';
$angle_svg:'%20x2%3d%22100%25%22';
}
@if $angle == "to top"{
$angle_old:'bottom,';
$angle_webkit:'left bottom, left top';
$angle_svg:'%20x2%3d%220%22%20y1%3d%22100%25%22';
}
@if $angle == "to right"{
$angle_old:'left,';
$angle_webkit:'left top, right top';
$angle_svg:'';
}
@if $color3 != null {
$color-stop3_css:',#'#{$color3}' '#{$offset3}'%';
$color-stop3_svg:'%3cstop%20style%3d%22stop%2dcolor%3a%23'#{$color3}'%22%20offset%3d%22'#{$offset3}'%25%22%2f%3e';
$color-stop3_webkit:',color-stop('#{$offset3}'%, #'#{$color3}')';
}
@if $color4 != null {
$color-stop4_css:',#'#{$color4}' '#{$offset4}'%';
$color-stop4_svg:'%3cstop%20style%3d%22stop%2dcolor%3a%23'#{$color4}'%22%20offset%3d%22'#{$offset4}'%25%22%2f%3e';
$color-stop4_webkit:',color-stop('#{$offset4}'%, #'#{$color4}')';
}
@if $color5 != null {
$color-stop5_css:',#'#{$color5}' '#{$offset5}'%';
$color-stop5_svg:'%3cstop%20style%3d%22stop%2dcolor%3a%23'#{$color5}'%22%20offset%3d%22'#{$offset5}'%25%22%2f%3e';
$color-stop5_webkit:',color-stop('#{$offset5}'%, #'#{$color5}')';
}
-pie-background: linear-gradient(#{$angle_old},#{$color-stop1_css}#{$color-stop2_css}#{$color-stop3_css}#{$color-stop4_css}#{$color-stop5_css});
background-image: url(data:image/svg+xml,%3c%3fxml%20version%3d%221%2e0%22%3f%3e%3csvg%20xmlns%3d%22http%3a%2f%2fwww%2ew3%2eorg%2f2000%2fsvg%22%20width%3d%22100%25%22%20height%3d%22100%25%22%3e%3cdefs%3e%3clinearGradient%20id%3d%22G%22#{$angle_svg}%3e#{$color-stop1_svg}#{$color-stop2_svg}#{$color-stop3_svg}#{$color-stop4_svg}#{$color-stop5_svg}%3c%2flinearGradient%3e%3c%2fdefs%3e%3crect%20width%3d%22100%25%22%20height%3d%22100%25%22%20fill%3d%22url%28%23G%29%22%2f%3e%3c%2fsvg%3e);
background-image: -webkit-gradient(linear,#{$angle_webkit},#{$color-stop1_webkit}#{$color-stop2_webkit}#{$color-stop3_webkit}#{$color-stop4_webkit}#{$color-stop5_webkit});
background-image:-webkit-linear-gradient(#{$angle_old},#{$color-stop1_css}#{$color-stop2_css}#{$color-stop3_css}#{$color-stop4_css}#{$color-stop5_css});
background-image: -moz-linear-gradient(#{$angle_old},#{$color-stop1_css}#{$color-stop2_css}#{$color-stop3_css}#{$color-stop4_css}#{$color-stop5_css});
background-image: -ms-linear-gradient(#{$angle_old},#{$color-stop1_css}#{$color-stop2_css}#{$color-stop3_css}#{$color-stop4_css}#{$color-stop5_css});
background-image: -o-linear-gradient(#{$angle_old},#{$color-stop1_css}#{$color-stop2_css}#{$color-stop3_css}#{$color-stop4_css}#{$color-stop5_css});
background-image: linear-gradient(#{$angle},#{$color-stop1_css}#{$color-stop2_css}#{$color-stop3_css}#{$color-stop4_css}#{$color-stop5_css});
}
さて、URL エンコード内では、colorStop 用の % や色コードの # をそのまま文字列として使うことができません。なので、冒頭で紹介した mixin の引数には % や # がついた状態ではなく、それらを取り除いた状態にしているわけです。SASS で文字列の replace ができればいいのですが…。ただ、これは内部で JavaScript のメソッドを利用可能な LESS でなら解決できる問題ですね。LESS いいですね。
というわけで、まとめとして
- CSS の gradient 関数は、SVG の Gradient にとても似ている
- SVG の内容はバイナリーではなくテキストなので動的な操作が簡単
- SASS より LESS が便利
ということがわかりました。
SASS では replace や文字列の加工などができませんが、LESS ならこれが可能です。おそらく、ここで示した mixin を LESS ように置き換えるならもっとシンプルになりそうです。
THREE.js で WebGL
JavaScript Advent Calendar 2011 (WebGL コース) の2日目として、この記事では THREE.js 経由で、WebGL を利用し 3D オブジェクトを表示するためのチュートリアルを紹介します。(WebGL とは、canvas 要素内で 3D を扱うための仕組みです)
この記事では最終的に次のデモを完成させます。
この記事で最終的に完成する demo (Chrome, Firefox, Opera などのWebGL が有効なブラウザー専用)
WebGL は普通に書くと OpenGL の shading の言語を理解していなければならず、よくわからないし難しいです。しかし、THREE.js のような WebGL のラッパーライブラリーを使うことで、JavaScript の知識の範囲で WebGL を扱うことができます。
THREE.js で 3D のグラフィクスを表示するためには…
- 下準備
- カメラを用意
- シーンを用意
- メッシュを作成
- ジオメトリーを作成
- マテリアルを作成
- メッシュをシーンに追加
- 光源を作成
- 光源をシーンに追加
- レンダラーを用意
- レンダラーをDOMに追加
- レンダリング
- アニメーション
といった手順を踏むことになります。(一部前後しても可能)
下準備
THREE.js を入手し、HTML 内に読み込みましょう。あわせて、領域の大きさも決めておきます。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>demo</title>
<script src="Three.js"></script>
<script>
window.addEventListener("DOMContentLoaded", function(){
var width = 600;
var height = 600;
});
</script>
</head>
<body>
</body>
</html>
カメラを用意
THREE.js のカメラにはいくつか種類があり、透視投影と平行投影のどちらの投影法も利用することができます。
| 透視投影 | THREE.PerspectiveCamera |
|---|---|
| 平行投影 | THREE.OrthographicCamera |

ここでは、透視投影を利用してみましょう。THREE.PerspectiveCamera には 画角, 縦横比, クリッピング手前, クリッピング奥 を渡します。クリッピング手前は、無限に近い場合を描画しないようにするため、クリッピング奥は、無限に遠い場所を描画しないようにするために設定します。つまり、クリッピングの手前と奥までの間が描画されることになります。
画角を変数 fov, 縦横比を変数 aspect, クリッピング手前を変数 near,クリッピング奥を変数 far としてカメラを設置するならば次のようになります。また、カメラの位置は x, y, z 方向に動かすこともできます。次の例では z 方向に 500 ずらしています。
<script>
window.addEventListener("DOMContentLoaded", function(){
var width = 600;
var height = 600;
var fov = 80;
var aspect = width / height;
var near = 1;
var far = 1000;
var camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
camera.position.z = 500;
});
</script>
シーンを用意
シーンを用意します。シーンとは空間を意味し、この中にさまざまなオブジェクト (物体) などを詰め込み、配置していくことになります。
<script>
window.addEventListener("DOMContentLoaded", function(){
var width = 600;
var height = 600;
var fov = 80;
var aspect = width / height;
var near = 1;
var far = 1000;
var camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
camera.position.z = 500;
var scene = new THREE.Scene();
});
</script>
メッシュを作成
メッシュとはポリゴンの集合により作られたオブジェクト (物体) のことを言います。メッシュは、ジオメトリー (座標) とマテリアル (表面素材) によって構成されます。
ジオメトリーを作成
ジオメトリーは、大きく分けて、
- あらかじめ THREE.js で用意されたプリミティブなジオメトリー
- 独自にモデリングしたジオメトリー
のどちらかを利用することができます。ここでは基本として、プリミティブなジオメトリーである、THREE.CubeGeometry を利用します。
THREE.CubeGeometry の引数には、横幅, 高さ, 奥行き, 横の分割数, 縦の分割数, 奥行きの分割数, 表面, sides を渡すことができます。横幅、高さ、奥行き以外はオプションです。sides は…何かよくわからなかったです。
ここでは、横幅、高さ、奥行きがそれぞれ 200 の立方体となるジオメトリーを用意しています。
<script>
window.addEventListener("DOMContentLoaded", function(){
var width = 600;
var height = 600;
var fov = 80;
var aspect = width / height;
var near = 1;
var far = 1000;
var camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
camera.position.z = 500;
var scene = new THREE.Scene();
var geometry = new THREE.CubeGeometry(200, 200, 200);
});
</script>
ジオメトリーは、この他にも THREE.SphereGeometry : 球体、THREE.TextGeometry : テキスト
THREE.TorusGeometry : トーラス(ドーナツ状の形)
などさまざまあります。また、独自にモデリングしたジオメトリーを利用することもでき、その例は、この記事の最後に参考として添付しています。
マテリアルを作成
先ほど作成したジオメトリーの表面に割り当てるマテリアルを用意しておきます。THREE.js ではさまざまなマテリアル表現を選択できます。ここではランバート反射表現が可能な THREE.MeshLambertMaterial を利用します。
THREE.MeshLambertMaterial の引数には、さまざまなプロパティーをもった object を渡すことができ、例えば、color, opacity,
, blending などがあります。今回はごく単純に color のみを指定します。
<script>
window.addEventListener("DOMContentLoaded", function(){
var width = 600;
var height = 600;
var fov = 80;
var aspect = width / height;
var near = 1;
var far = 1000;
var camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
camera.position.z = 500;
var scene = new THREE.Scene();
var geometry = new THREE.CubeGeometry(200, 200, 200);
var material = new THREE.MeshLambertMaterial( { color: 0x660000 } );
});
</script>
マテリアルはこの他にも THREE.MeshBasicMaterial や鏡面反射が可能 THREE.MeshPhongMaterial などさまざま用意されています。それぞれの引数に渡せる object のプロパティーは異なり、例えば THREE.MeshPhongMaterial には specular や shininess など輝きに関連する内容を渡すことができます。
メッシュを作成
ジオメトリーとマテリアルを合わせて一つのメッシュとします。THREE.Mesh の引数に ジオメトリー, マテリアル を渡します。
<script>
window.addEventListener("DOMContentLoaded", function(){
var width = 600;
var height = 600;
var fov = 80;
var aspect = width / height;
var near = 1;
var far = 1000;
var camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
camera.position.z = 500;
var scene = new THREE.Scene();
var geometry = new THREE.CubeGeometry(200, 200, 200);
var material = new THREE.MeshLambertMaterial( { color: 0x660000 } );
var cubeMesh = new THREE.Mesh( geometry, material);
});
</script>
メッシュをシーンに追加
先ほど用意したメッシュをシーンに追加します。シーンに何かを追加する際には、シーン.add(メッシュ) とします。シーンは scene、メッシュは cubeMesh という名前で用意しているので、ここでは scene.add( cubeMesh ); となればいいわけです。
<script>
window.addEventListener("DOMContentLoaded", function(){
var width = 600;
var height = 600;
var fov = 80;
var aspect = width / height;
var near = 1;
var far = 1000;
var camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
camera.position.z = 500;
var scene = new THREE.Scene();
var geometry = new THREE.CubeGeometry(200, 200, 200);
var material = new THREE.MeshLambertMaterial( { color: 0x660000 } );
var cubeMesh = new THREE.Mesh( geometry, material);
scene.add( cubeMesh );
});
</script>
光源を作成
次に、光源を作成します。光に影響する表面素材を利用している場合、光源がないと真っ暗で何も見えなくなってしまいます。
THREE.js では、環境光、平行光源、点光源、スポットライトを利用できます。
| 環境光 | THREE.AmbientLight |
|---|---|
| 平行光源 (無限遠光源) | THREE.DirectionalLight |
| 点光源 | THREE.PointLight |
| スポットライト | THREE.SpotLight |
この例では、太陽のように一定の方向で全体を照らしてくれる平行光源を利用します。もちろん、追加で複数の種類の光源を複数回利用することもできます。
THREE.DirectionalLight の引数には、色, 強さ を渡します。
また、真上からの光ではつまらないので少し斜めにしておきます。次のコードでは、平行光源.position.z で少し手前にずらしています。
<script>
window.addEventListener("DOMContentLoaded", function(){
var width = 600;
var height = 600;
var fov = 80;
var aspect = width / height;
var near = 1;
var far = 1000;
var camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
camera.position.z = 500;
var scene = new THREE.Scene();
var geometry = new THREE.CubeGeometry(200, 200, 200);
var material = new THREE.MeshLambertMaterial( { color: 0x660000 } );
var cubeMesh = new THREE.Mesh( geometry, material);
scene.add( cubeMesh );
var directionalLight = new THREE.DirectionalLight( 0xffffff, 3 );
directionalLight.position.z = 3;
});
</script>
光源をシーンに追加
先ほど用意した光源をシーンに追加します。シーンにメッシュを追加する際と同様に、シーン.add(光源) とします。シーンは scene、先ほど作成した平行光源は directionalLight という名前で用意しているので、ここでは scene.add( directionalLight ); となればいいわけです。
<script>
window.addEventListener("DOMContentLoaded", function(){
var width = 600;
var height = 600;
var fov = 80;
var aspect = width / height;
var near = 1;
var far = 1000;
var camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
camera.position.z = 500;
var scene = new THREE.Scene();
var geometry = new THREE.CubeGeometry(200, 200, 200);
var material = new THREE.MeshLambertMaterial( { color: 0x660000 } );
var cubeMesh = new THREE.Mesh( geometry, material);
scene.add( cubeMesh );
var directionalLight = new THREE.DirectionalLight( 0xffffff, 3 );
directionalLight.position.z = 3;
scene.add( directionalLight );
});
</script>
レンダラーを用意
ここまでの流れで、表示するための内容、つまり、カメラ、シーン、シーンの内容が揃いました。これらを実際に表示するための準備として、レンダラーを用意します。
THREE.js ではレンダリング方法ががあり、WebGL 意外にも、2Dcanvas, SVG を利用したレンダリングも可能です。ここではせっかくなので WebGL をつかったレンダリングを行います。
THREE.WebGLRenderer でレンダラーを用意し、レンダラー.setSize(横幅, 高さ) で大きさを決めておきます。
そして、renderer.domElement を DOM に appendChild し、Web ページ上にビューポートを設置します。このとき、WebGL でレンダリングさせている場合には、canvas要素が配置されます。
<script>
window.addEventListener("DOMContentLoaded", function(){
var width = 600;
var height = 600;
var fov = 80;
var aspect = width / height;
var near = 1;
var far = 1000;
var camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
camera.position.z = 500;
var scene = new THREE.Scene();
var geometry = new THREE.CubeGeometry(200, 200, 200);
var material = new THREE.MeshLambertMaterial( { color: 0x660000 } );
var cubeMesh = new THREE.Mesh( geometry, material);
scene.add( cubeMesh );
var directionalLight = new THREE.DirectionalLight( 0xffffff, 3 );
directionalLight.position.z = 3;
scene.add( directionalLight );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( width, height );
document.body.appendChild( renderer.domElement );
});
</script>
レンダリング
ここまでですべての準備が整いました。最後にレンダラー.render(シーン, カメラ)でレンダリングすることで、メッシュが光源の影響を受けて描画されます。
<script>
window.addEventListener("DOMContentLoaded", function(){
var width = 600;
var height = 600;
var fov = 80;
var aspect = width / height;
var near = 1;
var far = 1000;
var camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
camera.position.z = 500;
var scene = new THREE.Scene();
var geometry = new THREE.CubeGeometry(200, 200, 200);
var material = new THREE.MeshLambertMaterial( { color: 0x660000 } );
var cubeMesh = new THREE.Mesh( geometry, material);
scene.add( cubeMesh );
var directionalLight = new THREE.DirectionalLight( 0xffffff, 3 );
directionalLight.position.z = 3;
scene.add( directionalLight );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( width, height );
document.body.appendChild( renderer.domElement );
renderer.render( scene, camera );
});
</script>
アニメーション
ただ静止状態のまま表示しても、3D としてあまり面白くありません。アニメーションさせてみましょう。カメラやメッシュ、光源などを動かしながら連続でレンダリングすることでアニメーションさせることができます。
メッシュを少しずつ回転させながら連続でレンダリングする例は次のようになります。
<script>
window.addEventListener("DOMContentLoaded", function(){
var width = 600;
var height = 600;
var fov = 80;
var aspect = width / height;
var near = 1;
var far = 1000;
var camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
camera.position.z = 500;
var scene = new THREE.Scene();
var geometry = new THREE.CubeGeometry(200, 200, 200);
var material = new THREE.MeshLambertMaterial( { color: 0x660000 } );
var cubeMesh = new THREE.Mesh( geometry, material);
scene.add( cubeMesh );
var directionalLight = new THREE.DirectionalLight( 0xffffff, 3 );
directionalLight.position.z = 3;
scene.add( directionalLight );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( width, height );
document.body.appendChild( renderer.domElement );
renderer.render( scene, camera );
function rendering(){
cubeMesh.rotation.x += 0.01;
cubeMesh.rotation.y += 0.01;
renderer.render( scene, camera );
setTimeout(rendering, 30);
}
rendering();
});
</script>
これで冒頭のデモが完成します。
まとめ
ここまで見てきたとおり、THREE.js は、JavaScript と、3DCG に対する少しの知識があれば、WegGL を扱うことができるライブラリーというわけです。
WebGL は敷居が高いと感じているフロントエンドの技術者さんも多いのではないでしょうか。しかし、THREE.js はフロントエンドの技術者でも WebGL を触りやすくしてくれているのです。どんどん試してみるといいんじゃぁないでしょうか!
あ、あと THREE.js をつかって、モデラーで作成した 3D オブジェクトも扱うことができます。
HTML5 でのセクションの誤用にご注意
最近になって HTML5 を採用した Web サイトが増えてきました。HTML5 にすることは、将来の拡張性などを考える便利でよさそうなのですが、特にセクション関連の要素についてよくわからないで使ってしまうと、機械に対して意図しない構造の文書となってしまいます。

そして、これがすでに現実にもあるのです。テレビ朝日の Web サイトでは、HTML5 が採用されています。しかし、tv asahi という大見出し付近のソースコードは、2011年 7月 11日現在では以下のようになっています。
<header>
<div class="inner cfix">
<section class="cfix">
<div class="fltL">
<h1 id="tvasahiLogo"><a href="/" onClick="javascript: pageTracker._trackPageview('/Top/Header/Logo');" class="pfix">tv asahi</a></h1>
</div>
<div id="largeBanner" class="fltR">
<!-- PLACEHOLDERtag start-->
<script language='JavaScript'>CM8ShowAd('banner')</script>
<noscript>
<a href='http://web-jp.ad-v.jp/adam/ep/click/tv-asahi.TOP/banner?cat=tv-asahi.TOP' target='_blank'>
<img src='http://web-jp.ad-v.jp/adam/noscript?cat=tv-asahi.TOP&format=banner' border='0'></a>
</noscript>
<!-- PLACEHOLDERtag end-->
</div><!-- banner -->
</section><!-- cfix -->
</div>
</header>上記コード内の h1 要素はページ全体の見出しを意図しているのだと考えられます。しかし、section 要素の誤用により、ここでの h1 要素は広告の見出しとして機能し、ページ全体の見出しとしては機能しません。(ここでの説明がよくわからないのであれば、HTML5 で Web ページを作成したとしてもセクション系の要素は利用すべきではないでしょう)
このように、HTML5…特にセクション関連についての理解が浅いまま HTML5 を利用してしまうと、時として残念な結果になってしまうわけです。

よくわからないうちは text/html で、doctype のみ HTML5 の形式にするなどがおすすめです。といった内容を CSS Nite in AOMORI で話させていただく予定です。東北の皆様、よろしくおねがいします。
IE10 PP 2 が公開されました。API もいろいろサポート !
Internet Explorer 10 Platform Preview 2 が公開されました。
新たにサポートされる機能として以下があります。
CSS
- Positioned Floats :
float: positioned;(CSS Floats and Positioning Level 3) に対応。この記事の冒頭の画像での Positioned Floats の実サンプル(IE 10 専用) - CSS3 Gradients : 線型、放射型のサポート。content プロパティなどでも利用可能。
- CSSOM Floating Point Value support
HTML5
- HTML5 Forms (ただし、機能のみサポートで、新しい UI はない)
- <script> の async 属性と defer 属性
- <iframe> の sandbox 属性 による操作権限コントロール
API
- HTML5 Drag and Drop : HTML5 のドラッグ・ドロップ
- HTML5 File API : ファイルの読み込み
- HTML5 Web Workers : 非同期での処理
- Web Performance APIs
- requestAnimationFrame : アニメーション用 setTimeout みたいの
- Page Visibility API : ウインドウが最小化されるなどで表示されているか否かがわかる API
- setImmediate
- Improved hit testing APIs : ヒットテスト
その他
- CSS の読み込み数制限の緩和
- Media Query Listeners : スクリプトからメディアクエリーのフィーチャーとマッチするかを判別
これまで、ハードウェアアクセラレーションを活かした、<video>、SVG、canvas などに注力しているように感じていましたが、今回のアップデートでは、多数の API が含まれています。Internet Explorer 10 は Chrome や Firefox と同様に、単なる Web ブラウザーではなく、アプリケーションのランタイムとして利用できるプラットフォームになりつつあるといえます。
上記でサポートされる File API は、これまで Microsoft HTML5 Labs でフィーチャーされていました。HTML5 Labs では、この他に Web Sockets (ソケット通信)、Media Capture API (カメラ機器などへのアクセス) などもフィーチャーしており、今後の実装が期待できます。
なお、PP 1 の段階では
- CSS 3 Multi-Columns
- CSS 3 Flexible Box Layout
- Grid Layout
- CSS Gradients
をサポートしており、また、CSS3 Transtions、CSS3 Transform 3D のサポート予定も発表しています。
Microsoft MVP for Internet Explorer にアワードされました

4月 1日に Microsoft より Internet Explorer の MVP (Most Valuable Professional) として表彰されました。IE へのフィードバックや IE に関連する内容での講演、その他 Web 技術の執筆などを評価いただいたようでした。
MVP へお声がけくださった 五寳さん 、そして、講演などの機会を与えてくださった鷹野さんや自分の周りの皆様のおかげです。ありがとうございます。
IE は特に IE8 リリース前ころよりいろいろと注目してきました。つい最近は IE9 のリリースがあり、そして先日の MIX11 での IE10 の発表と IE に大きな変化起こりました。今後も IE にますます注目していきたいと思っています。
(IE 好きですが、IE に限らずブラウザーとベンダーはフラットにみんな好きです)

デモ。 (Chrome, Firefox, Opera などのWebGL が有効なブラウザー専用)
