|
|
|
|
@ -51,7 +51,7 @@ float fabs(float x) |
|
|
|
|
return(x>0 ? x : -x); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#define PI 3.14159 |
|
|
|
|
#define PI 3.14159265359 |
|
|
|
|
#define EULER 2.71828 |
|
|
|
|
#define SQRT2 1.41421 |
|
|
|
|
|
|
|
|
|
@ -346,7 +346,6 @@ GLuint create_fbo(GLuint texture) |
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
|
|
|
|
glBindTexture(GL_TEXTURE_2D, texture); |
|
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); |
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT); |
|
|
|
|
return(fbo); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -389,8 +388,8 @@ void frame_buffer_swap(frame_buffer* buffer) |
|
|
|
|
#define texWidth 512 |
|
|
|
|
#define texHeight 512 |
|
|
|
|
*/ |
|
|
|
|
#define texWidth (256) |
|
|
|
|
#define texHeight (256) |
|
|
|
|
#define texWidth (128) |
|
|
|
|
#define texHeight (128) |
|
|
|
|
|
|
|
|
|
float colorInitData[texWidth][texHeight][4] = {0}; |
|
|
|
|
float velocityInitData[texWidth][texHeight][4] = {0}; |
|
|
|
|
@ -505,6 +504,9 @@ int init(float canvasSize) |
|
|
|
|
|
|
|
|
|
WAJS_SetupCanvas(canvasSize, canvasSize); |
|
|
|
|
|
|
|
|
|
init_color_checker(); |
|
|
|
|
init_velocity_vortex(); |
|
|
|
|
|
|
|
|
|
// init programs
|
|
|
|
|
init_advect(&advectProgram); |
|
|
|
|
init_div(&divProgram); |
|
|
|
|
@ -519,9 +521,9 @@ int init(float canvasSize) |
|
|
|
|
|
|
|
|
|
// init frame buffers
|
|
|
|
|
console_log_fmt("create color buffer"); |
|
|
|
|
init_frame_buffer(&colorBuffer, texWidth, texHeight, TEX_INTERNAL_FORMAT, TEX_FORMAT, TEX_TYPE, 0); |
|
|
|
|
init_frame_buffer(&colorBuffer, texWidth, texHeight, TEX_INTERNAL_FORMAT, TEX_FORMAT, TEX_TYPE, (char*)colorInitData); |
|
|
|
|
console_log_fmt("create velocity buffer"); |
|
|
|
|
init_frame_buffer(&velocityBuffer, texWidth, texHeight, TEX_INTERNAL_FORMAT, TEX_FORMAT, TEX_TYPE, 0); |
|
|
|
|
init_frame_buffer(&velocityBuffer, texWidth, texHeight, TEX_INTERNAL_FORMAT, TEX_FORMAT, TEX_TYPE, (char*)velocityInitData); |
|
|
|
|
|
|
|
|
|
int gridFactor = 1; |
|
|
|
|
for(int i=0; i<MULTIGRID_COUNT; i++) |
|
|
|
|
@ -563,57 +565,7 @@ int init(float canvasSize) |
|
|
|
|
return(0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void apply_splat(float splatPosX, float splatPosY, float splatVelX, float splatVelY, float r, float g, float b, bool randomize) |
|
|
|
|
{ |
|
|
|
|
glUseProgram(splatProgram.prog); |
|
|
|
|
|
|
|
|
|
if(randomize) |
|
|
|
|
{ |
|
|
|
|
glUniform1f(splatProgram.randomize, 1.); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
glUniform1f(splatProgram.randomize, 0.); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// force
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, velocityBuffer.fbos[1]); |
|
|
|
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE0); |
|
|
|
|
glBindTexture(GL_TEXTURE_2D, velocityBuffer.textures[0]); |
|
|
|
|
glUniform1i(splatProgram.src, 0); |
|
|
|
|
|
|
|
|
|
glUniform2f(splatProgram.splatPos, splatPosX, splatPosY); |
|
|
|
|
glUniform3f(splatProgram.splatColor, splatVelX, splatVelY, 0); |
|
|
|
|
glUniform1f(splatProgram.additive, 1); |
|
|
|
|
glUniform1f(splatProgram.blending, 0); |
|
|
|
|
|
|
|
|
|
glUniform1f(splatProgram.radius, 0.01); |
|
|
|
|
|
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 6); |
|
|
|
|
|
|
|
|
|
frame_buffer_swap(&velocityBuffer); |
|
|
|
|
|
|
|
|
|
// dye
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, colorBuffer.fbos[1]); |
|
|
|
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE0); |
|
|
|
|
glBindTexture(GL_TEXTURE_2D, colorBuffer.textures[0]); |
|
|
|
|
glUniform1i(splatProgram.src, 0); |
|
|
|
|
|
|
|
|
|
glUniform2f(splatProgram.splatPos, splatPosX, splatPosY); |
|
|
|
|
glUniform3f(splatProgram.splatColor, r, g, b); |
|
|
|
|
glUniform1f(splatProgram.additive, 0); |
|
|
|
|
glUniform1f(splatProgram.blending, 1); |
|
|
|
|
glUniform1f(splatProgram.radius, 0.01); |
|
|
|
|
|
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 6); |
|
|
|
|
|
|
|
|
|
frame_buffer_swap(&colorBuffer); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void multigrid_smooth(frame_buffer* x, frame_buffer* b, float invGridSize, int iterationCount) |
|
|
|
|
void jacobi_solve(frame_buffer* x, frame_buffer* b, float invGridSize, int iterationCount) |
|
|
|
|
{ |
|
|
|
|
glUseProgram(jacobiProgram.prog); |
|
|
|
|
|
|
|
|
|
@ -635,52 +587,6 @@ void multigrid_smooth(frame_buffer* x, frame_buffer* b, float invGridSize, int i |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void multigrid_coarsen_residual(frame_buffer* output, frame_buffer* x, frame_buffer* b, float invFineGridSize) |
|
|
|
|
{ |
|
|
|
|
//NOTE: compute residual and downsample to coarser grid, put result in coarser buffer
|
|
|
|
|
glUseProgram(multigridRestrictResidualProgram.prog); |
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, output->fbos[1]); |
|
|
|
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE0); |
|
|
|
|
glBindTexture(GL_TEXTURE_2D, x->textures[0]); |
|
|
|
|
glUniform1i(multigridRestrictResidualProgram.xTex, 0); |
|
|
|
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE1); |
|
|
|
|
glBindTexture(GL_TEXTURE_2D, b->textures[0]); |
|
|
|
|
glUniform1i(multigridRestrictResidualProgram.bTex, 1); |
|
|
|
|
|
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 6); |
|
|
|
|
|
|
|
|
|
frame_buffer_swap(output); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void multigrid_prolongate_and_correct(frame_buffer* x, frame_buffer* error, float invFineGridSize) |
|
|
|
|
{ |
|
|
|
|
//NOTE: correct finer pressure
|
|
|
|
|
glUseProgram(multigridCorrectProgram.prog); |
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, x->fbos[1]); |
|
|
|
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE0); |
|
|
|
|
glBindTexture(GL_TEXTURE_2D, x->textures[0]); |
|
|
|
|
glUniform1i(multigridCorrectProgram.src, 0); |
|
|
|
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE1); |
|
|
|
|
glBindTexture(GL_TEXTURE_2D, error->textures[0]); |
|
|
|
|
glUniform1i(multigridCorrectProgram.error, 1); |
|
|
|
|
|
|
|
|
|
glUniform1f(multigridCorrectProgram.invGridSize, invFineGridSize); |
|
|
|
|
|
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 6); |
|
|
|
|
|
|
|
|
|
frame_buffer_swap(x); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void multigrid_clear(frame_buffer* error) |
|
|
|
|
{ |
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, error->fbos[0]); |
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// This function is called by loader.js every frame
|
|
|
|
|
void WAFNDraw() |
|
|
|
|
{ |
|
|
|
|
@ -711,81 +617,6 @@ void WAFNDraw() |
|
|
|
|
|
|
|
|
|
frame_buffer_swap(&velocityBuffer); |
|
|
|
|
|
|
|
|
|
//NOTE: apply force and dye
|
|
|
|
|
/*
|
|
|
|
|
if(mouseInput.down && (mouseInput.deltaX || mouseInput.deltaY)) |
|
|
|
|
{ |
|
|
|
|
float canvasWidth = canvas_width(); |
|
|
|
|
float canvasHeight = canvas_height(); |
|
|
|
|
|
|
|
|
|
float splatPosX = mouseInput.x/canvasWidth; |
|
|
|
|
float splatPosY = 1 - mouseInput.y/canvasHeight; |
|
|
|
|
|
|
|
|
|
float splatVelX = 5000.*DELTA*mouseInput.deltaX/canvasWidth; |
|
|
|
|
float splatVelY = -5000.*DELTA*mouseInput.deltaY/canvasWidth; |
|
|
|
|
|
|
|
|
|
float intensity = 100*sqrtf(square(mouseInput.deltaX/canvasWidth) + square(mouseInput.deltaY/canvasHeight)); |
|
|
|
|
|
|
|
|
|
float r = intensity * (sinf(2*PI*0.1*t) + 1); |
|
|
|
|
float g = intensity * (cosf(2*PI*0.1/EULER*t + 654) + 1); |
|
|
|
|
float b = intensity * (sinf(2*PI*0.1/SQRT2*t + 937) + 1); |
|
|
|
|
|
|
|
|
|
apply_splat(splatPosX, splatPosY, splatVelX, splatVelY, r, g, b, true); |
|
|
|
|
|
|
|
|
|
mouseInput.deltaX = 0; |
|
|
|
|
mouseInput.deltaY = 0; |
|
|
|
|
} |
|
|
|
|
*/ |
|
|
|
|
//DEBUG
|
|
|
|
|
/*
|
|
|
|
|
if((int)(frameT*3/2.) % 9 == 0) |
|
|
|
|
{ |
|
|
|
|
float dirX = 0.2*cosf(2*3.141516*frameT*7.26); |
|
|
|
|
float dirY = 0.3+0.1*sinf(frameT); |
|
|
|
|
apply_splat(0.5, 0., dirX, dirY, 1.5, 1., 0.1); |
|
|
|
|
} |
|
|
|
|
//*/
|
|
|
|
|
static bool splatTrig = false; |
|
|
|
|
static bool splat = false; |
|
|
|
|
static float splatStart = 0; |
|
|
|
|
static int splatDir = 0; |
|
|
|
|
|
|
|
|
|
if(resetCmd) |
|
|
|
|
{ |
|
|
|
|
splat = true; |
|
|
|
|
splatStart = frameT; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(splat) |
|
|
|
|
{ |
|
|
|
|
if(frameT - splatStart >= 0.5) |
|
|
|
|
{ |
|
|
|
|
splat = false; |
|
|
|
|
splatDir++; |
|
|
|
|
splatDir = splatDir % 3; |
|
|
|
|
} |
|
|
|
|
float dirX = 0; |
|
|
|
|
float dirY = 0; |
|
|
|
|
if(splatDir == 0) |
|
|
|
|
{ |
|
|
|
|
dirX = 0; |
|
|
|
|
dirY = 0.3; |
|
|
|
|
} |
|
|
|
|
if(splatDir == 1) |
|
|
|
|
{ |
|
|
|
|
dirX = 0.3; |
|
|
|
|
dirY = 0; |
|
|
|
|
} |
|
|
|
|
if(splatDir == 2) |
|
|
|
|
{ |
|
|
|
|
dirX = 0.2121; |
|
|
|
|
dirY = 0.2121; |
|
|
|
|
} |
|
|
|
|
apply_splat(0.5, 0.5, dirX, dirY, 1.5, 1., 0.1, false); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
resetCmd = false; |
|
|
|
|
|
|
|
|
|
//NOTE: compute divergence of advected velocity
|
|
|
|
|
glUseProgram(divProgram.prog); |
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, divBuffer[0].fbos[1]); |
|
|
|
|
@ -799,48 +630,10 @@ void WAFNDraw() |
|
|
|
|
frame_buffer_swap(&divBuffer[0]); |
|
|
|
|
|
|
|
|
|
//NOTE: compute pressure
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, pressureBuffer[0].fbos[1]); |
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT); |
|
|
|
|
|
|
|
|
|
#if 1 |
|
|
|
|
multigrid_clear(&pressureBuffer[0]); |
|
|
|
|
multigrid_smooth(&pressureBuffer[0], &divBuffer[0], INV_GRID_SIZE, 2000); |
|
|
|
|
#else |
|
|
|
|
//*
|
|
|
|
|
multigrid_clear(&pressureBuffer[0]); |
|
|
|
|
|
|
|
|
|
for(int i=0; i<4; i++) |
|
|
|
|
{ |
|
|
|
|
multigrid_smooth(&pressureBuffer[0], &divBuffer[0], INV_GRID_SIZE, 2); |
|
|
|
|
//*
|
|
|
|
|
multigrid_coarsen_residual(&divBuffer[1], &pressureBuffer[0], &divBuffer[0], INV_GRID_SIZE); |
|
|
|
|
|
|
|
|
|
multigrid_clear(&pressureBuffer[1]); |
|
|
|
|
multigrid_smooth(&pressureBuffer[1], &divBuffer[1], 2*INV_GRID_SIZE, 2); |
|
|
|
|
multigrid_coarsen_residual(&divBuffer[2], &pressureBuffer[1], &divBuffer[1], 2*INV_GRID_SIZE); |
|
|
|
|
|
|
|
|
|
multigrid_clear(&pressureBuffer[2]); |
|
|
|
|
multigrid_smooth(&pressureBuffer[2], &divBuffer[2], 4*INV_GRID_SIZE, 60); |
|
|
|
|
|
|
|
|
|
multigrid_prolongate_and_correct(&pressureBuffer[1], &pressureBuffer[2], 2*INV_GRID_SIZE); |
|
|
|
|
multigrid_smooth(&pressureBuffer[1], &divBuffer[1], 2*INV_GRID_SIZE, 8); |
|
|
|
|
|
|
|
|
|
multigrid_prolongate_and_correct(&pressureBuffer[0], &pressureBuffer[1], INV_GRID_SIZE); |
|
|
|
|
//*/
|
|
|
|
|
multigrid_smooth(&pressureBuffer[0], &divBuffer[0], INV_GRID_SIZE, 4); |
|
|
|
|
} |
|
|
|
|
/*/
|
|
|
|
|
multigrid_clear(&pressureBuffer[0]); |
|
|
|
|
multigrid_smooth(&pressureBuffer[0], &pressureBuffer[0], &divBuffer[0], INV_GRID_SIZE, 10); |
|
|
|
|
|
|
|
|
|
multigrid_coarsen_residual(&divBuffer[1], &pressureBuffer[0], &divBuffer[0], INV_GRID_SIZE); |
|
|
|
|
|
|
|
|
|
multigrid_clear(&pressureBuffer[1]); |
|
|
|
|
multigrid_smooth(&pressureBuffer[1], &pressureBuffer[1], &divBuffer[1], 2*INV_GRID_SIZE, 400); |
|
|
|
|
|
|
|
|
|
multigrid_prolongate_and_correct(&pressureBuffer[0], &pressureBuffer[0], &pressureBuffer[1], INV_GRID_SIZE); |
|
|
|
|
|
|
|
|
|
multigrid_smooth(&pressureBuffer[0], &pressureBuffer[0], &divBuffer[0], INV_GRID_SIZE, 10); |
|
|
|
|
//*/
|
|
|
|
|
#endif |
|
|
|
|
jacobi_solve(&pressureBuffer[0], &divBuffer[0], INV_GRID_SIZE, 20000); |
|
|
|
|
|
|
|
|
|
//NOTE: subtract pressure gradient to advected velocity
|
|
|
|
|
glUseProgram(subtractProgram.prog); |
|
|
|
|
@ -902,7 +695,6 @@ void WAFNDraw() |
|
|
|
|
|
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 6); |
|
|
|
|
/*/
|
|
|
|
|
|
|
|
|
|
//NOTE: recompute divergence of (corrected) velocity
|
|
|
|
|
glUseProgram(divProgram.prog); |
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, divBuffer[0].fbos[1]); |
|
|
|
|
@ -915,7 +707,6 @@ void WAFNDraw() |
|
|
|
|
|
|
|
|
|
frame_buffer_swap(&divBuffer[0]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//NOTE: Blit divergence to screen
|
|
|
|
|
glViewport(0, 0, canvas_width(), canvas_height()); |
|
|
|
|
glUseProgram(blitDivProgram.prog); |
|
|
|
|
|