質問するログイン新規登録

Q&A

1回答

358閲覧

3Dで水を表現したい

tesita

総合スコア0

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2026/09/24 16:09

0

0

3Dで水を表現したいです
海とかなら塊で表現できると思いますが
ちゃんと現実の物理として表示するにはどうしたらいいですか?
事象の名前とかは出せますが
ちゃんと波紋とか飛沫とか波がぶつかり合ってちゃんと上に逃げたりひろがったりみたいなのとか表現したいです
使える手法とかは調べれば出るとは思いますが複合的にやるものなんでしょうか?
ツイッターでみると粒上でやってる人見たことありますがなにでやるのがいいんでしょうか?
完全に確立されたものではないんですか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

fiveHundred

2026/09/25 04:53

用途は何ですか? というのも、全て計算するには非常に負荷が大きく、例えばゲームの場合、本来のゲーム処理に弊害が出てしまうため、それっぽく動かすだけにしておく、というのが主流だからです。
guest

回答1件

0

流体シミュレーションは普通はライブラリにまかせることが多いでしょう。
自力でやるのであればナビエ–ストークス方程式を利用することです。
なお完全な物理シミュレーションは負荷が高いのでスパコンの世界になります。
個人が趣味でやるレベルであればある程度簡略化して疑似処理でやるしかないと思います。

参考

「ライブラリになしのjavascriptで流体シミュレーション書いてよチャッピー」とお願いしたらサンプルを書いてくれました。
マウスクリックで染料投入、マウスムーブで流体シミュレーションです。参考までに

HTML

1<canvas id="canvas" width="600" height="600"></canvas> 2<script> 3const canvas = document.getElementById("canvas"); 4const ctx = canvas.getContext("2d"); 5const N = 100; 6const SIZE = N * N; 7const dt = 0.1; 8const viscosity = 0.00001; 9const pressureIterations = 30; 10const u = new Float32Array(SIZE); 11const v = new Float32Array(SIZE); 12const uPrev = new Float32Array(SIZE); 13const vPrev = new Float32Array(SIZE); 14const pressure = new Float32Array(SIZE); 15const pressurePrev = new Float32Array(SIZE); 16const divergence = new Float32Array(SIZE); 17const density = new Float32Array(SIZE); 18const densityPrev = new Float32Array(SIZE); 19function IX(x, y) { 20 return x + y * N; 21} 22function setBoundary(field, type) { 23 for (let i = 1; i < N - 1; i++) { 24 field[IX(i, 0)] = 25 type === 2 26 ? -field[IX(i, 1)] 27 : field[IX(i, 1)]; 28 field[IX(i, N - 1)] = 29 type === 2 30 ? -field[IX(i, N - 2)] 31 : field[IX(i, N - 2)]; 32 field[IX(0, i)] = 33 type === 1 34 ? -field[IX(1, i)] 35 : field[IX(1, i)]; 36 field[IX(N - 1, i)] = 37 type === 1 38 ? -field[IX(N - 2, i)] 39 : field[IX(N - 2, i)]; 40 } 41 field[IX(0, 0)] = 42 0.5 * ( 43 field[IX(1, 0)] + 44 field[IX(0, 1)] 45 ); 46 field[IX(0, N - 1)] = 47 0.5 * ( 48 field[IX(1, N - 1)] + 49 field[IX(0, N - 2)] 50 ); 51 field[IX(N - 1, 0)] = 52 0.5 * ( 53 field[IX(N - 2, 0)] + 54 field[IX(N - 1, 1)] 55 ); 56 field[IX(N - 1, N - 1)] = 57 0.5 * ( 58 field[IX(N - 2, N - 1)] + 59 field[IX(N - 1, N - 2)] 60 ); 61} 62function diffuse(field, source, diff, dt, boundaryType) { 63 const a = dt * diff * (N - 2) * (N - 2); 64 for (let k = 0; k < 20; k++) { 65 for (let y = 1; y < N - 1; y++) { 66 for (let x = 1; x < N - 1; x++) { 67 const i = IX(x, y); 68 field[i] = 69 ( 70 source[i] + 71 a * ( 72 field[IX(x - 1, y)] + 73 field[IX(x + 1, y)] + 74 field[IX(x, y - 1)] + 75 field[IX(x, y + 1)] 76 ) 77 ) 78 / 79 (1 + 4 * a); 80 } 81 } 82 setBoundary(field, boundaryType); 83 } 84} 85function advect( 86 field, 87 source, 88 uVelocity, 89 vVelocity, 90 dt, 91 boundaryType 92) { 93 const dt0 = dt * (N - 2); 94 for (let y = 1; y < N - 1; y++) { 95 for (let x = 1; x < N - 1; x++) { 96 const i = IX(x, y); 97 let px = x - dt0 * uVelocity[i]; 98 let py = y - dt0 * vVelocity[i]; 99 if (px < 0.5) px = 0.5; 100 if (px > N - 1.5) px = N - 1.5; 101 if (py < 0.5) py = 0.5; 102 if (py > N - 1.5) py = N - 1.5; 103 const x0 = Math.floor(px); 104 const x1 = x0 + 1; 105 const y0 = Math.floor(py); 106 const y1 = y0 + 1; 107 const sx = px - x0; 108 const sy = py - y0; 109 const i00 = IX(x0, y0); 110 const i10 = IX(x1, y0); 111 const i01 = IX(x0, y1); 112 const i11 = IX(x1, y1); 113 field[i] = 114 (1 - sy) * 115 ( 116 (1 - sx) * source[i00] + 117 sx * source[i10] 118 ) 119 + 120 sy * 121 ( 122 (1 - sx) * source[i01] + 123 sx * source[i11] 124 ); 125 } 126 } 127 setBoundary(field, boundaryType); 128} 129function project(u, v, pressure, divergence) { 130 for (let y = 1; y < N - 1; y++) { 131 for (let x = 1; x < N - 1; x++) { 132 const i = IX(x, y); 133 divergence[i] = 134 -0.5 * ( 135 u[IX(x + 1, y)] - 136 u[IX(x - 1, y)] + 137 v[IX(x, y + 1)] - 138 v[IX(x, y - 1)] 139 ) / N; 140 pressure[i] = 0; 141 } 142 } 143 setBoundary(divergence, 0); 144 setBoundary(pressure, 0); 145 for (let k = 0; k < pressureIterations; k++) { 146 for (let y = 1; y < N - 1; y++) { 147 for (let x = 1; x < N - 1; x++) { 148 const i = IX(x, y); 149 pressure[i] = 150 ( 151 divergence[i] + 152 pressure[IX(x - 1, y)] + 153 pressure[IX(x + 1, y)] + 154 pressure[IX(x, y - 1)] + 155 pressure[IX(x, y + 1)] 156 ) / 4; 157 } 158 } 159 setBoundary(pressure, 0); 160 } 161 for (let y = 1; y < N - 1; y++) { 162 for (let x = 1; x < N - 1; x++) { 163 const i = IX(x, y); 164 u[i] -= 165 0.5 * 166 N * 167 ( 168 pressure[IX(x + 1, y)] - 169 pressure[IX(x - 1, y)] 170 ); 171 v[i] -= 172 0.5 * 173 N * 174 ( 175 pressure[IX(x, y + 1)] - 176 pressure[IX(x, y - 1)] 177 ); 178 } 179 } 180 setBoundary(u, 1); 181 setBoundary(v, 2); 182} 183function velocityStep() { 184 uPrev.set(u); 185 vPrev.set(v); 186 diffuse( 187 u, 188 uPrev, 189 viscosity, 190 dt, 191 1 192 ); 193 diffuse( 194 v, 195 vPrev, 196 viscosity, 197 dt, 198 2 199 ); 200 project( 201 u, 202 v, 203 pressure, 204 divergence 205 ); 206 uPrev.set(u); 207 vPrev.set(v); 208 advect( 209 u, 210 uPrev, 211 uPrev, 212 vPrev, 213 dt, 214 1 215 ); 216 advect( 217 v, 218 vPrev, 219 uPrev, 220 vPrev, 221 dt, 222 2 223 ); 224 project( 225 u, 226 v, 227 pressure, 228 divergence 229 ); 230} 231function densityStep() { 232 densityPrev.set(density); 233 diffuse( 234 density, 235 densityPrev, 236 0.00001, 237 dt, 238 0 239 ); 240 densityPrev.set(density); 241 advect( 242 density, 243 densityPrev, 244 u, 245 v, 246 dt, 247 0 248 ); 249} 250let mouseX = 50; 251let mouseY = 50; 252let previousMouseX = 50; 253let previousMouseY = 50; 254let mouseDown = false; 255canvas.addEventListener("mousemove", function(e) { 256 const rect = canvas.getBoundingClientRect(); 257 mouseX = 258 (e.clientX - rect.left) 259 / rect.width 260 * N; 261 mouseY = 262 (e.clientY - rect.top) 263 / rect.height 264 * N; 265}); 266canvas.addEventListener("mousedown", function() { 267 mouseDown = true; 268}); 269canvas.addEventListener("mouseup", function() { 270 mouseDown = false; 271}); 272canvas.addEventListener("mouseleave", function() { 273 mouseDown = false; 274}); 275function addMouseForce() { 276 const x = Math.floor(mouseX); 277 const y = Math.floor(mouseY); 278 if ( 279 x < 2 || 280 x >= N - 2 || 281 y < 2 || 282 y >= N - 2 283 ) { 284 return; 285 } 286 const dx = mouseX - previousMouseX; 287 const dy = mouseY - previousMouseY; 288 const radius = 4; 289 for (let yy = -radius; yy <= radius; yy++) { 290 for (let xx = -radius; xx <= radius; xx++) { 291 const px = x + xx; 292 const py = y + yy; 293 if ( 294 px < 1 || 295 px >= N - 1 || 296 py < 1 || 297 py >= N - 1 298 ) { 299 continue; 300 } 301 const distance = 302 Math.sqrt(xx * xx + yy * yy); 303 if (distance > radius) { 304 continue; 305 } 306 const strength = 307 1 - distance / radius; 308 const i = IX(px, py); 309 u[i] += dx * 5 * strength; 310 v[i] += dy * 5 * strength; 311 if (mouseDown) { 312 density[i] += 5 * strength; 313 } 314 } 315 } 316 previousMouseX = mouseX; 317 previousMouseY = mouseY; 318} 319const image = 320 ctx.createImageData( 321 canvas.width, 322 canvas.height 323 ); 324function render() { 325 const pixels = image.data; 326 for (let py = 0; py < canvas.height; py++) { 327 for (let px = 0; px < canvas.width; px++) { 328 const x = 329 Math.floor( 330 px / canvas.width * N 331 ); 332 const y = 333 Math.floor( 334 py / canvas.height * N 335 ); 336 const d = 337 Math.min( 338 255, 339 density[IX(x, y)] * 255 340 ); 341 const index = 342 (px + py * canvas.width) * 4; 343 pixels[index] = d; 344 pixels[index + 1] = d * 0.15; 345 pixels[index + 2] = d * 0.15; 346 pixels[index + 3] = 255; 347 } 348 } 349 ctx.putImageData(image, 0, 0); 350} 351function update() { 352 addMouseForce(); 353 velocityStep(); 354 densityStep(); 355 render(); 356 requestAnimationFrame(update); 357} 358update(); 359</script>

投稿2026/09/25 09:22

編集2026/09/25 09:27
yambejp

総合スコア118675

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.25%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問