three.jsで多色グラデーションを作る。

9頂点8平面で構成されるメッシュにShaderMaterialで作成した多色グラデーションを貼り付けている。多色グラデーションは頂点シェーダーとフラグメントシェーダーの組み合わせで実現する。
頂点シェーダー
attribute vec3 verpos;
attribute vec3 verrgb;
varying vec3 varingrgb;
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(verpos, 1.0);
varingrgb = verrgb;
}
フラグメントシェーダー
varying mediump vec3 varingrgb;
void main() {
gl_FragColor = vec4(varingrgb, 1.0);
}
verposには頂点の座標、verrgbには頂点の色が渡り、varingrgbでフラグメントシェーダーに引き渡される。頂点シェーダーの処理はVertexに対するが、フラグメントシェーダーはピクセルに対するため、GLSLが色を案分することでグラデーションが実現する。
3D操作はOrbitControls.jsを使っている。
OrbitControls.js
以下は全ソース(html)です。
直下にthree.min.jsとOrbitControls.jsがあれば動作します。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>shade test</title>
<script type="text/javascript" src="three.min.js"></script>
<script type="text/javascript" src="OrbitControls.js"></script>
<script type="text/javascript">
var renderer;
var camera;
var controls;
var scene;
var container;
var light;
var light2;
var mesh;
var geometry;
function shadetest() {
init_threejs();
init_scene();
init_camera();
init_light();
init_object();
reset_position();
loop();
}
function init_threejs() {
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setClearColor(0xffffff, 1);
renderer.setSize(1, 1);
container = document.getElementById('canvas3d');
container.appendChild(renderer.domElement);
}
function init_scene() {
scene = new THREE.Scene();
}
function init_camera() {
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 100000);
camera.up.x = 0;
camera.up.y = 0;
camera.up.z = 1;
camera.position.set(0, 0, 5);
controls = new THREE.OrbitControls(camera, renderer.domElement);
}
function init_light() {
light = new THREE.DirectionalLight(0xcccccc, 1.6);
light.position = new THREE.Vector3(-100, 500, 800);
scene.add(light);
light2 = new THREE.AmbientLight(0x333333);
scene.add(light2);
}
function init_object() {
var vertexPositions = [
[-1.0, -1.0, 1.0],
[0.0, -1.0, 1.0],
[1.0, -1.0, 1.0],
[-1.0, 0.0, 1.0],
[0.0, 0.0, 1.0],
[1.0, 0.0, 1.0],
[-1.0, 1.0, 1.0],
[0.0, 1.0, 1.0],
[1.0, 1.0, 1.0]
];
var vertexColors = [
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
[1.0, 1.0, 0.0],
[0.0, 1.0, 1.0],
[1.0, 0.0, 1.0],
[0.5, 0.5, 0.0],
[0.0, 0.5, 0.5],
[0.5, 0.0, 0.5]
];
var indices = new Uint16Array([
0, 1, 4,
1, 2, 4,
2, 5, 4,
5, 8, 4,
8, 7, 4,
7, 6, 4,
6, 3, 4,
3, 0, 4
]);
var vertices = new Float32Array(vertexPositions.length * 3);
var colors = new Float32Array(vertexPositions.length * 3);
for (var i = 0; i < vertexPositions.length; i++) {
vertices[i * 3 + 0] = vertexPositions[i][0];
vertices[i * 3 + 1] = vertexPositions[i][1];
vertices[i * 3 + 2] = vertexPositions[i][2];
colors[i * 3 + 0] = vertexColors[i][0];
colors[i * 3 + 1] = vertexColors[i][1];
colors[i * 3 + 2] = vertexColors[i][2];
}
var shader = {
fragmentShader: [
"varying mediump vec3 varingrgb;",
"void main() {",
"gl_FragColor = vec4(varingrgb, 1.0);",
"}"
].join("\n"),
vertexShader: [
"attribute vec3 verpos;",
"attribute vec3 verrgb;",
"varying vec3 varingrgb;",
"void main() {",
"gl_Position = projectionMatrix * modelViewMatrix * vec4(verpos, 1.0);",
"varingrgb = verrgb;",
"}"
].join("\n")
}
var material = new THREE.ShaderMaterial(
{
vertexShader: shader.vertexShader,
fragmentShader: shader.fragmentShader
}
);
var geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.BufferAttribute(vertices, 3));
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
geometry.addAttribute('verpos', new THREE.BufferAttribute(vertices, 3));
geometry.addAttribute('verrgb', new THREE.BufferAttribute(colors, 3));
var mesh = new THREE.Mesh(geometry, material);
mesh.position.set(0, 0, 0);
scene.add(mesh);
}
function reset_position() {
var sz = {w:container.offsetWidth, h:container.offsetHeight};
renderer.setSize(sz.w, sz.h);
camera.aspect = sz.w / sz.h;
camera.updateProjectionMatrix();
}
function loop() {
requestAnimationFrame(loop);
controls.update();
renderer.clear();
renderer.render(scene, camera);
}
</script>
</head>
<body onload="shadetest();" onresize="reset_position();">
<div id="canvas3d" style="width:300px;height:300px;">
</div>
</body>
</html>
1 thought on “three.jsで多色グラデーション”