Created
April 6, 2014 01:03
-
-
Save mantissa/10000081 to your computer and use it in GitHub Desktop.
Frustrum Culling with Shaders in OF
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#version 120 | |
uniform sampler2DRect pointsTexture; | |
uniform sampler2DRect resultsTexture; | |
uniform vec4 viewport; | |
uniform float width; | |
uniform mat4 mvMatrix; | |
varying vec4 texCoord0; | |
void main(){ | |
vec3 pos = texture2DRect(pointsTexture, texCoord0.xy).xyz; | |
float d = 1.0f / (mvMatrix[0][3] * pos.x + mvMatrix[1][3] * pos.y + mvMatrix[2][3] * pos.z + mvMatrix[3][3]) ; | |
pos = (mvMatrix * vec4(pos, 1.0f)).yxz; | |
pos = pos * d; | |
vec3 screenPos; | |
screenPos.x = (( pos.x + 1.0f ) / 2.0f ) * viewport.z + viewport.x; | |
screenPos.y = (( 1.0f - pos.y ) / 2.0f ) * viewport.w + viewport.y; | |
screenPos.z = pos.z; | |
if( screenPos.x >= viewport.x && screenPos.x <= viewport.x+viewport.z && screenPos.y >= viewport.y && screenPos.y <= viewport.y+viewport.w ){ | |
gl_FragColor = vec4(screenPos.x, screenPos.y, screenPos.z, 1.0f); | |
}else{ | |
gl_FragColor = vec4(0.0f, 0.0f, 0.0f, 0.5f); | |
} | |
// for debugging | |
//gl_FragColor = vec4(mvMatrix[0].x, mvMatrix[0].y, mvMatrix[0].z, 1.0); | |
//gl_FragColor = vec4(screenPos.x, screenPos.y, screenPos.z, 1.0f); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#version 120 | |
uniform sampler2DRect pointsTexture; | |
uniform vec4 viewport; | |
uniform mat4 mvMatrix; | |
varying vec4 texCoord0; | |
void main(){ | |
texCoord0 = gl_MultiTexCoord0; | |
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "testApp.h" | |
//-------------------------------------------------------------- | |
void testApp::setup(){ | |
frustumShader.load("shaders/FrustrumCulling"); | |
shaderImage.allocate( PT_COUNT, 1, OF_IMAGE_COLOR ); | |
frustumShaderFBO.allocate( PT_COUNT, 1, GL_RGBA32F_ARB ); | |
shaderPix.allocate( PT_COUNT, 1, OF_IMAGE_COLOR_ALPHA ); | |
float * imgPixels = shaderImage.getPixels(); | |
int w = ofGetWidth(); | |
int h = ofGetHeight(); | |
// how many pixels outside of the screen | |
float expandAmt = 400; | |
// how many points back | |
float maxZOffset = 800; | |
for( int i=0; i<PT_COUNT; i++ ){ | |
ofPoint pt; | |
pt.x = ofRandom( -expandAmt, w+expandAmt ); | |
pt.y = ofRandom( -expandAmt, h+expandAmt ); | |
pt.z = ofRandom( 0, -maxZOffset ); | |
int pix = i * 3; | |
imgPixels[ pix ] = pt.x; | |
imgPixels[ pix +1 ] = pt.y; | |
imgPixels[ pix +2 ] = pt.z; | |
testPoints.push_back( pt ); | |
} | |
shaderImage.update(); | |
} | |
//-------------------------------------------------------------- | |
void testApp::update(){ | |
// update the camera based on the mouse position ... | |
float mX = ofGetMouseX(); | |
float mY = ofGetMouseY(); | |
ofPoint lookAt; | |
lookAt.x = ofGetWidth()/2 + ofMap( mX, 0, ofGetWidth(), -300, 300, true); | |
lookAt.y = ofGetHeight()/2 + ofMap( mY, 0, ofGetHeight(), 300, -300, true); | |
lookAt.z = -400; | |
cam.setPosition(ofGetWidth()/2, ofGetHeight()/2, 100); | |
cam.lookAt( lookAt ); | |
cam.setFov( 50 ); | |
} | |
//-------------------------------------------------------------- | |
void testApp::draw(){ | |
bool bDoComparison = false; | |
if( !bDoComparison ){ | |
drawCPUTest(); | |
} else { | |
long start = ofGetElapsedTimeMillis(); | |
drawCPUTest(); | |
long cpuDraw = ofGetElapsedTimeMillis()-start; | |
start = ofGetElapsedTimeMillis(); | |
drawGPUTest(); | |
long gpuDraw = ofGetElapsedTimeMillis()-start; | |
printf("cpu draw: %zd, ", cpuDraw); | |
printf("gpu draw: %zd, diff %zd (%.2f)\n", gpuDraw, cpuDraw-gpuDraw, float(cpuDraw-gpuDraw)/cpuDraw); | |
} | |
ofDrawBitmapStringHighlight( ofToString(ofGetFrameRate(), 2), 20, ofGetHeight()-20 ); | |
} | |
//-------------------------------------------------------------- | |
void testApp::drawCPUTest(){ | |
ofRectangle viewport = ofRectangle(20, 20, ofGetWidth()-40, ofGetHeight()-40 ); | |
ofMatrix4x4 modelViewMat = cam.getModelViewProjectionMatrix(viewport); | |
cam.begin( viewport ); | |
ofSetColor(255); | |
vector<ofPoint>::iterator pIter = testPoints.begin(); | |
while( pIter != testPoints.end() ){ | |
ofVec3f screenPt = (*pIter) * modelViewMat; | |
screenPt.x = ((screenPt.x + 1.0) / 2.0) * viewport.width + viewport.x; | |
screenPt.y = ((1.0 - screenPt.y) / 2.0) * viewport.height + viewport.y; | |
if( viewport.inside(screenPt.x, screenPt.y) ){ | |
ofDrawSphere( (*pIter), 5 ); | |
} | |
pIter++; | |
} | |
cam.end(); | |
bool bShowScreenPts = false; | |
if( bShowScreenPts ){ | |
ofSetColor(255, 0, 0); | |
vector<ofPoint>::iterator pIter = testPoints.begin(); | |
while( pIter != testPoints.end() ){ | |
ofVec3f screenPt = (*pIter) * modelViewMat; | |
screenPt.x = ((screenPt.x + 1.0) / 2.0) * viewport.width + viewport.x; | |
screenPt.y = ((1.0 - screenPt.y) / 2.0) * viewport.height + viewport.y; | |
if( viewport.inside(screenPt.x, screenPt.y) ){ | |
ofCircle(screenPt.x, screenPt.y, 5 ); | |
} | |
pIter++; | |
} | |
} | |
ofSetColor(255, 0, 0); | |
ofNoFill(); | |
ofRect( viewport ); | |
ofFill(); | |
} | |
//-------------------------------------------------------------- | |
void testApp::drawGPUTest(){ | |
ofRectangle viewport = ofRectangle(20, 20, ofGetWidth()-40, ofGetHeight()-40 ); | |
ofMatrix4x4 modelViewMat = cam.getModelViewProjectionMatrix(viewport); | |
frustumShaderFBO.begin(); | |
ofClear(0, 255); | |
frustumShader.begin(); | |
frustumShader.setUniformMatrix4f( "mvMatrix", modelViewMat ); | |
frustumShader.setUniform4f( "viewport", viewport.x, viewport.y, viewport.width, viewport.height ); | |
frustumShader.setUniformTexture( "pointsTexture", shaderImage, 0 ); | |
ofSetColor(255); | |
ofxDrawShaderRect(0, 0, shaderImage.width, shaderImage.height ); | |
frustumShader.end(); | |
frustumShaderFBO.end(); | |
// step 2: get the pix | |
frustumShaderFBO.getTextureReference().bind(); | |
glGetTexImage(frustumShaderFBO.getTextureReference().getTextureData().textureTarget,0,ofGetGlFormat(shaderPix),GL_FLOAT,shaderPix.getPixels()); | |
frustumShaderFBO.getTextureReference().unbind(); | |
float * pix = shaderPix.getPixels(); | |
int nPts = testPoints.size(); | |
cam.begin( viewport ); | |
for(int i=0; i<PT_COUNT; i++){ | |
int pt = i * 4; | |
float w = pix[pt+3]; | |
if( w >= 1.0 ){ | |
ofDrawSphere( testPoints[i], 5 ); | |
} | |
} | |
cam.end(); | |
bool bShowScreenPts = false; | |
if( bShowScreenPts ){ | |
for(int i=0; i<PT_COUNT; i++){ | |
int pt = i * 4; | |
float x = pix[pt]; | |
float y = pix[pt+1]; | |
float w = pix[pt+3]; | |
if( w == 1.0 ){ | |
ofSetColor(255, 0, 0); | |
ofCircle(x, y, 5 ); | |
} | |
} | |
} | |
ofSetColor(255, 0, 0); | |
ofNoFill(); | |
ofRect( viewport ); | |
ofFill(); | |
bool bDrawTextures = false; | |
if( bDrawTextures ){ | |
ofSetColor(255); | |
shaderImage.draw(5, 5, shaderImage.width, 10 ); | |
frustumShaderFBO.draw(5, 20, shaderImage.width, 10 ); | |
} | |
} | |
//-------------------------------------------------------------- | |
void testApp::drawNoTest(){ | |
ofRectangle viewport = ofRectangle(20, 20, ofGetWidth()-40, ofGetHeight()-40 ); | |
cam.begin( viewport ); | |
ofSetColor(255); | |
vector<ofPoint>::iterator pIter = testPoints.begin(); | |
while( pIter != testPoints.end() ){ | |
ofDrawSphere( (*pIter), 5 ); | |
pIter++; | |
} | |
cam.end(); | |
} | |
//-------------------------------------------------------------- | |
void testApp::exit(){ | |
testPoints.clear(); | |
} | |
//-------------------------------------------------------------- | |
void ofxDrawShaderRect(int x, int y, int w, int h){ | |
ofSetColor(255); | |
glBegin(GL_QUADS); | |
glTexCoord2f(0, 0); | |
glVertex2f(0, 0); | |
glTexCoord2f(w, 0); | |
glVertex2f(w, 0); | |
glTexCoord2f(w, h); | |
glVertex2f(w, h); | |
glTexCoord2f(0, h); | |
glVertex2f(0, h); | |
glEnd(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "ofMain.h" | |
#define PT_COUNT 3000 | |
class testApp : public ofBaseApp { | |
public: | |
void setup(); | |
void update(); | |
void draw(); | |
void exit(); | |
void drawCPUTest(); | |
void drawGPUTest(); | |
void drawNoTest(); | |
ofCamera cam; | |
ofShader frustumShader; | |
ofFbo frustumShaderFBO; | |
ofFloatImage shaderImage; | |
ofFloatImage resultsImage; | |
ofFloatPixels shaderPix; | |
vector<ofPoint> testPoints; | |
}; | |
void ofxDrawShaderRect(int x, int y, int w, int h); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment