Hi,
I’ve been trying to implement this paper in GLSL in order to do 2D n-body particle collision.
Like this paper says, by using 2 different FBOs, one (SPATIAL TEX) has particle’s location data as a form of texture in the order of texture coordinates, and the other (INDEXED TEX) has texture coordinates date as a form of frame buffer where I draw vertices which has texCoord as a color of itself so that I can get nearest neighbors by looking up SPATIAL TEX and fetch the neighbors’ coordinates from there and use them in INDEXED TEX for calculating forces or such.
I’m not 100% sure whether this would work well but seems promising and easier than other ways using complex space partitioning and sorting algorithm.
So, for the first step, I was thinking, if I draw a 2D grid of vertices which has normalized position values into a frame-buffer and then if I could access vertices’ value in the frame-buffer by using vertices’ position values as a texture coordinates then this method of the paper would technically work. Right?
However it seems not working, and it seems the values are slightly off every frame as I ping-ponging them. It’s really hard to explain in words but you will know when you see the code. Following is my entire code,
#include "cinder/app/App.h"
#include "cinder/app/RendererGl.h"
#include "cinder/gl/gl.h"
using namespace ci;
using namespace ci::app;
using namespace std;
class pixelPerfectTestApp : public App {
public:
static void prepareSettings( Settings *settings );
void setup() override;
void update() override;
void draw() override;
CameraOrtho m_cam;
gl::VaoRef vao_p_layout;
gl::VboRef vbo_p_loc;
gl::VboRef vbo_p_coord;
gl::FboRef fbo_p_indexed_loc[2];
gl::GlslProgRef shdr_p_indexed_loc;
const uint32_t num_p = 256*256;
const uint32_t p_buff_size = sqrt(num_p);
int w, h;
bool is_init = false;
string p_indexed_vert =
CI_GLSL( 150,
in vec4 p_position;
in vec2 p_texCoord0;
uniform mat4 ciModelViewProjection;
out vec2 texCoord;
void main(){
texCoord = p_texCoord0;
gl_Position = ciModelViewProjection * p_position;
});
string p_indexed_loc_frag =
CI_GLSL( 150,
in vec2 texCoord;
uniform sampler2D src_tex;
uniform bool is_init;
uniform vec2 res;
out vec4 fragColor;
void main(){
vec2 pp_loc = texture(src_tex, texCoord).rg;
vec2 loc = is_init ? pp_loc : texCoord;
fragColor = vec4(loc,1,1);
});
};
void pixelPerfectTestApp::setup()
{
// gl::enable(GL_TEXTURE_RECTANGLE_ARB);
m_cam.setOrtho(0, 1, 0, 1, -1, 1);
w = getWindowWidth();
h = getWindowHeight();
std::vector<vec4> _p(num_p);
std::vector<vec2> _coord(num_p);
for(uint32_t y = 0; y < p_buff_size; y++)
for(uint32_t x = 0; x < p_buff_size; x++){
int _i = x + y * p_buff_size;
// custom loc&coord to match those identically
// +.5f pixel perfect
// - https://stackoverflow.com/a/8885105
// for texel fetching in tex2d
// - https://gamedev.stackexchange.com/a/90566
_p[_i] = vec4(
((x +.5f)/(float)p_buff_size),
((y +.5f)/(float)p_buff_size),
0.f, 1.f);
_coord[_i] = vec2(((x +.5f)/(float)p_buff_size),
((y +.5f)/(float)p_buff_size));
// cout << _i << "/" << num_p << " : " << _p[_i] << endl;
}
vbo_p_loc = gl::Vbo::create( GL_ARRAY_BUFFER, _p.size() * sizeof(vec4), _p.data(), GL_STATIC_DRAW );
vbo_p_coord = gl::Vbo::create( GL_ARRAY_BUFFER, _coord.size() * sizeof(vec2), _coord.data(), GL_STATIC_DRAW );
vao_p_layout = ci::gl::Vao::create();
{
gl::ScopedVao vao(vao_p_layout);
{
gl::ScopedBuffer vbo(vbo_p_loc);
ci::gl::vertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
ci::gl::enableVertexAttribArray(0);
}
{
gl::ScopedBuffer vbo(vbo_p_coord);
ci::gl::vertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
ci::gl::enableVertexAttribArray(1);
}
}
shdr_p_indexed_loc =
gl::GlslProg::create(gl::GlslProg::Format()
.vertex(p_indexed_vert)
.fragment(p_indexed_loc_frag)
.attribLocation("p_position", 0)
.attribLocation("p_texCoord0", 1)
);
gl::Fbo::Format fbo_format;
fbo_format
.setColorTextureFormat(gl::Texture::Format()
// .target(GL_TEXTURE_RECTANGLE_ARB)
.target(GL_TEXTURE_2D)
.minFilter(GL_NEAREST)
.magFilter(GL_NEAREST)
// .internalFormat(GL_RGB32F_ARB)
.internalFormat(GL_RGBA32F)
.wrap(GL_CLAMP_TO_EDGE)
);
for(int i = 0; i < 2; i++){
fbo_p_indexed_loc[i] = gl::Fbo::create( w, h, fbo_format.colorTexture() );
}
}
void pixelPerfectTestApp::update()
{
{
gl::ScopedFramebuffer fbo_scope(fbo_p_indexed_loc[0]);
{
gl::clear(Color(.0f,.0f,.0f));
gl::ScopedViewport viewportScope( ivec2( 0 ), fbo_p_indexed_loc[0]->getSize() );
gl::pushMatrices();
gl::setMatrices( m_cam );
gl::ScopedGlslProg shdr_scope(shdr_p_indexed_loc);
{
gl::ScopedTextureBind tex0(fbo_p_indexed_loc[1]->getColorTexture(), 1);
shdr_p_indexed_loc->uniform("src_tex", 1);
shdr_p_indexed_loc->uniform("is_init", is_init);
gl::ScopedVao vao_scope(vao_p_layout);
gl::context()->setDefaultShaderVars();
gl::drawArrays(GL_POINTS, 0, num_p);
}
gl::popMatrices();
}
}
std::swap(fbo_p_indexed_loc[0], fbo_p_indexed_loc[1]);
is_init = true;
}
void pixelPerfectTestApp::draw()
{
gl::setMatricesWindow( getWindowSize() );
gl::clear(Color(0, 0, 0));
gl::draw(fbo_p_indexed_loc[1]->getColorTexture(), toPoints( fbo_p_indexed_loc[1]->getColorTexture()->getBounds() ) );
}
void pixelPerfectTestApp::prepareSettings( Settings* settings ){
settings->setWindowSize( 850, 850 );
}
CINDER_APP( pixelPerfectTestApp, RendererGl, pixelPerfectTestApp::prepareSettings )
and what’s happening here at the beginning
The colors are supposed to stay same (representing coordinates) but it is changed as frame goes by
Based on this, I assume the problem would be in a precision in texture coordinates. I have tried to do the same thing with Rectangular ARB Texture but I couldn’t make it.
I’m not even sure whether I’m suspecting a right point or not. Any insight or direction would be very appreciated!
Thanks!
P.S. I’m self-taught so if there’s something looked absurd in my code then please don’t hesitate to point it out, I would really appreciated.