Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,19 @@ export default function App() {
const [isWaving, setIsWaving] = useState(false);
const [tiltAngle, setTiltAngle] = useState(0);
const [particleScale, setParticleScale] = useState(1);
const [gravityScale, setGravityScale] = useState(1);

return (
<div className="relative h-screen w-full overflow-hidden bg-gray-900">
{/* 1. Слой с водой (Канвас) — занимает весь экран на заднем плане */}
<div className="absolute inset-0 z-0">
<RealisticProgressBar progress={progress} isWaving={isWaving} tiltAngle={tiltAngle} particleScale={particleScale} />
<RealisticProgressBar
progress={progress}
isWaving={isWaving}
tiltAngle={tiltAngle}
particleScale={particleScale}
gravityScale={gravityScale}
/>
</div>

{/* 2. Слой интерфейса — только маленькая плашка внизу */}
Expand Down Expand Up @@ -79,6 +86,22 @@ export default function App() {
/>
</div>

<div>
<div className="mb-2 flex items-center justify-between text-[10px] uppercase tracking-wider text-white/60">
<span>Gravity</span>
<span>{gravityScale.toFixed(2)}x</span>
</div>
<input
type="range"
min="0"
max="2"
step="0.01"
value={gravityScale}
onChange={(e) => setGravityScale(parseFloat(e.target.value))}
className="w-full h-1.5 bg-white/10 rounded-lg appearance-none cursor-pointer accent-white"
/>
</div>

{/* Кнопка */}
<button
onClick={() => setIsWaving(!isWaving)}
Expand Down
9 changes: 9 additions & 0 deletions src/components/RealisticProgressBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ interface RealisticProgressBarProps {
className?: string;
meshQuality?: 'high' | 'balanced' | 'low';
particleScale?: number;
gravityScale?: number;
}


Expand Down Expand Up @@ -52,13 +53,15 @@ export const RealisticProgressBar: React.FC<RealisticProgressBarProps> = ({
className,
meshQuality = 'low',
particleScale = 1,
gravityScale = 1,
}) => {
const canvasRef = useRef<HTMLCanvasElement>(null);
const progressRef = useRef(progress);
const isWavingRef = useRef(isWaving);
const waveAmplitudeRef = useRef(0.0);
const timeRef = useRef(0.0);
const tiltAngleRef = useRef(tiltAngle);
const gravityScaleRef = useRef(gravityScale);
const smoothedTiltAngleRef = useRef(tiltAngle);
const kinematicPrevRef = useRef<KinematicSample | null>(null);
const reverseImpulseRef = useRef({ strength: 0.0, age: 1e6, deltaV: new Vec2(0, 0) });
Expand All @@ -76,6 +79,11 @@ export const RealisticProgressBar: React.FC<RealisticProgressBarProps> = ({
tiltAngleRef.current = tiltAngle;
}, [tiltAngle]);

useEffect(() => {
gravityScaleRef.current = gravityScale;
SPH.setGravityScale(gravityScale);
}, [gravityScale]);

useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
Expand Down Expand Up @@ -150,6 +158,7 @@ export const RealisticProgressBar: React.FC<RealisticProgressBarProps> = ({
let lastTime = performance.now();

const initAsync = async () => {
SPH.setGravityScale(gravityScaleRef.current);
const bgUrl = 'https://images.unsplash.com/photo-1618221195710-dd6b41faaea6?q=80&w=2000&auto=format&fit=crop';
const [bgTex] = await Promise.all([
GLU.loadTexture(gl, bgUrl),
Expand Down
16 changes: 13 additions & 3 deletions src/sph/sph.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import sortparticlesFrag from './sortparticles.frag?raw';
let _gl;

const _gravity = new Vec2(0, -10);
let _gravityScale = 1.0;
const _rho0 = 1; //1000だと圧力が半精度では表現できなくなるので適当な値にする
const _viscosity = 0.18 * _rho0;
const _surfTension = 2;
Expand Down Expand Up @@ -145,7 +146,8 @@ export const init = (gl, particleSpacing, fluidDomainRadius, posArray) => {
_initWallKernelTex();

let vel = new Array(posArray.length).fill(0);
let velh = vel.map((v, i) => v-_dt/2*(i%2===0?_gravity.x:_gravity.y));
let g = _scaledGravity();
let velh = vel.map((v, i) => v-_dt/2*(i%2===0?g.x:g.y));
let particleVBOs = [posArray, vel, velh].map(a => GLU.createVBO(_gl, a));
_initPosVelTex(particleVBOs);
};
Expand Down Expand Up @@ -188,13 +190,19 @@ export const setAnimationParams = (time, waveAmplitude) => {
_waveAmplitude = waveAmplitude;
};

export const setGravityScale = (scale) => {
_gravityScale = Math.max(0, scale);
};

export const setContainerKinematics = (kinematics) => {
_containerKinematics = {
..._containerKinematics,
...kinematics,
};
};

const _scaledGravity = () => Vec2.mul(_gravityScale, _gravity);

//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

const _bindUpdateUBO = () => {
Expand Down Expand Up @@ -226,7 +234,8 @@ const _initParams = () => {
let mass = _rho0 * volume0;
let h = 1.02 * _dp;
_kernelRadius = 2*h;
let velLimit = Math.sqrt(2 * Vec2.length(_gravity) * _fluidDomainRadius);
let gravityLength = Math.max(Vec2.length(_scaledGravity()), 1e-4);
let velLimit = Math.sqrt(2 * gravityLength * _fluidDomainRadius);
let speedSound = 3 * velLimit;
_dt = 0.45 * h / velLimit;
let pressB = _rho0 * speedSound * speedSound / 2;
Expand Down Expand Up @@ -389,7 +398,8 @@ const _updateParticles = () => {

_updateParticlesProgram.use();
_posVelWriteFBO.bind();
_gl.uniform2f(_updateParticlesProgram.uniform('g'), _gravity.x, _gravity.y);
const g = _scaledGravity();
_gl.uniform2f(_updateParticlesProgram.uniform('g'), g.x, g.y);
_gl.uniform4f(_updateParticlesProgram.uniform('pointerPosVel'), _pointerPos.x, _pointerPos.y, _pointerVel.x, _pointerVel.y);
_gl.uniform1f(_updateParticlesProgram.uniform('pointerRadius'), 3);
_gl.uniform1f(_updateParticlesProgram.uniform('u_progress'), _progress);
Expand Down