Skip to content
Snippets Groups Projects
Commit b357ae13 authored by Hyung-Taik Choi's avatar Hyung-Taik Choi
Browse files

Initial commit

parent 54ed78b0
Branches
No related tags found
No related merge requests found
MIT License MIT License
Copyright (c) 2017 Pavel Dobryakov Copyright (c) 2021 Hyung-Taik Choi
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
......
# WebGL Fluid Simulation # WebGL Fluid Simulation Tutorial
[Play here](https://paveldogreat.github.io/WebGL-Fluid-Simulation/)
<img src="/screenshot.jpg?raw=true" width="880">
## References
http://developer.download.nvidia.com/books/HTML/gpugems/gpugems_ch38.html
https://github.com/mharrys/fluids-2d
https://github.com/haxiomic/GPU-Fluid-Experiments
## License
The code is available under the [MIT license](LICENSE)
This diff is collapsed.
...@@ -9,24 +9,12 @@ ...@@ -9,24 +9,12 @@
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes"> <meta name="mobile-web-app-capable" content="yes">
<link rel="apple-touch-icon" href="logo.png">
<link rel="icon" href="logo.png">
<title>WebGL Fluid Simulation</title> <title>WebGL Fluid Simulation</title>
<meta name="description" content="A WebGL fluid simulation that works in mobile browsers."> <meta name="description" content="A WebGL fluid simulation that works in mobile browsers.">
<meta property="og:type" content="website"> <!-- <script type="text/javascript" src="dat.gui.min.js"></script> -->
<meta property="og:title" content="Webgl Fluid Simulation">
<meta property="og:description" content="A WebGL fluid simulation that works in mobile browsers.">
<meta property="og:url" content="https://paveldogreat.github.io/WebGL-Fluid-Simulation/">
<meta property="og:image" content="https://paveldogreat.github.io/WebGL-Fluid-Simulation/logo.png">
<script type="text/javascript" src="dat.gui.min.js"></script>
<style> <style>
@font-face {
font-family: 'iconfont';
src: url('iconfont.ttf') format('truetype');
}
* { * {
user-select: none; user-select: none;
...@@ -49,176 +37,19 @@ ...@@ -49,176 +37,19 @@
height: 100%; height: 100%;
} }
.dg {
opacity: 0.9;
}
.dg .property-name {
overflow: visible;
}
.bigFont {
font-size: 150%;
color: #8C8C8C;
}
.cr.function.appBigFont {
font-size: 150%;
line-height: 27px;
color: #A5F8D3;
background-color: #023C40;
}
.cr.function.appBigFont .property-name {
float: none;
}
.cr.function.appBigFont .icon {
position: sticky;
bottom: 27px;
}
.icon {
font-family: 'iconfont';
font-size: 130%;
float: right;
}
.twitter:before {
content: 'a';
}
.github:before {
content: 'b';
}
.app:before {
content: 'c';
}
.discord:before {
content: 'd';
}
.promo {
display: none;
/* display: table; */
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
overflow: auto;
color: lightblue;
background-color: rgba(0,0,0,0.4);
animation: promo-appear-animation 0.35s ease-out;
}
.promo-middle {
display: table-cell;
vertical-align: middle;
}
.promo-content {
width: 80vw;
height: 80vh;
max-width: 80vh;
max-height: 80vw;
margin: auto;
padding: 0;
font-size: 2.8vmax;
font-family: Futura, "Trebuchet MS", Arial, sans-serif;
text-align: center;
background-image: url("promo_back.png");
background-position: center;
background-repeat: no-repeat;
background-size: cover;
border-radius: 15px;
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2), 0 6px 20px 0 rgba(0,0,0,0.19);
}
.promo-header {
height: 10%;
padding: 2px 16px;
}
.promo-close {
width: 10%;
height: 100%;
text-align: left;
float: left;
font-size: 1.3em;
/* transition: 0.2s; */
}
.promo-close:hover {
/* transform: scale(1.25); */
cursor: pointer;
}
.promo-body {
padding: 8px 16px 16px 16px;
margin: auto;
}
.promo-body p {
margin-top: 0;
mix-blend-mode: color-dodge;
}
.link {
width: 100%;
display: inline-block;
}
.link img {
width: 100%;
}
@keyframes promo-appear-animation {
0% {
transform: scale(2.0);
opacity: 0;
}
100% {
transform: scale(1.0);
opacity: 1;
}
}
</style> </style>
<script> <!-- <script>
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date; window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
ga('create', 'UA-105392568-1', 'auto'); ga('create', 'UA-105392568-1', 'auto');
ga('send', 'pageview'); ga('send', 'pageview');
</script> </script>
<script async src="https://www.google-analytics.com/analytics.js"></script> <script async src="https://www.google-analytics.com/analytics.js"></script> -->
</head> </head>
<body> <body>
<canvas></canvas> <canvas></canvas>
<!-- Mother of God, pls forgive me -->
<div class="promo">
<div class="promo-middle">
<div class="promo-content">
<div class="promo-header">
<span class="promo-close">&times;</span>
</div>
<div class="promo-body">
<p>Try Fluid Simulation app!</p>
<div class="links-container">
<a class="link" id="apple_link" target="_blank">
<img class="link-img" alt="Download on the App Store" src="app_badge.png"/>
</a>
<a class="link" id="google_link" target="_blank">
<img class="link-img" alt="Get it on Google Play" src="gp_badge.png"/>
</a>
</div>
</div>
</div>
</div>
</div>
<script src="./script.js"></script> <script src="./script.js"></script>
</body> </body>
</html> </html>
\ No newline at end of file
/* /*
MIT License MIT License
Copyright (c) 2017 Pavel Dobryakov Copyright (c) 2021 Hyung-Taik Choi
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
...@@ -26,30 +26,30 @@ SOFTWARE. ...@@ -26,30 +26,30 @@ SOFTWARE.
// Mobile promo section // Mobile promo section
const promoPopup = document.getElementsByClassName('promo')[0]; // const promoPopup = document.getElementsByClassName('promo')[0];
const promoPopupClose = document.getElementsByClassName('promo-close')[0]; // const promoPopupClose = document.getElementsByClassName('promo-close')[0];
if (isMobile()) { // if (isMobile()) {
setTimeout(() => { // setTimeout(() => {
promoPopup.style.display = 'table'; // promoPopup.style.display = 'table';
}, 20000); // }, 20000);
} // }
promoPopupClose.addEventListener('click', e => { // promoPopupClose.addEventListener('click', e => {
promoPopup.style.display = 'none'; // promoPopup.style.display = 'none';
}); // });
const appleLink = document.getElementById('apple_link'); // const appleLink = document.getElementById('apple_link');
appleLink.addEventListener('click', e => { // appleLink.addEventListener('click', e => {
ga('send', 'event', 'link promo', 'app'); // ga('send', 'event', 'link promo', 'app');
window.open('https://apps.apple.com/us/app/fluid-simulation/id1443124993'); // window.open('https://apps.apple.com/us/app/fluid-simulation/id1443124993');
}); // });
const googleLink = document.getElementById('google_link'); // const googleLink = document.getElementById('google_link');
googleLink.addEventListener('click', e => { // googleLink.addEventListener('click', e => {
ga('send', 'event', 'link promo', 'app'); // ga('send', 'event', 'link promo', 'app');
window.open('https://play.google.com/store/apps/details?id=games.paveldogreat.fluidsimfree'); // window.open('https://play.google.com/store/apps/details?id=games.paveldogreat.fluidsimfree');
}); // });
// Simulation section // Simulation section
...@@ -113,7 +113,7 @@ if (!ext.supportLinearFiltering) { ...@@ -113,7 +113,7 @@ if (!ext.supportLinearFiltering) {
config.SUNRAYS = false; config.SUNRAYS = false;
} }
startGUI(); // startGUI();
function getWebGLContext (canvas) { function getWebGLContext (canvas) {
const params = { alpha: true, depth: false, stencil: false, antialias: false, preserveDrawingBuffer: false }; const params = { alpha: true, depth: false, stencil: false, antialias: false, preserveDrawingBuffer: false };
...@@ -153,7 +153,7 @@ function getWebGLContext (canvas) { ...@@ -153,7 +153,7 @@ function getWebGLContext (canvas) {
formatR = getSupportedFormat(gl, gl.RGBA, gl.RGBA, halfFloatTexType); formatR = getSupportedFormat(gl, gl.RGBA, gl.RGBA, halfFloatTexType);
} }
ga('send', 'event', isWebGL2 ? 'webgl2' : 'webgl', formatRGBA == null ? 'not supported' : 'supported'); // ga('send', 'event', isWebGL2 ? 'webgl2' : 'webgl', formatRGBA == null ? 'not supported' : 'supported');
return { return {
gl, gl,
...@@ -205,80 +205,40 @@ function supportRenderTextureFormat (gl, internalFormat, format, type) { ...@@ -205,80 +205,40 @@ function supportRenderTextureFormat (gl, internalFormat, format, type) {
return status == gl.FRAMEBUFFER_COMPLETE; return status == gl.FRAMEBUFFER_COMPLETE;
} }
function startGUI () { // function startGUI () {
var gui = new dat.GUI({ width: 300 }); // var gui = new dat.GUI({ width: 300 });
gui.add(config, 'DYE_RESOLUTION', { 'high': 1024, 'medium': 512, 'low': 256, 'very low': 128 }).name('quality').onFinishChange(initFramebuffers); // gui.add(config, 'DYE_RESOLUTION', { 'high': 1024, 'medium': 512, 'low': 256, 'very low': 128 }).name('quality').onFinishChange(initFramebuffers);
gui.add(config, 'SIM_RESOLUTION', { '32': 32, '64': 64, '128': 128, '256': 256 }).name('sim resolution').onFinishChange(initFramebuffers); // gui.add(config, 'SIM_RESOLUTION', { '32': 32, '64': 64, '128': 128, '256': 256 }).name('sim resolution').onFinishChange(initFramebuffers);
gui.add(config, 'DENSITY_DISSIPATION', 0, 4.0).name('density diffusion'); // gui.add(config, 'DENSITY_DISSIPATION', 0, 4.0).name('density diffusion');
gui.add(config, 'VELOCITY_DISSIPATION', 0, 4.0).name('velocity diffusion'); // gui.add(config, 'VELOCITY_DISSIPATION', 0, 4.0).name('velocity diffusion');
gui.add(config, 'PRESSURE', 0.0, 1.0).name('pressure'); // gui.add(config, 'PRESSURE', 0.0, 1.0).name('pressure');
gui.add(config, 'CURL', 0, 50).name('vorticity').step(1); // gui.add(config, 'CURL', 0, 50).name('vorticity').step(1);
gui.add(config, 'SPLAT_RADIUS', 0.01, 1.0).name('splat radius'); // gui.add(config, 'SPLAT_RADIUS', 0.01, 1.0).name('splat radius');
gui.add(config, 'SHADING').name('shading').onFinishChange(updateKeywords); // gui.add(config, 'SHADING').name('shading').onFinishChange(updateKeywords);
gui.add(config, 'COLORFUL').name('colorful'); // gui.add(config, 'COLORFUL').name('colorful');
gui.add(config, 'PAUSED').name('paused').listen(); // gui.add(config, 'PAUSED').name('paused').listen();
gui.add({ fun: () => { // gui.add({ fun: () => {
splatStack.push(parseInt(Math.random() * 20) + 5); // splatStack.push(parseInt(Math.random() * 20) + 5);
} }, 'fun').name('Random splats'); // } }, 'fun').name('Random splats');
let bloomFolder = gui.addFolder('Bloom'); // let bloomFolder = gui.addFolder('Bloom');
bloomFolder.add(config, 'BLOOM').name('enabled').onFinishChange(updateKeywords); // bloomFolder.add(config, 'BLOOM').name('enabled').onFinishChange(updateKeywords);
bloomFolder.add(config, 'BLOOM_INTENSITY', 0.1, 2.0).name('intensity'); // bloomFolder.add(config, 'BLOOM_INTENSITY', 0.1, 2.0).name('intensity');
bloomFolder.add(config, 'BLOOM_THRESHOLD', 0.0, 1.0).name('threshold'); // bloomFolder.add(config, 'BLOOM_THRESHOLD', 0.0, 1.0).name('threshold');
let sunraysFolder = gui.addFolder('Sunrays'); // let sunraysFolder = gui.addFolder('Sunrays');
sunraysFolder.add(config, 'SUNRAYS').name('enabled').onFinishChange(updateKeywords); // sunraysFolder.add(config, 'SUNRAYS').name('enabled').onFinishChange(updateKeywords);
sunraysFolder.add(config, 'SUNRAYS_WEIGHT', 0.3, 1.0).name('weight'); // sunraysFolder.add(config, 'SUNRAYS_WEIGHT', 0.3, 1.0).name('weight');
let captureFolder = gui.addFolder('Capture'); // let captureFolder = gui.addFolder('Capture');
captureFolder.addColor(config, 'BACK_COLOR').name('background color'); // captureFolder.addColor(config, 'BACK_COLOR').name('background color');
captureFolder.add(config, 'TRANSPARENT').name('transparent'); // captureFolder.add(config, 'TRANSPARENT').name('transparent');
captureFolder.add({ fun: captureScreenshot }, 'fun').name('take screenshot'); // captureFolder.add({ fun: captureScreenshot }, 'fun').name('take screenshot');
let github = gui.add({ fun : () => { // if (isMobile())
window.open('https://github.com/PavelDoGreat/WebGL-Fluid-Simulation'); // gui.close();
ga('send', 'event', 'link button', 'github'); // }
} }, 'fun').name('Github');
github.__li.className = 'cr function bigFont';
github.__li.style.borderLeft = '3px solid #8C8C8C';
let githubIcon = document.createElement('span');
github.domElement.parentElement.appendChild(githubIcon);
githubIcon.className = 'icon github';
let twitter = gui.add({ fun : () => {
ga('send', 'event', 'link button', 'twitter');
window.open('https://twitter.com/PavelDoGreat');
} }, 'fun').name('Twitter');
twitter.__li.className = 'cr function bigFont';
twitter.__li.style.borderLeft = '3px solid #8C8C8C';
let twitterIcon = document.createElement('span');
twitter.domElement.parentElement.appendChild(twitterIcon);
twitterIcon.className = 'icon twitter';
let discord = gui.add({ fun : () => {
ga('send', 'event', 'link button', 'discord');
window.open('https://discordapp.com/invite/CeqZDDE');
} }, 'fun').name('Discord');
discord.__li.className = 'cr function bigFont';
discord.__li.style.borderLeft = '3px solid #8C8C8C';
let discordIcon = document.createElement('span');
discord.domElement.parentElement.appendChild(discordIcon);
discordIcon.className = 'icon discord';
let app = gui.add({ fun : () => {
ga('send', 'event', 'link button', 'app');
window.open('http://onelink.to/5b58bn');
} }, 'fun').name('Check out mobile app');
app.__li.className = 'cr function appBigFont';
app.__li.style.borderLeft = '3px solid #00FF7F';
let appIcon = document.createElement('span');
app.domElement.parentElement.appendChild(appIcon);
appIcon.className = 'icon app';
if (isMobile())
gui.close();
}
function isMobile () { function isMobile () {
return /Mobi|Android/i.test(navigator.userAgent); return /Mobi|Android/i.test(navigator.userAgent);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment