2Dフラクタルノイズで地形を生成して、山を回転させるアニメーションのゲーム。
スペースキーを押すことで新しい地形を再生成します。
Three.jsを使って3Dで生成された山の地形を描画し、それを回転させるアニメーションを実現しています。また、スペースキーを押すと異なる地形が再生成されます。
Three.js を使って3D地形を生成し、アニメーションさせています。
フラクタルノイズ を用いて山のような地形を生成しています。
スペースキーを押すと、新しい地形がランダムに生成されます。
シーン、カメラ、レンダラー の作成:
シーンは3Dオブジェクトを配置する空間。
カメラはシーンを観察する視点を提供。
レンダラーはWebGLを使ってシーンをブラウザに描画。
地形メッシュとマテリアル:
PlaneGeometryを使って100x100の分割されたメッシュを作成。
地形の色は緑(0x228B22)で、ワイヤーフレームではなく実際の地形として描画。
光源:
AmbientLight(環境光)で全体を照らし、PointLight(ポイント光源)で太陽のような光を表現。
ノイズの生成:
Perlinノイズをベースにしたフラクタルノイズで山の地形を作成しています。各頂点のz軸をこのノイズで計算し、高低差を作り出しています。
アニメーション:
地形はplane.rotation.zの値を少しずつ増やして回転させています。これにより、地形が回転しているように見えます。
スペースキーでの地形再生成:
キーボードのスペースキーを押すと、新しいノイズパターンを使って地形を再生成します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Terrain Rotation</title>
<style>
body { margin: 0; overflow: hidden; }
canvas { display: block; }
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
// シーン、カメラ、レンダラーの作成
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 地形用のメッシュとマテリアル
const geometry = new THREE.PlaneGeometry(10, 10, 100, 100); // 100x100のメッシュ
const material = new THREE.MeshStandardMaterial({ color: 0x228B22, wireframe: false });
const plane = new THREE.Mesh(geometry, material);
plane.rotation.x = -Math.PI / 2; // 平面を横に回転させる
scene.add(plane);
// 環境光源とポイント光源(太陽のような光)
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); // 環境光
scene.add(ambientLight);
const pointLight = new THREE.PointLight(0xffffff, 1, 100);
pointLight.position.set(5, 10, 5); // 光源の位置
scene.add(pointLight);
// カメラ位置の設定
camera.position.z = 10;
camera.position.y = 5;
camera.lookAt(plane.position);
// ノイズ生成用の関数 (2Dフラクタルノイズ)
function fade(t) {
return t * t * t * (t * (t * 6 - 15) + 10);
}
function lerp(t, a, b) {
return a + t * (b - a);
}
function grad(hash, x, y) {
const h = hash & 15;
const u = h < 8 ? x : y;
const v = h < 4 ? y : x;
return ((h & 1) === 0 ? u : -u) + ((h & 2) === 0 ? v : -v);
}
const permutation = [...Array(256).keys()];
for (let i = permutation.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[permutation[i], permutation[j]] = [permutation[j], permutation[i]];
}
const p = [...permutation, ...permutation];
function perlin(x, y) {
const X = Math.floor(x) & 255;
const Y = Math.floor(y) & 255;
x -= Math.floor(x);
y -= Math.floor(y);
const u = fade(x);
const v = fade(y);
const A = p[X] + Y;
const B = p[X + 1] + Y;
return lerp(v, lerp(u, grad(p[A], x, y), grad(p[B], x - 1, y)),
lerp(u, grad(p[A + 1], x, y - 1), grad(p[B + 1], x - 1, y - 1)));
}
// フラクタルノイズの生成
function fractalNoise(x, y, octaves, persistence) {
let total = 0;
let frequency = 1;
let amplitude = 1;
let maxValue = 0;
for (let i = 0; i < octaves; i++) {
total += perlin(x * frequency, y * frequency) * amplitude;
maxValue += amplitude;
amplitude *= persistence;
frequency *= 2;
}
return total / maxValue;
}
// 地形の生成関数
function generateTerrain() {
const positions = geometry.attributes.position.array;
for (let i = 0; i < positions.length; i += 3) {
const x = positions[i];
const y = positions[i + 1];
// フラクタルノイズによってz軸の位置を更新
const noiseValue = fractalNoise(x * 0.2, y * 0.2, 5, 0.5);
positions[i + 2] = noiseValue * 2; // Z軸を更新し、山のように変形
}
geometry.attributes.position.needsUpdate = true;
}
// 初期の地形を生成
generateTerrain();
// アニメーション用の変数
function animate() {
requestAnimationFrame(animate);
// 山の回転
plane.rotation.z += 0.005; // z軸で回転
// レンダリング
renderer.render(scene, camera);
}
// ウィンドウリサイズ時にレンダラーとカメラのアスペクト比を調整
window.addEventListener('resize', () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
// スペースキーで地形の再生成
window.addEventListener('keydown', (event) => {
if (event.code === 'Space') {
generateTerrain();
}
});
// アニメーションを開始
animate();
</script>
</body>
</html>
参考。
GLSL(OpenGL Shading Language)には、様々な組み込み関数とユーティリティ関数が用意されています。これらの関数は、シェーダー内での計算やデータ処理を助けるために設計されています。以下に、GLSLの主要な関数とそのカテゴリを示します。
数学関数
算術関数
abs(x): 絶対値
sign(x): 符号
min(x, y): 最小値
max(x, y): 最大値
clamp(x, minVal, maxVal): 値を範囲内に制限
mix(x, y, a): 線形補間
三角関数
sin(x): サイン
cos(x): コサイン
tan(x): タンジェント
asin(x): アークサイン
acos(x): アークコサイン
atan(x): アークタンジェント
atan(y, x): 2変数アークタンジェント
指数・対数関数
pow(x, y): 指数
exp(x): 指数関数
log(x): 自然対数
log2(x): 2を底とする対数
sqrt(x): 平方根
inversesqrt(x): 逆平方根
絶対値・浮動小数点関数
float(x): 浮動小数点数への変換
int(x): 整数への変換
round(x): 四捨五入
floor(x): 小数点以下切り捨て
ceil(x): 小数点以下切り上げ
ベクトル・行列関数
ベクトル関数
length(x): ベクトルの長さ
normalize(x): ベクトルの正規化
dot(x, y): ドット積
cross(x, y): クロス積
reflect(I, N): 反射ベクトル
refract(I, N, eta): 屈折ベクトル
行列関数
transpose(x): 行列の転置
inverse(x): 行列の逆行列
determinant(x): 行列の行列式
テクスチャ関数
サンプリング関数
texture2D(sampler2D, coord): 2Dテクスチャサンプリング
texture3D(sampler3D, coord): 3Dテクスチャサンプリング
textureCube(samplerCube, coord): キューブマップテクスチャサンプリング
テクスチャ関連
textureSize(sampler2D, level): テクスチャのサイズ取得
texelFetch(sampler2D, P, lod): 指定されたレベルのテクセル取得
数値演算関数
浮動小数点数演算
mod(x, y): 剰余
fmod(x, y): 浮動小数点剰余
fract(x): 小数部分
trunc(x): 切り捨て整数
ビット操作関数(GLSL 4.0以降)
bitCount(x): ビット数
bitFieldExtract(x, offset, count): ビットフィールド抽出
bitFieldInsert(x, insert, offset, count): ビットフィールド挿入
bitReverse(x): ビット反転
その他の関数
制御関数
if(condition) { ... }: 条件付き実行
for(init; condition; increment) { ... }: ループ
while(condition) { ... }: 繰り返し
switch(expression) { case value: ... break; ... default: ... }: スイッチ文
discard;: 現在のフラグメントを描画しない
エラー処理
assert(condition);: 条件が満たされない場合にエラーを発生させる(GLSL 4.30以降)
関数の定義
void functionName(params) { ... }: GLSLでは、シェーダー内で関数を定義し、呼び出すことができます。引数や戻り値の型を指定し、複雑な処理を分割して管理することができます。
シェーダー内での利用
シェーダー内でこれらの関数を利用することで、さまざまなグラフィックス処理を効率的に行うことができます。例えば、頂点シェーダーでは、頂点の位置計算や変換を行い、フラグメントシェーダーでは、ピクセルごとの色計算やテクスチャサンプリングを行います。
GLSLコードのサンプル
以下に、いくつかのGLSLの関数を使ったシンプルなシェーダーの例を示します。
頂点シェーダーのサンプル
#version 300 es
layout(location = 0) in vec4 a_position; // 頂点位置
layout(location = 1) in vec4 a_color; // 頂点カラー
out vec4 v_color; // フラグメントシェーダーへの出力
void main() {
gl_Position = a_position; // 頂点の位置を設定
v_color = a_color; // 頂点カラーをフラグメントシェーダーへ渡す
}
フラグメントシェーダーのサンプル
#version 300 es
precision mediump float; // 浮動小数点の精度指定
in vec4 v_color; // 頂点シェーダーからの入力
out vec4 fragColor; // 最終的なフラグメント色
void main() {
fragColor = v_color; // 頂点カラーをそのまま出力
}
まとめ
GLSLの組み込み関数は、グラフィックスシェーダーでの計算や処理を効率的に行うための強力なツールです。