Apply consistent code formatting across the repo. Add clang-format and pre-commit hooks.

This commit is contained in:
Rob Armstrong
2025-03-27 10:30:07 -07:00
parent 2cd58fbc9a
commit ceab6e8bcc
782 changed files with 107230 additions and 106548 deletions

View File

@@ -28,216 +28,229 @@
#include <stdlib.h>
#define HELPERGL_EXTERN_GL_FUNC_IMPLEMENTATION
#include <helper_gl.h>
#include "GLSLProgram.h"
GLSLProgram::GLSLProgram(const char *vsource, const char *fsource) {
mProg = compileProgram(vsource, 0, fsource);
GLSLProgram::GLSLProgram(const char *vsource, const char *fsource) { mProg = compileProgram(vsource, 0, fsource); }
GLSLProgram::GLSLProgram(const char *vsource, const char *gsource, const char *fsource, GLenum gsInput, GLenum gsOutput)
{
mProg = compileProgram(vsource, gsource, fsource, gsInput, gsOutput);
}
GLSLProgram::GLSLProgram(const char *vsource, const char *gsource,
const char *fsource, GLenum gsInput, GLenum gsOutput) {
mProg = compileProgram(vsource, gsource, fsource, gsInput, gsOutput);
}
GLSLProgram::~GLSLProgram() {
if (mProg) {
glDeleteProgram(mProg);
}
GLSLProgram::~GLSLProgram()
{
if (mProg) {
glDeleteProgram(mProg);
}
}
void GLSLProgram::enable() { glUseProgram(mProg); }
void GLSLProgram::disable() { glUseProgram(0); }
void GLSLProgram::setUniform1f(const char *name, float value) {
GLint loc = glGetUniformLocation(mProg, name);
void GLSLProgram::setUniform1f(const char *name, float value)
{
GLint loc = glGetUniformLocation(mProg, name);
if (loc >= 0) {
glUniform1f(loc, value);
} else {
if (loc >= 0) {
glUniform1f(loc, value);
}
else {
#if _DEBUG
fprintf(stderr, "Error setting parameter '%s'\n", name);
fprintf(stderr, "Error setting parameter '%s'\n", name);
#endif
}
}
}
void GLSLProgram::setUniform2f(const char *name, float x, float y) {
GLint loc = glGetUniformLocation(mProg, name);
void GLSLProgram::setUniform2f(const char *name, float x, float y)
{
GLint loc = glGetUniformLocation(mProg, name);
if (loc >= 0) {
glUniform2f(loc, x, y);
} else {
if (loc >= 0) {
glUniform2f(loc, x, y);
}
else {
#if _DEBUG
fprintf(stderr, "Error setting parameter '%s'\n", name);
fprintf(stderr, "Error setting parameter '%s'\n", name);
#endif
}
}
}
void GLSLProgram::setUniform3f(const char *name, float x, float y, float z) {
GLint loc = glGetUniformLocation(mProg, name);
void GLSLProgram::setUniform3f(const char *name, float x, float y, float z)
{
GLint loc = glGetUniformLocation(mProg, name);
if (loc >= 0) {
glUniform3f(loc, x, y, z);
} else {
if (loc >= 0) {
glUniform3f(loc, x, y, z);
}
else {
#if _DEBUG
fprintf(stderr, "Error setting parameter '%s'\n", name);
fprintf(stderr, "Error setting parameter '%s'\n", name);
#endif
}
}
}
void GLSLProgram::setUniform4f(const char *name, float x, float y, float z,
float w) {
GLint loc = glGetUniformLocation(mProg, name);
void GLSLProgram::setUniform4f(const char *name, float x, float y, float z, float w)
{
GLint loc = glGetUniformLocation(mProg, name);
if (loc >= 0) {
glUniform4f(loc, x, y, z, w);
} else {
if (loc >= 0) {
glUniform4f(loc, x, y, z, w);
}
else {
#if _DEBUG
fprintf(stderr, "Error setting parameter '%s'\n", name);
fprintf(stderr, "Error setting parameter '%s'\n", name);
#endif
}
}
}
void GLSLProgram::setUniformMatrix4fv(const GLchar *name, GLfloat *m,
bool transpose) {
GLint loc = glGetUniformLocation(mProg, name);
void GLSLProgram::setUniformMatrix4fv(const GLchar *name, GLfloat *m, bool transpose)
{
GLint loc = glGetUniformLocation(mProg, name);
if (loc >= 0) {
glUniformMatrix4fv(loc, 1, transpose, m);
} else {
if (loc >= 0) {
glUniformMatrix4fv(loc, 1, transpose, m);
}
else {
#if _DEBUG
fprintf(stderr, "Error setting parameter '%s'\n", name);
fprintf(stderr, "Error setting parameter '%s'\n", name);
#endif
}
}
}
void GLSLProgram::setUniformfv(const GLchar *name, GLfloat *v, int elementSize,
int count) {
GLint loc = glGetUniformLocation(mProg, name);
void GLSLProgram::setUniformfv(const GLchar *name, GLfloat *v, int elementSize, int count)
{
GLint loc = glGetUniformLocation(mProg, name);
if (loc == -1) {
if (loc == -1) {
#ifdef _DEBUG
fprintf(stderr, "Error setting parameter '%s'\n", name);
fprintf(stderr, "Error setting parameter '%s'\n", name);
#endif
return;
}
switch (elementSize) {
case 1:
glUniform1fv(loc, count, v);
break;
case 2:
glUniform2fv(loc, count, v);
break;
case 3:
glUniform3fv(loc, count, v);
break;
case 4:
glUniform4fv(loc, count, v);
break;
}
}
void GLSLProgram::bindTexture(const char *name, GLuint tex, GLenum target,
GLint unit) {
GLint loc = glGetUniformLocation(mProg, name);
if (loc >= 0) {
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(target, tex);
glUseProgram(mProg);
glUniform1i(loc, unit);
glActiveTexture(GL_TEXTURE0);
} else {
#if _DEBUG
fprintf(stderr, "Error binding texture '%s'\n", name);
#endif
}
}
GLuint GLSLProgram::checkCompileStatus(GLuint shader, GLint *status) {
glGetShaderiv(shader, GL_COMPILE_STATUS, status);
if (!(*status)) {
char log[2048];
int len;
glGetShaderInfoLog(shader, 2048, (GLsizei *)&len, log);
printf("Error: shader(%04d), Info log: %s\n", (int)shader, log);
glDeleteShader(shader);
return 0;
}
return 1;
}
GLuint GLSLProgram::compileProgram(const char *vsource, const char *gsource,
const char *fsource, GLenum gsInput,
GLenum gsOutput) {
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
GLint compiled = 0;
glShaderSource(vertexShader, 1, &vsource, 0);
glShaderSource(fragmentShader, 1, &fsource, 0);
glCompileShader(vertexShader);
if (checkCompileStatus(vertexShader, &compiled) == 0) {
printf("<compileProgram compilation error with vertexShader>:\n");
printf("%s\n", vsource);
return 0;
}
glCompileShader(fragmentShader);
if (checkCompileStatus(fragmentShader, &compiled) == 0) {
printf("<compileProgram compilation error with fragmentShader>:\n");
printf("%s\n", fsource);
return 0;
}
GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
if (gsource) {
GLuint geomShader = glCreateShader(GL_GEOMETRY_SHADER_EXT);
glShaderSource(geomShader, 1, &gsource, 0);
glCompileShader(geomShader);
glGetShaderiv(geomShader, GL_COMPILE_STATUS, (GLint *)&compiled);
if (checkCompileStatus(geomShader, &compiled) == 0) {
printf("<compileProgram compilation error with geomShader>:\n");
printf("%s\n", gsource);
return 0;
return;
}
glAttachShader(program, geomShader);
switch (elementSize) {
case 1:
glUniform1fv(loc, count, v);
break;
glProgramParameteriEXT(program, GL_GEOMETRY_INPUT_TYPE_EXT, gsInput);
glProgramParameteriEXT(program, GL_GEOMETRY_OUTPUT_TYPE_EXT, gsOutput);
glProgramParameteriEXT(program, GL_GEOMETRY_VERTICES_OUT_EXT, 4);
}
case 2:
glUniform2fv(loc, count, v);
break;
glLinkProgram(program);
case 3:
glUniform3fv(loc, count, v);
break;
// check if program linked
GLint success = 0;
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
char temp[1024];
glGetProgramInfoLog(program, 1024, 0, temp);
fprintf(stderr, "Failed to link program:\n%s\n", temp);
glDeleteProgram(program);
program = 0;
exit(EXIT_FAILURE);
}
return program;
case 4:
glUniform4fv(loc, count, v);
break;
}
}
void GLSLProgram::bindTexture(const char *name, GLuint tex, GLenum target, GLint unit)
{
GLint loc = glGetUniformLocation(mProg, name);
if (loc >= 0) {
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(target, tex);
glUseProgram(mProg);
glUniform1i(loc, unit);
glActiveTexture(GL_TEXTURE0);
}
else {
#if _DEBUG
fprintf(stderr, "Error binding texture '%s'\n", name);
#endif
}
}
GLuint GLSLProgram::checkCompileStatus(GLuint shader, GLint *status)
{
glGetShaderiv(shader, GL_COMPILE_STATUS, status);
if (!(*status)) {
char log[2048];
int len;
glGetShaderInfoLog(shader, 2048, (GLsizei *)&len, log);
printf("Error: shader(%04d), Info log: %s\n", (int)shader, log);
glDeleteShader(shader);
return 0;
}
return 1;
}
GLuint GLSLProgram::compileProgram(const char *vsource,
const char *gsource,
const char *fsource,
GLenum gsInput,
GLenum gsOutput)
{
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
GLint compiled = 0;
glShaderSource(vertexShader, 1, &vsource, 0);
glShaderSource(fragmentShader, 1, &fsource, 0);
glCompileShader(vertexShader);
if (checkCompileStatus(vertexShader, &compiled) == 0) {
printf("<compileProgram compilation error with vertexShader>:\n");
printf("%s\n", vsource);
return 0;
}
glCompileShader(fragmentShader);
if (checkCompileStatus(fragmentShader, &compiled) == 0) {
printf("<compileProgram compilation error with fragmentShader>:\n");
printf("%s\n", fsource);
return 0;
}
GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
if (gsource) {
GLuint geomShader = glCreateShader(GL_GEOMETRY_SHADER_EXT);
glShaderSource(geomShader, 1, &gsource, 0);
glCompileShader(geomShader);
glGetShaderiv(geomShader, GL_COMPILE_STATUS, (GLint *)&compiled);
if (checkCompileStatus(geomShader, &compiled) == 0) {
printf("<compileProgram compilation error with geomShader>:\n");
printf("%s\n", gsource);
return 0;
}
glAttachShader(program, geomShader);
glProgramParameteriEXT(program, GL_GEOMETRY_INPUT_TYPE_EXT, gsInput);
glProgramParameteriEXT(program, GL_GEOMETRY_OUTPUT_TYPE_EXT, gsOutput);
glProgramParameteriEXT(program, GL_GEOMETRY_VERTICES_OUT_EXT, 4);
}
glLinkProgram(program);
// check if program linked
GLint success = 0;
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
char temp[1024];
glGetProgramInfoLog(program, 1024, 0, temp);
fprintf(stderr, "Failed to link program:\n%s\n", temp);
glDeleteProgram(program);
program = 0;
exit(EXIT_FAILURE);
}
return program;
}

View File

@@ -32,35 +32,40 @@
#include <stdio.h>
class GLSLProgram {
public:
// construct program from strings
GLSLProgram(const char *vsource, const char *fsource);
GLSLProgram(const char *vsource, const char *gsource, const char *fsource,
GLenum gsInput = GL_POINTS, GLenum gsOutput = GL_TRIANGLE_STRIP);
~GLSLProgram();
class GLSLProgram
{
public:
// construct program from strings
GLSLProgram(const char *vsource, const char *fsource);
GLSLProgram(const char *vsource,
const char *gsource,
const char *fsource,
GLenum gsInput = GL_POINTS,
GLenum gsOutput = GL_TRIANGLE_STRIP);
~GLSLProgram();
void enable();
void disable();
void enable();
void disable();
void setUniform1f(const GLchar *name, GLfloat x);
void setUniform2f(const GLchar *name, GLfloat x, GLfloat y);
void setUniform3f(const char *name, float x, float y, float z);
void setUniform4f(const char *name, float x, float y, float z, float w);
void setUniformfv(const GLchar *name, GLfloat *v, int elementSize,
int count = 1);
void setUniformMatrix4fv(const GLchar *name, GLfloat *m, bool transpose);
void setUniform1f(const GLchar *name, GLfloat x);
void setUniform2f(const GLchar *name, GLfloat x, GLfloat y);
void setUniform3f(const char *name, float x, float y, float z);
void setUniform4f(const char *name, float x, float y, float z, float w);
void setUniformfv(const GLchar *name, GLfloat *v, int elementSize, int count = 1);
void setUniformMatrix4fv(const GLchar *name, GLfloat *m, bool transpose);
void bindTexture(const char *name, GLuint tex, GLenum target, GLint unit);
void bindTexture(const char *name, GLuint tex, GLenum target, GLint unit);
inline GLuint getProgId() { return mProg; }
inline GLuint getProgId() { return mProg; }
private:
GLuint checkCompileStatus(GLuint shader, GLint *status);
GLuint compileProgram(const char *vsource, const char *gsource,
const char *fsource, GLenum gsInput = GL_POINTS,
GLenum gsOutput = GL_TRIANGLE_STRIP);
GLuint mProg;
private:
GLuint checkCompileStatus(GLuint shader, GLint *status);
GLuint compileProgram(const char *vsource,
const char *gsource,
const char *fsource,
GLenum gsInput = GL_POINTS,
GLenum gsOutput = GL_TRIANGLE_STRIP);
GLuint mProg;
};
#endif

View File

@@ -29,266 +29,258 @@
Class to represent an array in GPU and CPU memory
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#define HELPERGL_EXTERN_GL_FUNC_IMPLEMENTATION
#include <helper_gl.h>
#include <cuda_runtime.h>
#include <cuda_gl_interop.h>
#include <cuda_runtime.h>
#include <helper_cuda.h>
#include <helper_gl.h>
template <class T>
class GpuArray {
public:
GpuArray();
~GpuArray();
template <class T> class GpuArray
{
public:
GpuArray();
~GpuArray();
enum Direction {
HOST_TO_DEVICE,
DEVICE_TO_HOST,
};
enum Direction {
HOST_TO_DEVICE,
DEVICE_TO_HOST,
};
// allocate and free
void alloc(size_t size, bool vbo = false, bool doubleBuffer = false,
bool useElementArray = false);
void free();
// allocate and free
void alloc(size_t size, bool vbo = false, bool doubleBuffer = false, bool useElementArray = false);
void free();
// swap buffers for double buffering
void swap();
// swap buffers for double buffering
void swap();
// when using vbo, must map before getting device ptr
void map();
void unmap();
// when using vbo, must map before getting device ptr
void map();
void unmap();
void copy(Direction dir, uint start = 0, uint count = 0);
void memset(T value, uint start = 0, uint count = 0);
void copy(Direction dir, uint start = 0, uint count = 0);
void memset(T value, uint start = 0, uint count = 0);
T *getDevicePtr() { return m_dptr[m_currentRead]; }
GLuint getVbo() { return m_vbo[m_currentRead]; }
T *getDevicePtr() { return m_dptr[m_currentRead]; }
GLuint getVbo() { return m_vbo[m_currentRead]; }
T *getDeviceWritePtr() { return m_dptr[m_currentWrite]; }
GLuint getWriteVbo() { return m_vbo[m_currentWrite]; }
T *getDeviceWritePtr() { return m_dptr[m_currentWrite]; }
GLuint getWriteVbo() { return m_vbo[m_currentWrite]; }
T *getHostPtr() { return m_hptr; }
T *getHostPtr() { return m_hptr; }
size_t getSize() const { return m_size; }
size_t getSize() const { return m_size; }
private:
GLuint createVbo(size_t size, bool useElementArray);
private:
GLuint createVbo(size_t size, bool useElementArray);
void allocDevice();
void allocVbo(bool useElementArray);
void allocHost();
void allocDevice();
void allocVbo(bool useElementArray);
void allocHost();
void freeDevice();
void freeVbo();
void freeHost();
void freeDevice();
void freeVbo();
void freeHost();
size_t m_size;
T *m_dptr[2];
GLuint m_vbo[2];
struct cudaGraphicsResource
*m_cuda_vbo_resource[2]; // handles OpenGL-CUDA exchange
size_t m_size;
T *m_dptr[2];
GLuint m_vbo[2];
struct cudaGraphicsResource *m_cuda_vbo_resource[2]; // handles OpenGL-CUDA exchange
T *m_hptr;
T *m_hptr;
bool m_useVBO;
bool m_doubleBuffer;
uint m_currentRead, m_currentWrite;
bool m_useVBO;
bool m_doubleBuffer;
uint m_currentRead, m_currentWrite;
};
template <class T>
GpuArray<T>::GpuArray()
: m_size(0), m_hptr(0), m_currentRead(0), m_currentWrite(0) {
m_dptr[0] = 0;
m_dptr[1] = 0;
m_vbo[0] = 0;
m_vbo[1] = 0;
m_cuda_vbo_resource[0] = NULL;
m_cuda_vbo_resource[1] = NULL;
}
template <class T>
GpuArray<T>::~GpuArray() {
free();
}
template <class T>
void GpuArray<T>::alloc(size_t size, bool vbo, bool doubleBuffer,
bool useElementArray) {
m_size = size;
m_useVBO = vbo;
m_doubleBuffer = doubleBuffer;
if (m_doubleBuffer) {
m_currentWrite = 1;
}
allocHost();
if (vbo) {
allocVbo(useElementArray);
} else {
allocDevice();
}
}
template <class T>
void GpuArray<T>::free() {
freeHost();
if (m_vbo) {
freeVbo();
}
if (m_dptr) {
freeDevice();
}
}
template <class T>
void GpuArray<T>::allocHost() {
m_hptr = (T *)new T[m_size];
}
template <class T>
void GpuArray<T>::freeHost() {
if (m_hptr) {
delete[] m_hptr;
m_hptr = 0;
}
}
template <class T>
void GpuArray<T>::allocDevice() {
checkCudaErrors(cudaMalloc((void **)&m_dptr[0], m_size * sizeof(T)));
if (m_doubleBuffer) {
checkCudaErrors(cudaMalloc((void **)&m_dptr[1], m_size * sizeof(T)));
}
}
template <class T>
void GpuArray<T>::freeDevice() {
if (m_dptr[0]) {
checkCudaErrors(cudaFree(m_dptr[0]));
: m_size(0)
, m_hptr(0)
, m_currentRead(0)
, m_currentWrite(0)
{
m_dptr[0] = 0;
}
if (m_dptr[1]) {
checkCudaErrors(cudaFree(m_dptr[1]));
m_dptr[1] = 0;
}
}
template <class T>
GLuint GpuArray<T>::createVbo(size_t size, bool useElementArray) {
GLuint vbo;
glGenBuffers(1, &vbo);
if (useElementArray) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
} else {
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
return vbo;
}
template <class T>
void GpuArray<T>::allocVbo(bool useElementArray) {
m_vbo[0] = createVbo(m_size * sizeof(T), useElementArray);
checkCudaErrors(cudaGraphicsGLRegisterBuffer(
&m_cuda_vbo_resource[0], m_vbo[0], cudaGraphicsMapFlagsWriteDiscard));
if (m_doubleBuffer) {
m_vbo[1] = createVbo(m_size * sizeof(T), useElementArray);
checkCudaErrors(cudaGraphicsGLRegisterBuffer(
&m_cuda_vbo_resource[1], m_vbo[1], cudaGraphicsMapFlagsWriteDiscard));
}
}
template <class T>
void GpuArray<T>::freeVbo() {
if (m_vbo[0]) {
checkCudaErrors(cudaGraphicsUnregisterResource(m_cuda_vbo_resource[0]));
glDeleteBuffers(1, &m_vbo[0]);
m_vbo[0] = 0;
}
if (m_vbo[1]) {
checkCudaErrors(cudaGraphicsUnregisterResource(m_cuda_vbo_resource[1]));
glDeleteBuffers(1, &m_vbo[1]);
m_vbo[1] = 0;
}
m_cuda_vbo_resource[0] = NULL;
m_cuda_vbo_resource[1] = NULL;
}
template <class T>
void GpuArray<T>::swap() {
std::swap(m_currentRead, m_currentWrite);
template <class T> GpuArray<T>::~GpuArray() { free(); }
template <class T> void GpuArray<T>::alloc(size_t size, bool vbo, bool doubleBuffer, bool useElementArray)
{
m_size = size;
m_useVBO = vbo;
m_doubleBuffer = doubleBuffer;
if (m_doubleBuffer) {
m_currentWrite = 1;
}
allocHost();
if (vbo) {
allocVbo(useElementArray);
}
else {
allocDevice();
}
}
template <class T>
void GpuArray<T>::map() {
if (m_vbo[0]) {
checkCudaErrors(cudaGraphicsMapResources(1, &m_cuda_vbo_resource[0], 0));
size_t num_bytes;
checkCudaErrors(cudaGraphicsResourceGetMappedPointer(
(void **)&m_dptr[0], &num_bytes, m_cuda_vbo_resource[0]));
}
template <class T> void GpuArray<T>::free()
{
freeHost();
if (m_doubleBuffer && m_vbo[1]) {
checkCudaErrors(cudaGraphicsMapResources(1, &m_cuda_vbo_resource[1], 0));
size_t num_bytes;
checkCudaErrors(cudaGraphicsResourceGetMappedPointer(
(void **)&m_dptr[1], &num_bytes, m_cuda_vbo_resource[1]));
}
if (m_vbo) {
freeVbo();
}
if (m_dptr) {
freeDevice();
}
}
template <class T>
void GpuArray<T>::unmap() {
if (m_vbo[0]) {
checkCudaErrors(cudaGraphicsUnmapResources(1, &m_cuda_vbo_resource[0], 0));
m_dptr[0] = 0;
}
template <class T> void GpuArray<T>::allocHost() { m_hptr = (T *)new T[m_size]; }
if (m_doubleBuffer && m_vbo[1]) {
checkCudaErrors(cudaGraphicsUnmapResources(1, &m_cuda_vbo_resource[1], 0));
m_dptr[1] = 0;
}
template <class T> void GpuArray<T>::freeHost()
{
if (m_hptr) {
delete[] m_hptr;
m_hptr = 0;
}
}
template <class T>
void GpuArray<T>::copy(Direction dir, uint start, uint count) {
if (count == 0) {
count = (uint)m_size;
}
template <class T> void GpuArray<T>::allocDevice()
{
checkCudaErrors(cudaMalloc((void **)&m_dptr[0], m_size * sizeof(T)));
map();
if (m_doubleBuffer) {
checkCudaErrors(cudaMalloc((void **)&m_dptr[1], m_size * sizeof(T)));
}
}
switch (dir) {
template <class T> void GpuArray<T>::freeDevice()
{
if (m_dptr[0]) {
checkCudaErrors(cudaFree(m_dptr[0]));
m_dptr[0] = 0;
}
if (m_dptr[1]) {
checkCudaErrors(cudaFree(m_dptr[1]));
m_dptr[1] = 0;
}
}
template <class T> GLuint GpuArray<T>::createVbo(size_t size, bool useElementArray)
{
GLuint vbo;
glGenBuffers(1, &vbo);
if (useElementArray) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
else {
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
return vbo;
}
template <class T> void GpuArray<T>::allocVbo(bool useElementArray)
{
m_vbo[0] = createVbo(m_size * sizeof(T), useElementArray);
checkCudaErrors(cudaGraphicsGLRegisterBuffer(&m_cuda_vbo_resource[0], m_vbo[0], cudaGraphicsMapFlagsWriteDiscard));
if (m_doubleBuffer) {
m_vbo[1] = createVbo(m_size * sizeof(T), useElementArray);
checkCudaErrors(
cudaGraphicsGLRegisterBuffer(&m_cuda_vbo_resource[1], m_vbo[1], cudaGraphicsMapFlagsWriteDiscard));
}
}
template <class T> void GpuArray<T>::freeVbo()
{
if (m_vbo[0]) {
checkCudaErrors(cudaGraphicsUnregisterResource(m_cuda_vbo_resource[0]));
glDeleteBuffers(1, &m_vbo[0]);
m_vbo[0] = 0;
}
if (m_vbo[1]) {
checkCudaErrors(cudaGraphicsUnregisterResource(m_cuda_vbo_resource[1]));
glDeleteBuffers(1, &m_vbo[1]);
m_vbo[1] = 0;
}
}
template <class T> void GpuArray<T>::swap() { std::swap(m_currentRead, m_currentWrite); }
template <class T> void GpuArray<T>::map()
{
if (m_vbo[0]) {
checkCudaErrors(cudaGraphicsMapResources(1, &m_cuda_vbo_resource[0], 0));
size_t num_bytes;
checkCudaErrors(cudaGraphicsResourceGetMappedPointer((void **)&m_dptr[0], &num_bytes, m_cuda_vbo_resource[0]));
}
if (m_doubleBuffer && m_vbo[1]) {
checkCudaErrors(cudaGraphicsMapResources(1, &m_cuda_vbo_resource[1], 0));
size_t num_bytes;
checkCudaErrors(cudaGraphicsResourceGetMappedPointer((void **)&m_dptr[1], &num_bytes, m_cuda_vbo_resource[1]));
}
}
template <class T> void GpuArray<T>::unmap()
{
if (m_vbo[0]) {
checkCudaErrors(cudaGraphicsUnmapResources(1, &m_cuda_vbo_resource[0], 0));
m_dptr[0] = 0;
}
if (m_doubleBuffer && m_vbo[1]) {
checkCudaErrors(cudaGraphicsUnmapResources(1, &m_cuda_vbo_resource[1], 0));
m_dptr[1] = 0;
}
}
template <class T> void GpuArray<T>::copy(Direction dir, uint start, uint count)
{
if (count == 0) {
count = (uint)m_size;
}
map();
switch (dir) {
case HOST_TO_DEVICE:
checkCudaErrors(cudaMemcpy((void *)(m_dptr[m_currentRead] + start),
(void *)(m_hptr + start), count * sizeof(T),
cudaMemcpyHostToDevice));
break;
checkCudaErrors(cudaMemcpy((void *)(m_dptr[m_currentRead] + start),
(void *)(m_hptr + start),
count * sizeof(T),
cudaMemcpyHostToDevice));
break;
case DEVICE_TO_HOST:
checkCudaErrors(cudaMemcpy((void *)(m_hptr + start),
(void *)(m_dptr[m_currentRead] + start),
count * sizeof(T), cudaMemcpyDeviceToHost));
break;
}
checkCudaErrors(cudaMemcpy((void *)(m_hptr + start),
(void *)(m_dptr[m_currentRead] + start),
count * sizeof(T),
cudaMemcpyDeviceToHost));
break;
}
unmap();
unmap();
}
template <class T>
void GpuArray<T>::memset(T value, uint start, uint count) {}
template <class T> void GpuArray<T>::memset(T value, uint start, uint count) {}

View File

@@ -25,23 +25,22 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <algorithm>
#include <assert.h>
#include <math.h>
#include <memory.h>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <math.h>
#include <memory.h>
#define HELPERGL_EXTERN_GL_FUNC_IMPLEMENTATION
#include <helper_gl.h>
#include <cuda_runtime.h>
#include <cuda_gl_interop.h>
#include <helper_functions.h>
#include <cuda_runtime.h>
#include <helper_cuda.h>
#include <helper_functions.h>
#include <helper_gl.h>
#include "ParticleSystem.h"
#include "ParticleSystem.cuh"
#include "ParticleSystem.h"
#include "particles_kernel.cuh"
#ifndef CUDART_PI_F
@@ -53,97 +52,104 @@
*/
ParticleSystem::ParticleSystem(uint numParticles, bool bUseVBO, bool bUseGL)
: m_bInitialized(false),
m_bUseVBO(bUseVBO),
m_numParticles(numParticles),
m_particleRadius(0.1f),
m_doDepthSort(false),
m_timer(NULL),
m_time(0.0f) {
m_params.gravity = make_float3(0.0f, 0.0f, 0.0f);
m_params.globalDamping = 1.0f;
m_params.noiseSpeed = make_float3(0.0f, 0.0f, 0.0f);
: m_bInitialized(false)
, m_bUseVBO(bUseVBO)
, m_numParticles(numParticles)
, m_particleRadius(0.1f)
, m_doDepthSort(false)
, m_timer(NULL)
, m_time(0.0f)
{
m_params.gravity = make_float3(0.0f, 0.0f, 0.0f);
m_params.globalDamping = 1.0f;
m_params.noiseSpeed = make_float3(0.0f, 0.0f, 0.0f);
_initialize(numParticles, bUseGL);
_initialize(numParticles, bUseGL);
}
ParticleSystem::~ParticleSystem() {
_free();
m_numParticles = 0;
ParticleSystem::~ParticleSystem()
{
_free();
m_numParticles = 0;
}
void ParticleSystem::_initialize(int numParticles, bool bUseGL) {
assert(!m_bInitialized);
void ParticleSystem::_initialize(int numParticles, bool bUseGL)
{
assert(!m_bInitialized);
createNoiseTexture(64, 64, 64);
createNoiseTexture(64, 64, 64);
m_numParticles = numParticles;
m_numParticles = numParticles;
// allocate GPU arrays
m_pos.alloc(m_numParticles, m_bUseVBO, true); // create as VBO
m_vel.alloc(m_numParticles, m_bUseVBO, true);
// allocate GPU arrays
m_pos.alloc(m_numParticles, m_bUseVBO, true); // create as VBO
m_vel.alloc(m_numParticles, m_bUseVBO, true);
m_sortKeys.alloc(m_numParticles);
m_indices.alloc(m_numParticles, m_bUseVBO, false,
true); // create as index buffer
m_sortKeys.alloc(m_numParticles);
m_indices.alloc(m_numParticles, m_bUseVBO, false,
true); // create as index buffer
sdkCreateTimer(&m_timer);
setParameters(&m_params);
sdkCreateTimer(&m_timer);
setParameters(&m_params);
m_bInitialized = true;
m_bInitialized = true;
}
void ParticleSystem::_free() { assert(m_bInitialized); }
// step the simulation
void ParticleSystem::step(float deltaTime) {
assert(m_bInitialized);
void ParticleSystem::step(float deltaTime)
{
assert(m_bInitialized);
m_params.time = m_time;
setParameters(&m_params);
m_params.time = m_time;
setParameters(&m_params);
m_pos.map();
m_vel.map();
m_pos.map();
m_vel.map();
// integrate particles
integrateSystem(m_pos.getDevicePtr(), m_pos.getDeviceWritePtr(),
m_vel.getDevicePtr(), m_vel.getDeviceWritePtr(), deltaTime,
m_numParticles);
// integrate particles
integrateSystem(m_pos.getDevicePtr(),
m_pos.getDeviceWritePtr(),
m_vel.getDevicePtr(),
m_vel.getDeviceWritePtr(),
deltaTime,
m_numParticles);
m_pos.unmap();
m_vel.unmap();
m_pos.unmap();
m_vel.unmap();
m_pos.swap();
m_vel.swap();
m_pos.swap();
m_vel.swap();
m_time += deltaTime;
m_time += deltaTime;
}
// depth sort the particles
void ParticleSystem::depthSort() {
if (!m_doDepthSort) {
return;
}
void ParticleSystem::depthSort()
{
if (!m_doDepthSort) {
return;
}
m_pos.map();
m_indices.map();
m_pos.map();
m_indices.map();
// calculate depth
calcDepth(m_pos.getDevicePtr(), m_sortKeys.getDevicePtr(),
m_indices.getDevicePtr(), m_sortVector, m_numParticles);
// calculate depth
calcDepth(m_pos.getDevicePtr(), m_sortKeys.getDevicePtr(), m_indices.getDevicePtr(), m_sortVector, m_numParticles);
// radix sort
sortParticles(m_sortKeys.getDevicePtr(), m_indices.getDevicePtr(),
m_numParticles);
// radix sort
sortParticles(m_sortKeys.getDevicePtr(), m_indices.getDevicePtr(), m_numParticles);
m_pos.unmap();
m_indices.unmap();
m_pos.unmap();
m_indices.unmap();
}
uint *ParticleSystem::getSortedIndices() {
// copy sorted indices back to CPU
m_indices.copy(GpuArray<uint>::DEVICE_TO_HOST);
return m_indices.getHostPtr();
uint *ParticleSystem::getSortedIndices()
{
// copy sorted indices back to CPU
m_indices.copy(GpuArray<uint>::DEVICE_TO_HOST);
return m_indices.getHostPtr();
}
// random float [0, 1]
@@ -156,213 +162,237 @@ inline float sfrand() { return frand() * 2.0f - 1.0f; }
inline vec3f svrand() { return vec3f(sfrand(), sfrand(), sfrand()); }
// random point in circle
inline vec2f randCircle() {
vec2f r;
inline vec2f randCircle()
{
vec2f r;
do {
r = vec2f(sfrand(), sfrand());
} while (length(r) > 1.0f);
do {
r = vec2f(sfrand(), sfrand());
} while (length(r) > 1.0f);
return r;
return r;
}
// random point in sphere
inline vec3f randSphere() {
vec3f r;
inline vec3f randSphere()
{
vec3f r;
do {
r = svrand();
} while (length(r) > 1.0f);
do {
r = svrand();
} while (length(r) > 1.0f);
return r;
return r;
}
// initialize in regular grid
void ParticleSystem::initGrid(vec3f start, uint3 size, vec3f spacing,
float jitter, vec3f vel, uint numParticles,
float lifetime) {
srand(1973);
void ParticleSystem::initGrid(vec3f start,
uint3 size,
vec3f spacing,
float jitter,
vec3f vel,
uint numParticles,
float lifetime)
{
srand(1973);
float4 *posPtr = m_pos.getHostPtr();
float4 *velPtr = m_vel.getHostPtr();
float4 *posPtr = m_pos.getHostPtr();
float4 *velPtr = m_vel.getHostPtr();
for (uint z = 0; z < size.z; z++) {
for (uint y = 0; y < size.y; y++) {
for (uint x = 0; x < size.x; x++) {
uint i = (z * size.y * size.x) + (y * size.x) + x;
for (uint z = 0; z < size.z; z++) {
for (uint y = 0; y < size.y; y++) {
for (uint x = 0; x < size.x; x++) {
uint i = (z * size.y * size.x) + (y * size.x) + x;
if (i < numParticles) {
vec3f pos = start + spacing * vec3f((float)x, (float)y, (float)z) +
svrand() * jitter;
if (i < numParticles) {
vec3f pos = start + spacing * vec3f((float)x, (float)y, (float)z) + svrand() * jitter;
posPtr[i] = make_float4(pos.x, pos.y, pos.z, 0.0f);
velPtr[i] = make_float4(vel.x, vel.y, vel.z, lifetime);
posPtr[i] = make_float4(pos.x, pos.y, pos.z, 0.0f);
velPtr[i] = make_float4(vel.x, vel.y, vel.z, lifetime);
}
}
}
}
}
}
}
// initialize in random positions within cube
void ParticleSystem::initCubeRandom(vec3f origin, vec3f size, vec3f vel,
float lifetime) {
float4 *posPtr = m_pos.getHostPtr();
float4 *velPtr = m_vel.getHostPtr();
void ParticleSystem::initCubeRandom(vec3f origin, vec3f size, vec3f vel, float lifetime)
{
float4 *posPtr = m_pos.getHostPtr();
float4 *velPtr = m_vel.getHostPtr();
for (uint i = 0; i < m_numParticles; i++) {
vec3f pos = origin + svrand() * size;
posPtr[i] = make_float4(pos.x, pos.y, pos.z, 0.0f);
velPtr[i] = make_float4(vel.x, vel.y, vel.z, lifetime);
}
for (uint i = 0; i < m_numParticles; i++) {
vec3f pos = origin + svrand() * size;
posPtr[i] = make_float4(pos.x, pos.y, pos.z, 0.0f);
velPtr[i] = make_float4(vel.x, vel.y, vel.z, lifetime);
}
}
// add sphere on regular grid
void ParticleSystem::addSphere(uint &index, vec3f pos, vec3f vel, int r,
float spacing, float jitter, float lifetime) {
float4 *posPtr = m_pos.getHostPtr();
float4 *velPtr = m_vel.getHostPtr();
void ParticleSystem::addSphere(uint &index, vec3f pos, vec3f vel, int r, float spacing, float jitter, float lifetime)
{
float4 *posPtr = m_pos.getHostPtr();
float4 *velPtr = m_vel.getHostPtr();
uint start = index;
uint count = 0;
uint start = index;
uint count = 0;
for (int z = -r; z <= r; z++) {
for (int y = -r; y <= r; y++) {
for (int x = -r; x <= r; x++) {
vec3f delta = vec3f((float)x, (float)y, (float)z) * spacing;
float dist = length(delta);
for (int z = -r; z <= r; z++) {
for (int y = -r; y <= r; y++) {
for (int x = -r; x <= r; x++) {
vec3f delta = vec3f((float)x, (float)y, (float)z) * spacing;
float dist = length(delta);
if ((dist <= spacing * r) && (index < m_numParticles)) {
// vec3f p = pos + delta + svrand()*jitter;
if ((dist <= spacing * r) && (index < m_numParticles)) {
// vec3f p = pos + delta + svrand()*jitter;
posPtr[index] = make_float4(pos.x, pos.y, pos.z, 0.0f);
velPtr[index] = make_float4(vel.x, vel.y, vel.z, lifetime);
posPtr[index] = make_float4(pos.x, pos.y, pos.z, 0.0f);
velPtr[index] = make_float4(vel.x, vel.y, vel.z, lifetime);
index++;
count++;
index++;
count++;
}
}
}
}
}
}
m_pos.copy(GpuArray<float4>::HOST_TO_DEVICE, start, count);
m_vel.copy(GpuArray<float4>::HOST_TO_DEVICE, start, count);
m_pos.copy(GpuArray<float4>::HOST_TO_DEVICE, start, count);
m_vel.copy(GpuArray<float4>::HOST_TO_DEVICE, start, count);
}
void ParticleSystem::reset(ParticleConfig config) {
switch (config) {
void ParticleSystem::reset(ParticleConfig config)
{
switch (config) {
default:
case CONFIG_RANDOM:
initCubeRandom(vec3f(0.0, 1.0, 0.0), vec3f(1.0, 1.0, 1.0), vec3f(0.0f),
100.0);
break;
initCubeRandom(vec3f(0.0, 1.0, 0.0), vec3f(1.0, 1.0, 1.0), vec3f(0.0f), 100.0);
break;
case CONFIG_GRID: {
float jitter = m_particleRadius * 0.01f;
uint s = (int)ceilf(powf((float)m_numParticles, 1.0f / 3.0f));
uint gridSize[3];
gridSize[0] = gridSize[1] = gridSize[2] = s;
initGrid(vec3f(-1.0, 0.0, -1.0), make_uint3(s, s, s),
vec3f(m_particleRadius * 2.0f), jitter, vec3f(0.0),
m_numParticles, 100.0);
float jitter = m_particleRadius * 0.01f;
uint s = (int)ceilf(powf((float)m_numParticles, 1.0f / 3.0f));
uint gridSize[3];
gridSize[0] = gridSize[1] = gridSize[2] = s;
initGrid(vec3f(-1.0, 0.0, -1.0),
make_uint3(s, s, s),
vec3f(m_particleRadius * 2.0f),
jitter,
vec3f(0.0),
m_numParticles,
100.0);
} break;
}
}
m_pos.copy(GpuArray<float4>::HOST_TO_DEVICE);
m_vel.copy(GpuArray<float4>::HOST_TO_DEVICE);
m_pos.copy(GpuArray<float4>::HOST_TO_DEVICE);
m_vel.copy(GpuArray<float4>::HOST_TO_DEVICE);
}
// particle emitters
void ParticleSystem::discEmitter(uint &index, vec3f pos, vec3f vel, vec3f vx,
vec3f vy, float r, int n, float lifetime,
float lifetimeVariance) {
float4 *posPtr = m_pos.getHostPtr();
float4 *velPtr = m_vel.getHostPtr();
void ParticleSystem::discEmitter(uint &index,
vec3f pos,
vec3f vel,
vec3f vx,
vec3f vy,
float r,
int n,
float lifetime,
float lifetimeVariance)
{
float4 *posPtr = m_pos.getHostPtr();
float4 *velPtr = m_vel.getHostPtr();
uint start = index;
uint count = 0;
uint start = index;
uint count = 0;
for (int i = 0; i < n; i++) {
vec2f delta = randCircle() * r;
for (int i = 0; i < n; i++) {
vec2f delta = randCircle() * r;
if (index < m_numParticles) {
vec3f p = pos + delta.x * vx + delta.y * vy;
float lt = lifetime + frand() * lifetimeVariance;
if (index < m_numParticles) {
vec3f p = pos + delta.x * vx + delta.y * vy;
float lt = lifetime + frand() * lifetimeVariance;
posPtr[index] = make_float4(p.x, p.y, p.z, 0.0f);
velPtr[index] = make_float4(vel.x, vel.y, vel.z, lt);
posPtr[index] = make_float4(p.x, p.y, p.z, 0.0f);
velPtr[index] = make_float4(vel.x, vel.y, vel.z, lt);
index++;
count++;
index++;
count++;
}
}
}
m_pos.copy(GpuArray<float4>::HOST_TO_DEVICE, start, count);
m_vel.copy(GpuArray<float4>::HOST_TO_DEVICE, start, count);
m_pos.copy(GpuArray<float4>::HOST_TO_DEVICE, start, count);
m_vel.copy(GpuArray<float4>::HOST_TO_DEVICE, start, count);
}
void ParticleSystem::sphereEmitter(uint &index, vec3f pos, vec3f vel,
vec3f spread, float r, int n, float lifetime,
float lifetimeVariance) {
float4 *posPtr = m_pos.getHostPtr();
float4 *velPtr = m_vel.getHostPtr();
void ParticleSystem::sphereEmitter(uint &index,
vec3f pos,
vec3f vel,
vec3f spread,
float r,
int n,
float lifetime,
float lifetimeVariance)
{
float4 *posPtr = m_pos.getHostPtr();
float4 *velPtr = m_vel.getHostPtr();
uint start = index;
uint count = 0;
uint start = index;
uint count = 0;
for (int i = 0; i < n; i++) {
vec3f x = randSphere();
for (int i = 0; i < n; i++) {
vec3f x = randSphere();
// float dist = length(x);
if (index < m_numParticles) {
vec3f p = pos + x * r;
float age = 0.0;
// float dist = length(x);
if (index < m_numParticles) {
vec3f p = pos + x * r;
float age = 0.0;
float lt = lifetime + frand() * lifetimeVariance;
float lt = lifetime + frand() * lifetimeVariance;
vec3f dir = randSphere();
dir.y = fabs(dir.y);
vec3f v = vel + dir * spread;
vec3f dir = randSphere();
dir.y = fabs(dir.y);
vec3f v = vel + dir * spread;
posPtr[index] = make_float4(p.x, p.y, p.z, age);
velPtr[index] = make_float4(v.x, v.y, v.z, lt);
posPtr[index] = make_float4(p.x, p.y, p.z, age);
velPtr[index] = make_float4(v.x, v.y, v.z, lt);
index++;
count++;
index++;
count++;
}
}
}
m_pos.copy(GpuArray<float4>::HOST_TO_DEVICE, start, count);
m_vel.copy(GpuArray<float4>::HOST_TO_DEVICE, start, count);
m_pos.copy(GpuArray<float4>::HOST_TO_DEVICE, start, count);
m_vel.copy(GpuArray<float4>::HOST_TO_DEVICE, start, count);
}
void ParticleSystem::setModelView(float *m) {
for (int i = 0; i < 16; i++) {
m_modelView.m[i] = m[i];
}
void ParticleSystem::setModelView(float *m)
{
for (int i = 0; i < 16; i++) {
m_modelView.m[i] = m[i];
}
}
// dump particles to stdout for debugging
void ParticleSystem::dumpParticles(uint start, uint count) {
m_pos.copy(GpuArray<float4>::DEVICE_TO_HOST);
float4 *pos = m_pos.getHostPtr();
void ParticleSystem::dumpParticles(uint start, uint count)
{
m_pos.copy(GpuArray<float4>::DEVICE_TO_HOST);
float4 *pos = m_pos.getHostPtr();
m_vel.copy(GpuArray<float4>::DEVICE_TO_HOST);
float4 *vel = m_vel.getHostPtr();
m_vel.copy(GpuArray<float4>::DEVICE_TO_HOST);
float4 *vel = m_vel.getHostPtr();
for (uint i = start; i < start + count; i++) {
printf("%d: ", i);
printf("pos: (%.4f, %.4f, %.4f, %.4f)\n", pos[i].x, pos[i].y, pos[i].z,
pos[i].w);
printf("vel: (%.4f, %.4f, %.4f, %.4f)\n", vel[i].x, vel[i].y, vel[i].z,
vel[i].w);
}
for (uint i = start; i < start + count; i++) {
printf("%d: ", i);
printf("pos: (%.4f, %.4f, %.4f, %.4f)\n", pos[i].x, pos[i].y, pos[i].z, pos[i].w);
printf("vel: (%.4f, %.4f, %.4f, %.4f)\n", vel[i].x, vel[i].y, vel[i].z, vel[i].w);
}
}
// dump particles to a system memory host
void ParticleSystem::dumpBin(float4 **posData, float4 **velData) {
m_pos.copy(GpuArray<float4>::DEVICE_TO_HOST);
*posData = m_pos.getHostPtr();
void ParticleSystem::dumpBin(float4 **posData, float4 **velData)
{
m_pos.copy(GpuArray<float4>::DEVICE_TO_HOST);
*posData = m_pos.getHostPtr();
m_vel.copy(GpuArray<float4>::DEVICE_TO_HOST);
*velData = m_vel.getHostPtr();
m_vel.copy(GpuArray<float4>::DEVICE_TO_HOST);
*velData = m_vel.getHostPtr();
}

View File

@@ -27,18 +27,20 @@
#include "particles_kernel.cuh"
extern "C" {
void initCuda(bool bUseGL);
void setParameters(SimParams *hostParams);
void createNoiseTexture(int w, int h, int d);
extern "C"
{
void initCuda(bool bUseGL);
void setParameters(SimParams *hostParams);
void createNoiseTexture(int w, int h, int d);
void integrateSystem(float4 *oldPos, float4 *newPos, float4 *oldVel,
float4 *newVel, float deltaTime, int numParticles);
void
integrateSystem(float4 *oldPos, float4 *newPos, float4 *oldVel, float4 *newVel, float deltaTime, int numParticles);
void calcDepth(float4 *pos,
float *keys, // output
uint *indices, // output
float3 sortVector, int numParticles);
void calcDepth(float4 *pos,
float *keys, // output
uint *indices, // output
float3 sortVector,
int numParticles);
void sortParticles(float *sortKeys, uint *indices, uint numParticles);
void sortParticles(float *sortKeys, uint *indices, uint numParticles);
}

View File

@@ -29,84 +29,102 @@
#define __PARTICLESYSTEM_H__
#include <helper_functions.h>
#include "particles_kernel.cuh"
#include "vector_functions.h"
#include "GpuArray.h"
#include "nvMath.h"
#include "particles_kernel.cuh"
#include "vector_functions.h"
using namespace nv;
// CUDA BodySystem: runs on the GPU
class ParticleSystem {
public:
ParticleSystem(uint numParticles, bool bUseVBO = true, bool bUseGL = true);
~ParticleSystem();
class ParticleSystem
{
public:
ParticleSystem(uint numParticles, bool bUseVBO = true, bool bUseGL = true);
~ParticleSystem();
enum ParticleConfig { CONFIG_RANDOM, CONFIG_GRID, _NUM_CONFIGS };
enum ParticleConfig { CONFIG_RANDOM, CONFIG_GRID, _NUM_CONFIGS };
void step(float deltaTime);
void depthSort();
void reset(ParticleConfig config);
void step(float deltaTime);
void depthSort();
void reset(ParticleConfig config);
uint getNumParticles() { return m_numParticles; }
uint getNumParticles() { return m_numParticles; }
uint getPosBuffer() { return m_pos.getVbo(); }
uint getVelBuffer() { return m_vel.getVbo(); }
uint getColorBuffer() { return 0; }
uint getSortedIndexBuffer() { return m_indices.getVbo(); }
uint *getSortedIndices();
uint getPosBuffer() { return m_pos.getVbo(); }
uint getVelBuffer() { return m_vel.getVbo(); }
uint getColorBuffer() { return 0; }
uint getSortedIndexBuffer() { return m_indices.getVbo(); }
uint *getSortedIndices();
float getParticleRadius() { return m_particleRadius; }
float getParticleRadius() { return m_particleRadius; }
SimParams &getParams() { return m_params; }
SimParams &getParams() { return m_params; }
void setSorting(bool x) { m_doDepthSort = x; }
void setModelView(float *m);
void setSortVector(float3 v) { m_sortVector = v; }
void setSorting(bool x) { m_doDepthSort = x; }
void setModelView(float *m);
void setSortVector(float3 v) { m_sortVector = v; }
void addSphere(uint &index, vec3f pos, vec3f vel, int r, float spacing,
float jitter, float lifetime);
void discEmitter(uint &index, vec3f pos, vec3f vel, vec3f vx, vec3f vy,
float r, int n, float lifetime, float lifetimeVariance);
void sphereEmitter(uint &index, vec3f pos, vec3f vel, vec3f spread, float r,
int n, float lifetime, float lifetimeVariance);
void addSphere(uint &index, vec3f pos, vec3f vel, int r, float spacing, float jitter, float lifetime);
void discEmitter(uint &index,
vec3f pos,
vec3f vel,
vec3f vx,
vec3f vy,
float r,
int n,
float lifetime,
float lifetimeVariance);
void sphereEmitter(uint &index,
vec3f pos,
vec3f vel,
vec3f spread,
float r,
int n,
float lifetime,
float lifetimeVariance);
void dumpParticles(uint start, uint count);
void dumpBin(float4 **posData, float4 **velData);
void dumpParticles(uint start, uint count);
void dumpBin(float4 **posData, float4 **velData);
protected: // methods
ParticleSystem() {}
protected: // methods
ParticleSystem() {}
void _initialize(int numParticlesm, bool bUseGL = true);
void _free();
void _initialize(int numParticlesm, bool bUseGL = true);
void _free();
void initGrid(vec3f start, uint3 size, vec3f spacing, float jitter, vec3f vel,
uint numParticles, float lifetime = 100.0f);
void initCubeRandom(vec3f origin, vec3f size, vec3f vel,
float lifetime = 100.0f);
void initGrid(vec3f start,
uint3 size,
vec3f spacing,
float jitter,
vec3f vel,
uint numParticles,
float lifetime = 100.0f);
void initCubeRandom(vec3f origin, vec3f size, vec3f vel, float lifetime = 100.0f);
protected: // data
bool m_bInitialized;
bool m_bUseVBO;
uint m_numParticles;
protected: // data
bool m_bInitialized;
bool m_bUseVBO;
uint m_numParticles;
float m_particleRadius;
float m_particleRadius;
GpuArray<float4> m_pos;
GpuArray<float4> m_vel;
GpuArray<float4> m_pos;
GpuArray<float4> m_vel;
// params
SimParams m_params;
// params
SimParams m_params;
float4x4 m_modelView;
float3 m_sortVector;
bool m_doDepthSort;
float4x4 m_modelView;
float3 m_sortVector;
bool m_doDepthSort;
GpuArray<float> m_sortKeys;
GpuArray<uint> m_indices; // sorted indices for rendering
GpuArray<float> m_sortKeys;
GpuArray<uint> m_indices; // sorted indices for rendering
StopWatchInterface *m_timer;
float m_time;
StopWatchInterface *m_timer;
float m_time;
};
#endif // __PARTICLESYSTEM_H__
#endif // __PARTICLESYSTEM_H__

View File

@@ -29,131 +29,128 @@
This file contains simple wrapper functions that call the CUDA kernels
*/
#define HELPERGL_EXTERN_GL_FUNC_IMPLEMENTATION
#include <helper_gl.h>
#include <helper_cuda.h>
#include <cstdlib>
#include <cstdio>
#include <string.h>
#include <cstdlib>
#include <cuda_gl_interop.h>
#include <helper_cuda.h>
#include <helper_gl.h>
#include <string.h>
#include "ParticleSystem.cuh"
#include "particles_kernel_device.cuh"
#include "thrust/device_ptr.h"
#include "thrust/for_each.h"
#include "thrust/iterator/zip_iterator.h"
#include "thrust/sort.h"
#include "particles_kernel_device.cuh"
#include "ParticleSystem.cuh"
extern "C"
{
cudaArray *noiseArray;
cudaArray *noiseArray;
void setParameters(SimParams *hostParams)
{
// copy parameters to constant memory
checkCudaErrors(cudaMemcpyToSymbol(cudaParams, hostParams, sizeof(SimParams)));
}
// Round a / b to nearest higher integer value
int iDivUp(int a, int b) { return (a % b != 0) ? (a / b + 1) : (a / b); }
// compute grid and thread block size for a given number of elements
void computeGridSize(int n, int blockSize, int &numBlocks, int &numThreads)
{
numThreads = min(blockSize, n);
numBlocks = iDivUp(n, numThreads);
}
inline float frand() { return rand() / (float)RAND_MAX; }
// create 3D texture containing random values
void createNoiseTexture(int w, int h, int d)
{
cudaExtent size = make_cudaExtent(w, h, d);
size_t elements = size.width * size.height * size.depth;
float *volumeData = (float *)malloc(elements * 4 * sizeof(float));
float *ptr = volumeData;
for (size_t i = 0; i < elements; i++)
void setParameters(SimParams *hostParams)
{
*ptr++ = frand() * 2.0f - 1.0f;
*ptr++ = frand() * 2.0f - 1.0f;
*ptr++ = frand() * 2.0f - 1.0f;
*ptr++ = frand() * 2.0f - 1.0f;
// copy parameters to constant memory
checkCudaErrors(cudaMemcpyToSymbol(cudaParams, hostParams, sizeof(SimParams)));
}
cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float4>();
checkCudaErrors(cudaMalloc3DArray(&noiseArray, &channelDesc, size));
// Round a / b to nearest higher integer value
int iDivUp(int a, int b) { return (a % b != 0) ? (a / b + 1) : (a / b); }
cudaMemcpy3DParms copyParams = {0};
copyParams.srcPtr = make_cudaPitchedPtr(
(void *)volumeData, size.width * sizeof(float4), size.width, size.height);
copyParams.dstArray = noiseArray;
copyParams.extent = size;
copyParams.kind = cudaMemcpyHostToDevice;
checkCudaErrors(cudaMemcpy3D(&copyParams));
// compute grid and thread block size for a given number of elements
void computeGridSize(int n, int blockSize, int &numBlocks, int &numThreads)
{
numThreads = min(blockSize, n);
numBlocks = iDivUp(n, numThreads);
}
free(volumeData);
inline float frand() { return rand() / (float)RAND_MAX; }
cudaResourceDesc texRes;
memset(&texRes, 0, sizeof(cudaResourceDesc));
// create 3D texture containing random values
void createNoiseTexture(int w, int h, int d)
{
cudaExtent size = make_cudaExtent(w, h, d);
size_t elements = size.width * size.height * size.depth;
texRes.resType = cudaResourceTypeArray;
texRes.res.array.array = noiseArray;
float *volumeData = (float *)malloc(elements * 4 * sizeof(float));
float *ptr = volumeData;
cudaTextureDesc texDescr;
memset(&texDescr, 0, sizeof(cudaTextureDesc));
for (size_t i = 0; i < elements; i++) {
*ptr++ = frand() * 2.0f - 1.0f;
*ptr++ = frand() * 2.0f - 1.0f;
*ptr++ = frand() * 2.0f - 1.0f;
*ptr++ = frand() * 2.0f - 1.0f;
}
texDescr.normalizedCoords = true;
texDescr.filterMode = cudaFilterModeLinear;
texDescr.addressMode[0] = cudaAddressModeWrap;
texDescr.addressMode[1] = cudaAddressModeWrap;
texDescr.addressMode[2] = cudaAddressModeWrap;
texDescr.readMode = cudaReadModeElementType;
cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float4>();
checkCudaErrors(cudaMalloc3DArray(&noiseArray, &channelDesc, size));
checkCudaErrors(cudaCreateTextureObject(&noiseTex, &texRes, &texDescr, NULL));
}
cudaMemcpy3DParms copyParams = {0};
copyParams.srcPtr =
make_cudaPitchedPtr((void *)volumeData, size.width * sizeof(float4), size.width, size.height);
copyParams.dstArray = noiseArray;
copyParams.extent = size;
copyParams.kind = cudaMemcpyHostToDevice;
checkCudaErrors(cudaMemcpy3D(&copyParams));
void integrateSystem(float4 *oldPos, float4 *newPos, float4 *oldVel,
float4 *newVel, float deltaTime, int numParticles)
{
thrust::device_ptr<float4> d_newPos(newPos);
thrust::device_ptr<float4> d_newVel(newVel);
thrust::device_ptr<float4> d_oldPos(oldPos);
thrust::device_ptr<float4> d_oldVel(oldVel);
free(volumeData);
thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(
d_newPos, d_newVel, d_oldPos, d_oldVel)),
thrust::make_zip_iterator(thrust::make_tuple(
d_newPos + numParticles, d_newVel + numParticles,
d_oldPos + numParticles, d_oldVel + numParticles)),
integrate_functor(deltaTime, noiseTex));
}
cudaResourceDesc texRes;
memset(&texRes, 0, sizeof(cudaResourceDesc));
void calcDepth(float4 *pos,
float *keys, // output
uint *indices, // output
float3 sortVector, int numParticles)
{
thrust::device_ptr<float4> d_pos(pos);
thrust::device_ptr<float> d_keys(keys);
thrust::device_ptr<uint> d_indices(indices);
texRes.resType = cudaResourceTypeArray;
texRes.res.array.array = noiseArray;
thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(d_pos, d_keys)),
thrust::make_zip_iterator(thrust::make_tuple(
d_pos + numParticles, d_keys + numParticles)),
calcDepth_functor(sortVector));
cudaTextureDesc texDescr;
memset(&texDescr, 0, sizeof(cudaTextureDesc));
thrust::sequence(d_indices, d_indices + numParticles);
}
texDescr.normalizedCoords = true;
texDescr.filterMode = cudaFilterModeLinear;
texDescr.addressMode[0] = cudaAddressModeWrap;
texDescr.addressMode[1] = cudaAddressModeWrap;
texDescr.addressMode[2] = cudaAddressModeWrap;
texDescr.readMode = cudaReadModeElementType;
void sortParticles(float *sortKeys, uint *indices, uint numParticles)
{
thrust::sort_by_key(thrust::device_ptr<float>(sortKeys),
thrust::device_ptr<float>(sortKeys + numParticles),
thrust::device_ptr<uint>(indices));
}
checkCudaErrors(cudaCreateTextureObject(&noiseTex, &texRes, &texDescr, NULL));
}
void
integrateSystem(float4 *oldPos, float4 *newPos, float4 *oldVel, float4 *newVel, float deltaTime, int numParticles)
{
thrust::device_ptr<float4> d_newPos(newPos);
thrust::device_ptr<float4> d_newVel(newVel);
thrust::device_ptr<float4> d_oldPos(oldPos);
thrust::device_ptr<float4> d_oldVel(oldVel);
thrust::for_each(
thrust::make_zip_iterator(thrust::make_tuple(d_newPos, d_newVel, d_oldPos, d_oldVel)),
thrust::make_zip_iterator(thrust::make_tuple(
d_newPos + numParticles, d_newVel + numParticles, d_oldPos + numParticles, d_oldVel + numParticles)),
integrate_functor(deltaTime, noiseTex));
}
void calcDepth(float4 *pos,
float *keys, // output
uint *indices, // output
float3 sortVector,
int numParticles)
{
thrust::device_ptr<float4> d_pos(pos);
thrust::device_ptr<float> d_keys(keys);
thrust::device_ptr<uint> d_indices(indices);
thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(d_pos, d_keys)),
thrust::make_zip_iterator(thrust::make_tuple(d_pos + numParticles, d_keys + numParticles)),
calcDepth_functor(sortVector));
thrust::sequence(d_indices, d_indices + numParticles);
}
void sortParticles(float *sortKeys, uint *indices, uint numParticles)
{
thrust::sort_by_key(thrust::device_ptr<float>(sortKeys),
thrust::device_ptr<float>(sortKeys + numParticles),
thrust::device_ptr<uint>(indices));
}
} // extern "C"

View File

@@ -33,6 +33,7 @@
#include <stdlib.h>
#define HELPERGL_EXTERN_GL_FUNC_IMPLEMENTATION
#include <helper_gl.h>
#include "SmokeRenderer.h"
#include "SmokeShaders.h"
@@ -43,362 +44,222 @@
#include <GL/freeglut.h>
#endif
#define USE_MBLUR 1
#define USE_MBLUR 1
#define COLOR_ATTENUATION 1
SmokeRenderer::SmokeRenderer(int maxParticles)
: mMaxParticles(maxParticles),
mNumParticles(0),
mPosVbo(0),
mVelVbo(0),
mColorVbo(0),
mIndexBuffer(0),
mParticleRadius(0.005f),
mDisplayMode(VOLUMETRIC),
mWindowW(800),
mWindowH(600),
mFov(40.0f),
m_downSample(2),
m_numSlices(32),
m_numDisplayedSlices(32),
m_sliceNo(0),
m_shadowAlpha(0.005f),
m_spriteAlpha(0.1f),
m_doBlur(false),
m_blurRadius(1.0f),
m_displayLightBuffer(false),
m_lightPos(5.0f, 5.0f, -5.0f),
m_lightTarget(0.0f, 0.0f, 0.0f),
m_lightColor(1.0f, 1.0f, 0.5f),
m_colorAttenuation(0.1f, 0.2f, 0.3f),
m_lightBufferSize(256),
m_srcLightTexture(0),
m_lightDepthTexture(0),
m_lightFbo(0),
m_imageTex(0),
m_depthTex(0),
m_imageFbo(0) {
// load shader programs
m_simpleProg = new GLSLProgram(particleVS, simplePS);
m_particleProg = new GLSLProgram(mblurVS, mblurGS, particlePS);
m_particleShadowProg = new GLSLProgram(mblurVS, mblurGS, particleShadowPS);
: mMaxParticles(maxParticles)
, mNumParticles(0)
, mPosVbo(0)
, mVelVbo(0)
, mColorVbo(0)
, mIndexBuffer(0)
, mParticleRadius(0.005f)
, mDisplayMode(VOLUMETRIC)
, mWindowW(800)
, mWindowH(600)
, mFov(40.0f)
, m_downSample(2)
, m_numSlices(32)
, m_numDisplayedSlices(32)
, m_sliceNo(0)
, m_shadowAlpha(0.005f)
, m_spriteAlpha(0.1f)
, m_doBlur(false)
, m_blurRadius(1.0f)
, m_displayLightBuffer(false)
, m_lightPos(5.0f, 5.0f, -5.0f)
, m_lightTarget(0.0f, 0.0f, 0.0f)
, m_lightColor(1.0f, 1.0f, 0.5f)
, m_colorAttenuation(0.1f, 0.2f, 0.3f)
, m_lightBufferSize(256)
, m_srcLightTexture(0)
, m_lightDepthTexture(0)
, m_lightFbo(0)
, m_imageTex(0)
, m_depthTex(0)
, m_imageFbo(0)
{
// load shader programs
m_simpleProg = new GLSLProgram(particleVS, simplePS);
m_particleProg = new GLSLProgram(mblurVS, mblurGS, particlePS);
m_particleShadowProg = new GLSLProgram(mblurVS, mblurGS, particleShadowPS);
m_blurProg = new GLSLProgram(passThruVS, blurPS);
m_displayTexProg = new GLSLProgram(passThruVS, texture2DPS);
m_blurProg = new GLSLProgram(passThruVS, blurPS);
m_displayTexProg = new GLSLProgram(passThruVS, texture2DPS);
// create buffer for light shadows
createLightBuffer();
// create buffer for light shadows
createLightBuffer();
glutReportErrors();
glutReportErrors();
}
SmokeRenderer::~SmokeRenderer() {
delete m_particleProg;
delete m_particleShadowProg;
delete m_blurProg;
delete m_displayTexProg;
delete m_simpleProg;
SmokeRenderer::~SmokeRenderer()
{
delete m_particleProg;
delete m_particleShadowProg;
delete m_blurProg;
delete m_displayTexProg;
delete m_simpleProg;
delete m_lightFbo;
glDeleteTextures(2, m_lightTexture);
glDeleteTextures(1, &m_lightDepthTexture);
delete m_lightFbo;
glDeleteTextures(2, m_lightTexture);
glDeleteTextures(1, &m_lightDepthTexture);
delete m_imageFbo;
glDeleteTextures(1, &m_imageTex);
glDeleteTextures(1, &m_depthTex);
delete m_imageFbo;
glDeleteTextures(1, &m_imageTex);
glDeleteTextures(1, &m_depthTex);
}
// draw points from vertex buffer objects
void SmokeRenderer::drawPoints(int start, int count, bool sort) {
glBindBuffer(GL_ARRAY_BUFFER, mPosVbo);
glVertexPointer(4, GL_FLOAT, 0, 0);
glEnableClientState(GL_VERTEX_ARRAY);
void SmokeRenderer::drawPoints(int start, int count, bool sort)
{
glBindBuffer(GL_ARRAY_BUFFER, mPosVbo);
glVertexPointer(4, GL_FLOAT, 0, 0);
glEnableClientState(GL_VERTEX_ARRAY);
if (mColorVbo) {
glBindBuffer(GL_ARRAY_BUFFER, mColorVbo);
glColorPointer(4, GL_FLOAT, 0, 0);
glEnableClientState(GL_COLOR_ARRAY);
}
if (mColorVbo) {
glBindBuffer(GL_ARRAY_BUFFER, mColorVbo);
glColorPointer(4, GL_FLOAT, 0, 0);
glEnableClientState(GL_COLOR_ARRAY);
}
if (mVelVbo) {
glBindBuffer(GL_ARRAY_BUFFER, mVelVbo);
glClientActiveTexture(GL_TEXTURE0);
glTexCoordPointer(4, GL_FLOAT, 0, 0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}
if (sort) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, mIndexBuffer);
glDrawElements(GL_POINTS, count, GL_UNSIGNED_INT, (void *)(start * sizeof(unsigned int)));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
}
else {
glDrawArrays(GL_POINTS, start, count);
}
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
if (mVelVbo) {
glBindBuffer(GL_ARRAY_BUFFER, mVelVbo);
glClientActiveTexture(GL_TEXTURE0);
glTexCoordPointer(4, GL_FLOAT, 0, 0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}
if (sort) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, mIndexBuffer);
glDrawElements(GL_POINTS, count, GL_UNSIGNED_INT,
(void *)(start * sizeof(unsigned int)));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
} else {
glDrawArrays(GL_POINTS, start, count);
}
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glClientActiveTexture(GL_TEXTURE0);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
// draw points using given shader program
void SmokeRenderer::drawPointSprites(GLSLProgram *prog, int start, int count,
bool shadowed) {
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE); // don't write depth
glEnable(GL_BLEND);
void SmokeRenderer::drawPointSprites(GLSLProgram *prog, int start, int count, bool shadowed)
{
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE); // don't write depth
glEnable(GL_BLEND);
prog->enable();
prog->setUniform1f("pointRadius", mParticleRadius);
prog->enable();
prog->setUniform1f("pointRadius", mParticleRadius);
if (shadowed) {
prog->bindTexture("shadowTex", m_lightTexture[m_srcLightTexture],
GL_TEXTURE_2D, 0);
}
if (shadowed) {
prog->bindTexture("shadowTex", m_lightTexture[m_srcLightTexture], GL_TEXTURE_2D, 0);
}
// draw points
drawPoints(start, count, true);
// draw points
drawPoints(start, count, true);
prog->disable();
prog->disable();
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
}
// calculate vectors for half-angle slice rendering
void SmokeRenderer::calcVectors() {
// get model view matrix
glGetFloatv(GL_MODELVIEW_MATRIX, (float *)m_modelView.get_value());
void SmokeRenderer::calcVectors()
{
// get model view matrix
glGetFloatv(GL_MODELVIEW_MATRIX, (float *)m_modelView.get_value());
// calculate eye space light vector
m_lightVector = normalize(m_lightPos);
m_lightPosEye = m_modelView * vec4f(m_lightPos, 1.0);
// calculate eye space light vector
m_lightVector = normalize(m_lightPos);
m_lightPosEye = m_modelView * vec4f(m_lightPos, 1.0);
// calculate half-angle vector between view and light
m_viewVector = -vec3f(m_modelView.get_row(2));
// calculate half-angle vector between view and light
m_viewVector = -vec3f(m_modelView.get_row(2));
if (dot(m_viewVector, m_lightVector) > 0) {
m_halfVector = normalize(m_viewVector + m_lightVector);
m_invertedView = false;
} else {
m_halfVector = normalize(-m_viewVector + m_lightVector);
m_invertedView = true;
}
if (dot(m_viewVector, m_lightVector) > 0) {
m_halfVector = normalize(m_viewVector + m_lightVector);
m_invertedView = false;
}
else {
m_halfVector = normalize(-m_viewVector + m_lightVector);
m_invertedView = true;
}
// calculate light view matrix
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
gluLookAt(m_lightPos[0], m_lightPos[1], m_lightPos[2], m_lightTarget[0],
m_lightTarget[1], m_lightTarget[2], 0.0, 1.0, 0.0);
// calculate light view matrix
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
gluLookAt(m_lightPos[0],
m_lightPos[1],
m_lightPos[2],
m_lightTarget[0],
m_lightTarget[1],
m_lightTarget[2],
0.0,
1.0,
0.0);
// calculate light projection matrix
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluPerspective(45.0, 1.0, 1.0, 200.0);
// calculate light projection matrix
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluPerspective(45.0, 1.0, 1.0, 200.0);
glGetFloatv(GL_MODELVIEW_MATRIX, (float *)m_lightView.get_value());
glGetFloatv(GL_PROJECTION_MATRIX, (float *)m_lightProj.get_value());
glGetFloatv(GL_MODELVIEW_MATRIX, (float *)m_lightView.get_value());
glGetFloatv(GL_PROJECTION_MATRIX, (float *)m_lightProj.get_value());
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
// construct shadow matrix
matrix4f scale;
scale.set_scale(vec3f(0.5, 0.5, 0.5));
matrix4f translate;
translate.set_translate(vec3f(0.5, 0.5, 0.5));
// construct shadow matrix
matrix4f scale;
scale.set_scale(vec3f(0.5, 0.5, 0.5));
matrix4f translate;
translate.set_translate(vec3f(0.5, 0.5, 0.5));
m_shadowMatrix =
translate * scale * m_lightProj * m_lightView * inverse(m_modelView);
m_shadowMatrix = translate * scale * m_lightProj * m_lightView * inverse(m_modelView);
// calc object space eye position
m_eyePos = inverse(m_modelView) * vec4f(0.0, 0.0, 0.0, 1.0);
// calc object space eye position
m_eyePos = inverse(m_modelView) * vec4f(0.0, 0.0, 0.0, 1.0);
// calc half vector in eye space
m_halfVectorEye = m_modelView * vec4f(m_halfVector, 0.0);
// calc half vector in eye space
m_halfVectorEye = m_modelView * vec4f(m_halfVector, 0.0);
}
// draw slice of particles from camera view
void SmokeRenderer::drawSlice(int i) {
m_imageFbo->Bind();
glViewport(0, 0, m_imageW, m_imageH);
void SmokeRenderer::drawSlice(int i)
{
m_imageFbo->Bind();
glViewport(0, 0, m_imageW, m_imageH);
glColor4f(1.0, 1.0, 1.0, m_spriteAlpha);
glColor4f(1.0, 1.0, 1.0, m_spriteAlpha);
if (m_invertedView) {
// front-to-back
glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE);
} else {
// back-to-front
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
if (m_invertedView) {
// front-to-back
glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE);
}
else {
// back-to-front
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
drawPointSprites(m_particleShadowProg, i * m_batchSize, m_batchSize, true);
drawPointSprites(m_particleShadowProg, i * m_batchSize, m_batchSize, true);
m_imageFbo->Disable();
m_imageFbo->Disable();
}
// draw slice of particles from light's point of view
void SmokeRenderer::drawSliceLightView(int i) {
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadMatrixf((GLfloat *)m_lightView.get_value());
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadMatrixf((GLfloat *)m_lightProj.get_value());
m_lightFbo->Bind();
glViewport(0, 0, m_lightBufferSize, m_lightBufferSize);
glColor4f(m_colorAttenuation[0] * m_shadowAlpha,
m_colorAttenuation[1] * m_shadowAlpha,
m_colorAttenuation[2] * m_shadowAlpha, 1.0);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
drawPointSprites(m_particleProg, i * m_batchSize, m_batchSize, false);
m_lightFbo->Disable();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
// draw particles as slices with shadowing
void SmokeRenderer::drawSlices() {
m_batchSize = mNumParticles / m_numSlices;
// clear light buffer
m_srcLightTexture = 0;
m_lightFbo->Bind();
m_lightFbo->AttachTexture(GL_TEXTURE_2D, m_lightTexture[m_srcLightTexture],
GL_COLOR_ATTACHMENT0_EXT);
glClearColor(1.0f - m_lightColor[0], 1.0f - m_lightColor[1],
1.0f - m_lightColor[2], 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
m_lightFbo->Disable();
// clear volume image
m_imageFbo->Bind();
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
m_imageFbo->Disable();
glActiveTexture(GL_TEXTURE0);
glMatrixMode(GL_TEXTURE);
glLoadMatrixf((GLfloat *)m_shadowMatrix.get_value());
// render slices
if (m_numDisplayedSlices > m_numSlices) m_numDisplayedSlices = m_numSlices;
for (int i = 0; i < m_numDisplayedSlices; i++) {
// draw slice from camera view, sampling light buffer
drawSlice(i);
// draw slice from light view to light buffer, accumulating shadows
drawSliceLightView(i);
if (m_doBlur) {
blurLightBuffer();
}
}
glActiveTexture(GL_TEXTURE0);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
}
// blur light buffer to simulate scattering effects
void SmokeRenderer::blurLightBuffer() {
m_lightFbo->Bind();
m_lightFbo->AttachTexture(GL_TEXTURE_2D,
m_lightTexture[1 - m_srcLightTexture],
GL_COLOR_ATTACHMENT0_EXT);
glViewport(0, 0, m_lightBufferSize, m_lightBufferSize);
m_blurProg->enable();
m_blurProg->bindTexture("tex", m_lightTexture[m_srcLightTexture],
GL_TEXTURE_2D, 0);
m_blurProg->setUniform2f("texelSize", 1.0f / (float)m_lightBufferSize,
1.0f / (float)m_lightBufferSize);
m_blurProg->setUniform1f("blurRadius", m_blurRadius);
glDisable(GL_DEPTH_TEST);
drawQuad();
m_blurProg->disable();
m_srcLightTexture = 1 - m_srcLightTexture;
m_lightFbo->Disable();
}
// display texture to screen
void SmokeRenderer::displayTexture(GLuint tex) {
m_displayTexProg->enable();
m_displayTexProg->bindTexture("tex", tex, GL_TEXTURE_2D, 0);
drawQuad();
m_displayTexProg->disable();
}
// composite final volume image on top of scene
void SmokeRenderer::compositeResult() {
glViewport(0, 0, mWindowW, mWindowH);
glDisable(GL_DEPTH_TEST);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
displayTexture(m_imageTex);
glDisable(GL_BLEND);
}
void SmokeRenderer::render() {
switch (mDisplayMode) {
case POINTS:
glColor3f(1.0, 1.0, 1.0);
m_simpleProg->enable();
drawPoints(0, mNumParticles, false);
m_simpleProg->disable();
break;
case SPRITES:
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
glColor4f(1.0, 1.0, 1.0, m_spriteAlpha);
drawPointSprites(m_particleProg, 0, mNumParticles, false);
break;
case VOLUMETRIC:
drawSlices();
compositeResult();
break;
case NUM_MODES:
break;
}
if (m_displayLightBuffer) {
// display light buffer to screen
glViewport(0, 0, m_lightBufferSize, m_lightBufferSize);
glDisable(GL_DEPTH_TEST);
displayTexture(m_lightTexture[m_srcLightTexture]);
glViewport(0, 0, mWindowW, mWindowH);
}
glutReportErrors();
}
// render scene depth to texture
// (this is to ensure that particle are correctly occluded in the low-resolution
// render buffer)
void SmokeRenderer::beginSceneRender(Target target) {
if (target == LIGHT_BUFFER) {
m_lightFbo->Bind();
glViewport(0, 0, m_lightBufferSize, m_lightBufferSize);
void SmokeRenderer::drawSliceLightView(int i)
{
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadMatrixf((GLfloat *)m_lightView.get_value());
@@ -406,162 +267,318 @@ void SmokeRenderer::beginSceneRender(Target target) {
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadMatrixf((GLfloat *)m_lightProj.get_value());
} else {
m_imageFbo->Bind();
glViewport(0, 0, m_imageW, m_imageH);
}
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthMask(GL_TRUE);
glClear(GL_DEPTH_BUFFER_BIT);
}
m_lightFbo->Bind();
glViewport(0, 0, m_lightBufferSize, m_lightBufferSize);
glColor4f(m_colorAttenuation[0] * m_shadowAlpha,
m_colorAttenuation[1] * m_shadowAlpha,
m_colorAttenuation[2] * m_shadowAlpha,
1.0);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
drawPointSprites(m_particleProg, i * m_batchSize, m_batchSize, false);
void SmokeRenderer::endSceneRender(Target target) {
if (target == LIGHT_BUFFER) {
m_lightFbo->Disable();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
} else {
m_imageFbo->Disable();
}
}
glViewport(0, 0, mWindowW, mWindowH);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// draw particles as slices with shadowing
void SmokeRenderer::drawSlices()
{
m_batchSize = mNumParticles / m_numSlices;
// clear light buffer
m_srcLightTexture = 0;
m_lightFbo->Bind();
m_lightFbo->AttachTexture(GL_TEXTURE_2D, m_lightTexture[m_srcLightTexture], GL_COLOR_ATTACHMENT0_EXT);
glClearColor(1.0f - m_lightColor[0], 1.0f - m_lightColor[1], 1.0f - m_lightColor[2], 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
m_lightFbo->Disable();
// clear volume image
m_imageFbo->Bind();
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
m_imageFbo->Disable();
glActiveTexture(GL_TEXTURE0);
glMatrixMode(GL_TEXTURE);
glLoadMatrixf((GLfloat *)m_shadowMatrix.get_value());
// render slices
if (m_numDisplayedSlices > m_numSlices)
m_numDisplayedSlices = m_numSlices;
for (int i = 0; i < m_numDisplayedSlices; i++) {
// draw slice from camera view, sampling light buffer
drawSlice(i);
// draw slice from light view to light buffer, accumulating shadows
drawSliceLightView(i);
if (m_doBlur) {
blurLightBuffer();
}
}
glActiveTexture(GL_TEXTURE0);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
}
// blur light buffer to simulate scattering effects
void SmokeRenderer::blurLightBuffer()
{
m_lightFbo->Bind();
m_lightFbo->AttachTexture(GL_TEXTURE_2D, m_lightTexture[1 - m_srcLightTexture], GL_COLOR_ATTACHMENT0_EXT);
glViewport(0, 0, m_lightBufferSize, m_lightBufferSize);
m_blurProg->enable();
m_blurProg->bindTexture("tex", m_lightTexture[m_srcLightTexture], GL_TEXTURE_2D, 0);
m_blurProg->setUniform2f("texelSize", 1.0f / (float)m_lightBufferSize, 1.0f / (float)m_lightBufferSize);
m_blurProg->setUniform1f("blurRadius", m_blurRadius);
glDisable(GL_DEPTH_TEST);
drawQuad();
m_blurProg->disable();
m_srcLightTexture = 1 - m_srcLightTexture;
m_lightFbo->Disable();
}
// display texture to screen
void SmokeRenderer::displayTexture(GLuint tex)
{
m_displayTexProg->enable();
m_displayTexProg->bindTexture("tex", tex, GL_TEXTURE_2D, 0);
drawQuad();
m_displayTexProg->disable();
}
// composite final volume image on top of scene
void SmokeRenderer::compositeResult()
{
glViewport(0, 0, mWindowW, mWindowH);
glDisable(GL_DEPTH_TEST);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
displayTexture(m_imageTex);
glDisable(GL_BLEND);
}
void SmokeRenderer::render()
{
switch (mDisplayMode) {
case POINTS:
glColor3f(1.0, 1.0, 1.0);
m_simpleProg->enable();
drawPoints(0, mNumParticles, false);
m_simpleProg->disable();
break;
case SPRITES:
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
glColor4f(1.0, 1.0, 1.0, m_spriteAlpha);
drawPointSprites(m_particleProg, 0, mNumParticles, false);
break;
case VOLUMETRIC:
drawSlices();
compositeResult();
break;
case NUM_MODES:
break;
}
if (m_displayLightBuffer) {
// display light buffer to screen
glViewport(0, 0, m_lightBufferSize, m_lightBufferSize);
glDisable(GL_DEPTH_TEST);
displayTexture(m_lightTexture[m_srcLightTexture]);
glViewport(0, 0, mWindowW, mWindowH);
}
glutReportErrors();
}
// render scene depth to texture
// (this is to ensure that particle are correctly occluded in the low-resolution
// render buffer)
void SmokeRenderer::beginSceneRender(Target target)
{
if (target == LIGHT_BUFFER) {
m_lightFbo->Bind();
glViewport(0, 0, m_lightBufferSize, m_lightBufferSize);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadMatrixf((GLfloat *)m_lightView.get_value());
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadMatrixf((GLfloat *)m_lightProj.get_value());
}
else {
m_imageFbo->Bind();
glViewport(0, 0, m_imageW, m_imageH);
}
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthMask(GL_TRUE);
glClear(GL_DEPTH_BUFFER_BIT);
}
void SmokeRenderer::endSceneRender(Target target)
{
if (target == LIGHT_BUFFER) {
m_lightFbo->Disable();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
else {
m_imageFbo->Disable();
}
glViewport(0, 0, mWindowW, mWindowH);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
// create an OpenGL texture
GLuint SmokeRenderer::createTexture(GLenum target, int w, int h,
GLint internalformat, GLenum format) {
GLuint texid;
glGenTextures(1, &texid);
glBindTexture(target, texid);
GLuint SmokeRenderer::createTexture(GLenum target, int w, int h, GLint internalformat, GLenum format)
{
GLuint texid;
glGenTextures(1, &texid);
glBindTexture(target, texid);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(target, 0, internalformat, w, h, 0, format, GL_FLOAT, 0);
return texid;
glTexImage2D(target, 0, internalformat, w, h, 0, format, GL_FLOAT, 0);
return texid;
}
// create buffers for off-screen rendering
void SmokeRenderer::createBuffers(int w, int h) {
if (m_imageFbo) {
glDeleteTextures(1, &m_imageTex);
glDeleteTextures(1, &m_depthTex);
delete m_imageFbo;
}
void SmokeRenderer::createBuffers(int w, int h)
{
if (m_imageFbo) {
glDeleteTextures(1, &m_imageTex);
glDeleteTextures(1, &m_depthTex);
delete m_imageFbo;
}
mWindowW = w;
mWindowH = h;
mWindowW = w;
mWindowH = h;
m_imageW = w / m_downSample;
m_imageH = h / m_downSample;
m_imageW = w / m_downSample;
m_imageH = h / m_downSample;
// create fbo for image buffer
GLint format = GL_RGBA16F_ARB;
// GLint format = GL_LUMINANCE16F_ARB;
// GLint format = GL_RGBA8;
m_imageTex =
createTexture(GL_TEXTURE_2D, m_imageW, m_imageH, format, GL_RGBA);
m_depthTex = createTexture(GL_TEXTURE_2D, m_imageW, m_imageH,
GL_DEPTH_COMPONENT24_ARB, GL_DEPTH_COMPONENT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// create fbo for image buffer
GLint format = GL_RGBA16F_ARB;
// GLint format = GL_LUMINANCE16F_ARB;
// GLint format = GL_RGBA8;
m_imageTex = createTexture(GL_TEXTURE_2D, m_imageW, m_imageH, format, GL_RGBA);
m_depthTex = createTexture(GL_TEXTURE_2D, m_imageW, m_imageH, GL_DEPTH_COMPONENT24_ARB, GL_DEPTH_COMPONENT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
m_imageFbo = new FramebufferObject();
m_imageFbo->AttachTexture(GL_TEXTURE_2D, m_imageTex,
GL_COLOR_ATTACHMENT0_EXT);
m_imageFbo->AttachTexture(GL_TEXTURE_2D, m_depthTex, GL_DEPTH_ATTACHMENT_EXT);
m_imageFbo->IsValid();
m_imageFbo = new FramebufferObject();
m_imageFbo->AttachTexture(GL_TEXTURE_2D, m_imageTex, GL_COLOR_ATTACHMENT0_EXT);
m_imageFbo->AttachTexture(GL_TEXTURE_2D, m_depthTex, GL_DEPTH_ATTACHMENT_EXT);
m_imageFbo->IsValid();
}
void SmokeRenderer::setLightColor(vec3f c) {
m_lightColor = c;
void SmokeRenderer::setLightColor(vec3f c)
{
m_lightColor = c;
// set light texture border color
GLfloat borderColor[4] = {1.0f - m_lightColor[0], 1.0f - m_lightColor[1],
1.0f - m_lightColor[2], 0.0f};
// set light texture border color
GLfloat borderColor[4] = {1.0f - m_lightColor[0], 1.0f - m_lightColor[1], 1.0f - m_lightColor[2], 0.0f};
glBindTexture(GL_TEXTURE_2D, m_lightTexture[0]);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
glBindTexture(GL_TEXTURE_2D, m_lightTexture[0]);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
glBindTexture(GL_TEXTURE_2D, m_lightTexture[1]);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
glBindTexture(GL_TEXTURE_2D, m_lightTexture[1]);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
glBindTexture(GL_TEXTURE_2D, 0);
glBindTexture(GL_TEXTURE_2D, 0);
}
// create FBOs for light buffer
void SmokeRenderer::createLightBuffer() {
GLint format = GL_RGBA16F_ARB;
// GLint format = GL_RGBA8;
// GLint format = GL_LUMINANCE16F_ARB;
void SmokeRenderer::createLightBuffer()
{
GLint format = GL_RGBA16F_ARB;
// GLint format = GL_RGBA8;
// GLint format = GL_LUMINANCE16F_ARB;
m_lightTexture[0] = createTexture(GL_TEXTURE_2D, m_lightBufferSize,
m_lightBufferSize, format, GL_RGBA);
// make shadows clamp to light color at edges
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
m_lightTexture[0] = createTexture(GL_TEXTURE_2D, m_lightBufferSize, m_lightBufferSize, format, GL_RGBA);
// make shadows clamp to light color at edges
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
m_lightTexture[1] = createTexture(GL_TEXTURE_2D, m_lightBufferSize,
m_lightBufferSize, format, GL_RGBA);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
m_lightTexture[1] = createTexture(GL_TEXTURE_2D, m_lightBufferSize, m_lightBufferSize, format, GL_RGBA);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
m_lightDepthTexture =
createTexture(GL_TEXTURE_2D, m_lightBufferSize, m_lightBufferSize,
GL_DEPTH_COMPONENT24_ARB, GL_DEPTH_COMPONENT);
m_lightDepthTexture = createTexture(
GL_TEXTURE_2D, m_lightBufferSize, m_lightBufferSize, GL_DEPTH_COMPONENT24_ARB, GL_DEPTH_COMPONENT);
m_lightFbo = new FramebufferObject();
m_lightFbo->AttachTexture(GL_TEXTURE_2D, m_lightTexture[m_srcLightTexture],
GL_COLOR_ATTACHMENT0_EXT);
m_lightFbo->AttachTexture(GL_TEXTURE_2D, m_lightDepthTexture,
GL_DEPTH_ATTACHMENT_EXT);
m_lightFbo->IsValid();
m_lightFbo = new FramebufferObject();
m_lightFbo->AttachTexture(GL_TEXTURE_2D, m_lightTexture[m_srcLightTexture], GL_COLOR_ATTACHMENT0_EXT);
m_lightFbo->AttachTexture(GL_TEXTURE_2D, m_lightDepthTexture, GL_DEPTH_ATTACHMENT_EXT);
m_lightFbo->IsValid();
}
void SmokeRenderer::setWindowSize(int w, int h) {
mAspect = (float)mWindowW / (float)mWindowH;
mInvFocalLen = tan(mFov * 0.5f * NV_PI / 180.0f);
void SmokeRenderer::setWindowSize(int w, int h)
{
mAspect = (float)mWindowW / (float)mWindowH;
mInvFocalLen = tan(mFov * 0.5f * NV_PI / 180.0f);
createBuffers(w, h);
createBuffers(w, h);
}
void SmokeRenderer::drawQuad() {
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(-1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex2f(1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex2f(1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex2f(-1.0f, 1.0f);
glEnd();
void SmokeRenderer::drawQuad()
{
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(-1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex2f(1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex2f(1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex2f(-1.0f, 1.0f);
glEnd();
}
void SmokeRenderer::drawVector(vec3f v) {
glBegin(GL_LINES);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3fv((float *)&v[0]);
glEnd();
void SmokeRenderer::drawVector(vec3f v)
{
glBegin(GL_LINES);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3fv((float *)&v[0]);
glEnd();
}
// render vectors to screen for debugging
void SmokeRenderer::debugVectors() {
glColor3f(1.0f, 1.0f, 0.0f);
drawVector(m_lightVector);
void SmokeRenderer::debugVectors()
{
glColor3f(1.0f, 1.0f, 0.0f);
drawVector(m_lightVector);
glColor3f(0.0f, 1.0f, 0.0f);
drawVector(m_viewVector);
glColor3f(0.0f, 1.0f, 0.0f);
drawVector(m_viewVector);
glColor3f(0.0f, 0.0f, 1.0f);
drawVector(-m_viewVector);
glColor3f(0.0f, 0.0f, 1.0f);
drawVector(-m_viewVector);
glColor3f(1.0f, 0.0f, 0.0f);
drawVector(m_halfVector);
glColor3f(1.0f, 0.0f, 0.0f);
drawVector(m_halfVector);
}

View File

@@ -30,139 +30,139 @@
#ifndef SMOKE_RENDERER_H
#define SMOKE_RENDERER_H
#include "framebufferObject.h"
#include "GLSLProgram.h"
#include "framebufferObject.h"
#include "nvMath.h"
using namespace nv;
class SmokeRenderer {
public:
SmokeRenderer(int maxParticles);
~SmokeRenderer();
class SmokeRenderer
{
public:
SmokeRenderer(int maxParticles);
~SmokeRenderer();
enum DisplayMode { POINTS, SPRITES, VOLUMETRIC, NUM_MODES };
enum DisplayMode { POINTS, SPRITES, VOLUMETRIC, NUM_MODES };
enum Target { LIGHT_BUFFER, SCENE_BUFFER };
enum Target { LIGHT_BUFFER, SCENE_BUFFER };
void setDisplayMode(DisplayMode mode) { mDisplayMode = mode; }
void setDisplayMode(DisplayMode mode) { mDisplayMode = mode; }
void setNumParticles(unsigned int x) { mNumParticles = x; }
void setPositionBuffer(GLuint vbo) { mPosVbo = vbo; }
void setVelocityBuffer(GLuint vbo) { mVelVbo = vbo; }
void setColorBuffer(GLuint vbo) { mColorVbo = vbo; }
void setIndexBuffer(GLuint ib) { mIndexBuffer = ib; }
void setNumParticles(unsigned int x) { mNumParticles = x; }
void setPositionBuffer(GLuint vbo) { mPosVbo = vbo; }
void setVelocityBuffer(GLuint vbo) { mVelVbo = vbo; }
void setColorBuffer(GLuint vbo) { mColorVbo = vbo; }
void setIndexBuffer(GLuint ib) { mIndexBuffer = ib; }
void setParticleRadius(float x) { mParticleRadius = x; }
void setWindowSize(int w, int h);
void setFOV(float fov) { mFov = fov; }
void setParticleRadius(float x) { mParticleRadius = x; }
void setWindowSize(int w, int h);
void setFOV(float fov) { mFov = fov; }
void setNumSlices(int x) { m_numSlices = x; }
void setNumDisplayedSlices(int x) { m_numDisplayedSlices = x; }
void setNumSlices(int x) { m_numSlices = x; }
void setNumDisplayedSlices(int x) { m_numDisplayedSlices = x; }
void setAlpha(float x) { m_spriteAlpha = x; }
void setShadowAlpha(float x) { m_shadowAlpha = x; }
void setColorAttenuation(vec3f c) { m_colorAttenuation = c; }
void setLightColor(vec3f c);
void setAlpha(float x) { m_spriteAlpha = x; }
void setShadowAlpha(float x) { m_shadowAlpha = x; }
void setColorAttenuation(vec3f c) { m_colorAttenuation = c; }
void setLightColor(vec3f c);
void setDoBlur(bool b) { m_doBlur = b; }
void setBlurRadius(float x) { m_blurRadius = x; }
void setDisplayLightBuffer(bool b) { m_displayLightBuffer = b; }
void setDoBlur(bool b) { m_doBlur = b; }
void setBlurRadius(float x) { m_blurRadius = x; }
void setDisplayLightBuffer(bool b) { m_displayLightBuffer = b; }
void beginSceneRender(Target target);
void endSceneRender(Target target);
void beginSceneRender(Target target);
void endSceneRender(Target target);
void setLightPosition(vec3f v) { m_lightPos = v; }
void setLightTarget(vec3f v) { m_lightTarget = v; }
void setLightPosition(vec3f v) { m_lightPos = v; }
void setLightTarget(vec3f v) { m_lightTarget = v; }
vec4f getLightPositionEyeSpace() { return m_lightPosEye; }
matrix4f getShadowMatrix() { return m_shadowMatrix; }
vec4f getLightPositionEyeSpace() { return m_lightPosEye; }
matrix4f getShadowMatrix() { return m_shadowMatrix; }
GLuint getShadowTexture() { return m_lightTexture[m_srcLightTexture]; }
GLuint getShadowTexture() { return m_lightTexture[m_srcLightTexture]; }
void calcVectors();
vec3f getSortVector() { return m_halfVector; }
void calcVectors();
vec3f getSortVector() { return m_halfVector; }
void render();
void debugVectors();
void render();
void debugVectors();
private:
void drawPoints(int start, int count, bool sort);
void drawPointSprites(GLSLProgram *prog, int start, int count, bool shadowed);
private:
void drawPoints(int start, int count, bool sort);
void drawPointSprites(GLSLProgram *prog, int start, int count, bool shadowed);
void drawSlice(int i);
void drawSliceLightView(int i);
void drawSlices();
void displayTexture(GLuint tex);
void compositeResult();
void blurLightBuffer();
void depthSort();
void drawSlice(int i);
void drawSliceLightView(int i);
void drawSlices();
void displayTexture(GLuint tex);
void compositeResult();
void blurLightBuffer();
void depthSort();
GLuint createTexture(GLenum target, int w, int h, GLint internalformat,
GLenum format);
void createBuffers(int w, int h);
void createLightBuffer();
GLuint createTexture(GLenum target, int w, int h, GLint internalformat, GLenum format);
void createBuffers(int w, int h);
void createLightBuffer();
void drawQuad();
void drawVector(vec3f v);
void drawQuad();
void drawVector(vec3f v);
// particle data
unsigned int mMaxParticles;
unsigned int mNumParticles;
// particle data
unsigned int mMaxParticles;
unsigned int mNumParticles;
GLuint mPosVbo;
GLuint mVelVbo;
GLuint mColorVbo;
GLuint mIndexBuffer;
GLuint mPosVbo;
GLuint mVelVbo;
GLuint mColorVbo;
GLuint mIndexBuffer;
float mParticleRadius;
DisplayMode mDisplayMode;
float mParticleRadius;
DisplayMode mDisplayMode;
// window
unsigned int mWindowW, mWindowH;
float mAspect, mInvFocalLen;
float mFov;
// window
unsigned int mWindowW, mWindowH;
float mAspect, mInvFocalLen;
float mFov;
int m_downSample;
int m_imageW, m_imageH;
int m_downSample;
int m_imageW, m_imageH;
int m_numSlices;
int m_numDisplayedSlices;
int m_batchSize;
int m_sliceNo;
int m_numSlices;
int m_numDisplayedSlices;
int m_batchSize;
int m_sliceNo;
float m_shadowAlpha;
float m_spriteAlpha;
bool m_doBlur;
float m_blurRadius;
bool m_displayLightBuffer;
float m_shadowAlpha;
float m_spriteAlpha;
bool m_doBlur;
float m_blurRadius;
bool m_displayLightBuffer;
vec3f m_lightVector, m_lightPos, m_lightTarget;
vec3f m_lightColor;
vec3f m_colorAttenuation;
float m_lightDistance;
vec3f m_lightVector, m_lightPos, m_lightTarget;
vec3f m_lightColor;
vec3f m_colorAttenuation;
float m_lightDistance;
matrix4f m_modelView, m_lightView, m_lightProj, m_shadowMatrix;
vec3f m_viewVector, m_halfVector;
bool m_invertedView;
vec4f m_eyePos;
vec4f m_halfVectorEye;
vec4f m_lightPosEye;
matrix4f m_modelView, m_lightView, m_lightProj, m_shadowMatrix;
vec3f m_viewVector, m_halfVector;
bool m_invertedView;
vec4f m_eyePos;
vec4f m_halfVectorEye;
vec4f m_lightPosEye;
// programs
GLSLProgram *m_simpleProg;
GLSLProgram *m_particleProg, *m_particleShadowProg;
GLSLProgram *m_displayTexProg, *m_blurProg;
// programs
GLSLProgram *m_simpleProg;
GLSLProgram *m_particleProg, *m_particleShadowProg;
GLSLProgram *m_displayTexProg, *m_blurProg;
// image buffers
int m_lightBufferSize;
GLuint m_lightTexture[2];
int m_srcLightTexture;
GLuint m_lightDepthTexture;
FramebufferObject *m_lightFbo;
// image buffers
int m_lightBufferSize;
GLuint m_lightTexture[2];
int m_srcLightTexture;
GLuint m_lightDepthTexture;
FramebufferObject *m_lightFbo;
GLuint m_imageTex, m_depthTex;
FramebufferObject *m_imageFbo;
GLuint m_imageTex, m_depthTex;
FramebufferObject *m_imageFbo;
};
#endif

View File

@@ -38,231 +38,229 @@ const char *particleVS = STRINGIFY(
\n
vec4 wpos = vec4(gl_Vertex.xyz, 1.0); \n
gl_Position = gl_ModelViewProjectionMatrix *wpos; \n
// calculate window-space point size \n
vec4 eyeSpacePos = gl_ModelViewMatrix *wpos; \n
float dist = length(eyeSpacePos.xyz); \n
gl_PointSize = pointRadius * (pointScale / dist); \n
gl_TexCoord[0] = gl_MultiTexCoord0; // sprite texcoord \n
gl_TexCoord[1] = eyeSpacePos; \n
gl_FrontColor = gl_Color; \n
} \n
);
// motion blur shaders
const char *mblurVS = STRINGIFY(
uniform float timestep; \n
void main() \n
{
\n
vec3 pos = gl_Vertex.xyz; \n
vec3 vel = gl_MultiTexCoord0.xyz; \n
vec3 pos2 = (pos - vel*timestep).xyz; // previous position \n
const char *mblurVS = STRINGIFY(uniform float timestep; \n void
main() \n {
\n vec3 pos = gl_Vertex.xyz;
\n vec3 vel = gl_MultiTexCoord0.xyz;
\n vec3 pos2 = (pos - vel * timestep).xyz; // previous position \n
gl_Position = gl_ModelViewMatrix * vec4(pos, 1.0); \n // eye space
gl_TexCoord[0] = gl_ModelViewMatrix * vec4(pos2, 1.0); \n
gl_Position = gl_ModelViewMatrix * vec4(pos, 1.0);
\n // eye space
gl_TexCoord[0] = gl_ModelViewMatrix * vec4(pos2, 1.0);
\n
// aging \n
float lifetime = gl_MultiTexCoord0.w; \n
float age = gl_Vertex.w; \n
float phase = (lifetime > 0.0) ? (age / lifetime) : 1.0; \n // [0, 1]
// aging \n
float lifetime = gl_MultiTexCoord0.w;
\n float age = gl_Vertex.w;
\n float phase = (lifetime > 0.0) ? (age / lifetime) : 1.0;
\n // [0, 1]
gl_TexCoord[1].x = phase; \n
float fade = 1.0 - phase; \n
// float fade = 1.0; \n
gl_TexCoord[1]
.x = phase;
\n float fade = 1.0 - phase;
\n
// float fade = 1.0; \n
// gl_FrontColor = gl_Color; \n
gl_FrontColor = vec4(gl_Color.xyz, gl_Color.w*fade); \n
} \n
);
// gl_FrontColor = gl_Color; \n
gl_FrontColor = vec4(gl_Color.xyz, gl_Color.w * fade);
\n
} \n);
// motion blur geometry shader
// - outputs stretched quad between previous and current positions
const char *mblurGS =
"#version 120\n"
"#extension GL_EXT_geometry_shader4 : enable\n"
STRINGIFY(
uniform float pointRadius; // point size in world space \n
void main() \n
{
const char *mblurGS = "#version 120\n"
"#extension GL_EXT_geometry_shader4 : enable\n" STRINGIFY(
uniform float pointRadius; // point size in world space \n
void main() \n {
\n
// aging \n
float phase = gl_TexCoordIn[0][1].x;
\n float radius = pointRadius;
\n
// eye space \n
vec3 pos = gl_PositionIn[0].xyz;
\n vec3 pos2 = gl_TexCoordIn[0][0].xyz;
\n vec3 motion = pos - pos2;
\n vec3 dir = normalize(motion);
\n float len = length(motion);
\n
vec3 x = dir * radius;
\n vec3 view = normalize(-pos);
\n vec3 y = normalize(cross(dir, view)) * radius;
\n float facing = dot(view, dir);
\n
// check for very small motion to avoid jitter \n
float threshold = 0.01;
\n
if ((len < threshold) || (facing > 0.95) || (facing < -0.95))
{
\n pos2 = pos;
\n x = vec3(radius, 0.0, 0.0);
\n y = vec3(0.0, -radius, 0.0);
\n
}
\n
// output quad \n
gl_FrontColor = gl_FrontColorIn[0];
\n gl_TexCoord[0] = vec4(0, 0, 0, phase);
\n gl_TexCoord[1] = gl_PositionIn[0];
\n gl_Position = gl_ProjectionMatrix * vec4(pos + x + y, 1);
\n EmitVertex();
\n
gl_TexCoord[0] = vec4(0, 1, 0, phase);
\n gl_TexCoord[1] = gl_PositionIn[0];
\n gl_Position = gl_ProjectionMatrix * vec4(pos + x - y, 1);
\n EmitVertex();
\n
gl_TexCoord[0] = vec4(1, 0, 0, phase);
\n gl_TexCoord[1] = gl_PositionIn[0];
\n gl_Position = gl_ProjectionMatrix * vec4(pos2 - x + y, 1);
\n EmitVertex();
\n
gl_TexCoord[0] = vec4(1, 1, 0, phase);
\n gl_TexCoord[1] = gl_PositionIn[0];
\n gl_Position = gl_ProjectionMatrix * vec4(pos2 - x - y, 1);
\n EmitVertex();
\n
} \n);
const char *simplePS = STRINGIFY(void main() \n {
\n gl_FragColor = gl_Color;
\n
// aging \n
float phase = gl_TexCoordIn[0][1].x; \n
float radius = pointRadius; \n
// eye space \n
vec3 pos = gl_PositionIn[0].xyz; \n
vec3 pos2 = gl_TexCoordIn[0][0].xyz; \n
vec3 motion = pos - pos2; \n
vec3 dir = normalize(motion); \n
float len = length(motion); \n
vec3 x = dir *radius; \n
vec3 view = normalize(-pos); \n
vec3 y = normalize(cross(dir, view)) * radius; \n
float facing = dot(view, dir); \n
// check for very small motion to avoid jitter \n
float threshold = 0.01; \n
if ((len < threshold) || (facing > 0.95) || (facing < -0.95))
{
\n
pos2 = pos;
\n
x = vec3(radius, 0.0, 0.0);
\n
y = vec3(0.0, -radius, 0.0);
\n
} \n
// output quad \n
gl_FrontColor = gl_FrontColorIn[0]; \n
gl_TexCoord[0] = vec4(0, 0, 0, phase); \n
gl_TexCoord[1] = gl_PositionIn[0]; \n
gl_Position = gl_ProjectionMatrix * vec4(pos + x + y, 1); \n
EmitVertex(); \n
gl_TexCoord[0] = vec4(0, 1, 0, phase); \n
gl_TexCoord[1] = gl_PositionIn[0]; \n
gl_Position = gl_ProjectionMatrix * vec4(pos + x - y, 1); \n
EmitVertex(); \n
gl_TexCoord[0] = vec4(1, 0, 0, phase); \n
gl_TexCoord[1] = gl_PositionIn[0]; \n
gl_Position = gl_ProjectionMatrix * vec4(pos2 - x + y, 1); \n
EmitVertex(); \n
gl_TexCoord[0] = vec4(1, 1, 0, phase); \n
gl_TexCoord[1] = gl_PositionIn[0]; \n
gl_Position = gl_ProjectionMatrix * vec4(pos2 - x - y, 1); \n
EmitVertex(); \n
} \n
);
const char *simplePS = STRINGIFY(
void main() \n
{
\n
gl_FragColor = gl_Color; \n
} \n
);
} \n);
// render particle without shadows
const char *particlePS = STRINGIFY(
uniform float pointRadius; \n
void main() \n
{
\n
// calculate eye-space sphere normal from texture coordinates \n
vec3 N; \n
N.xy = gl_TexCoord[0].xy*vec2(2.0, -2.0) + vec2(-1.0, 1.0); \n
float r2 = dot(N.xy, N.xy); \n
const char *particlePS = STRINGIFY(uniform float pointRadius; \n void
main() \n {
\n
// calculate eye-space sphere normal from texture coordinates \n
vec3 N;
\n N.xy = gl_TexCoord[0].xy * vec2(2.0, -2.0) + vec2(-1.0, 1.0);
\n float r2 = dot(N.xy, N.xy);
\n
if (r2 > 1.0) discard; // kill pixels outside circle \n
N.z = sqrt(1.0-r2); \n
if (r2 > 1.0) discard; // kill pixels outside circle \n
N.z = sqrt(1.0 - r2);
\n
// float alpha = saturate(1.0 - r2); \n
float alpha = clamp((1.0 - r2), 0.0, 1.0); \n
alpha *= gl_Color.w; \n
// float alpha = saturate(1.0 - r2); \n
float alpha = clamp((1.0 - r2), 0.0, 1.0);
\n alpha *= gl_Color.w;
\n
gl_FragColor = vec4(gl_Color.xyz * alpha, alpha); \n
} \n
);
gl_FragColor = vec4(gl_Color.xyz * alpha, alpha);
\n
} \n);
// render particle including shadows
const char *particleShadowPS = STRINGIFY(
uniform float pointRadius; \n
uniform sampler2D shadowTex; \n
uniform sampler2D depthTex; \n
void main() \n
{
\n
// calculate eye-space sphere normal from texture coordinates \n
vec3 N; \n
N.xy = gl_TexCoord[0].xy*vec2(2.0, -2.0) + vec2(-1.0, 1.0); \n
float r2 = dot(N.xy, N.xy); \n
uniform float pointRadius; \n uniform sampler2D shadowTex; \n uniform sampler2D depthTex; \n void
main() \n {
\n
// calculate eye-space sphere normal from texture coordinates \n
vec3 N;
\n N.xy = gl_TexCoord[0].xy * vec2(2.0, -2.0) + vec2(-1.0, 1.0);
\n float r2 = dot(N.xy, N.xy);
\n
if (r2 > 1.0) discard; \n // kill pixels outside circle
N.z = sqrt(1.0-r2); \n
vec4 eyeSpacePos = gl_TexCoord[1]; \n
vec4 eyeSpaceSpherePos = vec4(eyeSpacePos.xyz + N*pointRadius, 1.0); \n // point on sphere
vec4 shadowPos = gl_TextureMatrix[0] * eyeSpaceSpherePos; \n
vec3 shadow = vec3(1.0) - texture2DProj(shadowTex, shadowPos.xyw).xyz; \n
// float alpha = saturate(1.0 - r2); \n
float alpha = clamp((1.0 - r2), 0.0, 1.0); \n
alpha *= gl_Color.w; \n
if (r2 > 1.0) discard;
\n // kill pixels outside circle
N.z = sqrt(1.0 - r2);
\n vec4 eyeSpacePos = gl_TexCoord[1];
\n vec4 eyeSpaceSpherePos = vec4(eyeSpacePos.xyz + N * pointRadius, 1.0);
\n // point on sphere
vec4 shadowPos = gl_TextureMatrix[0] * eyeSpaceSpherePos;
\n vec3 shadow = vec3(1.0) - texture2DProj(shadowTex, shadowPos.xyw).xyz;
\n
// float alpha = saturate(1.0 - r2); \n
float alpha = clamp((1.0 - r2), 0.0, 1.0);
\n alpha *= gl_Color.w;
\n
gl_FragColor = vec4(gl_Color.xyz *shadow * alpha, alpha); \n // premul alpha
}
);
gl_FragColor = vec4(gl_Color.xyz * shadow * alpha, alpha);
\n // premul alpha
});
// render particle as lit sphere
const char *particleSpherePS = STRINGIFY(
uniform float pointRadius; \n
uniform vec3 lightDir = vec3(0.577, 0.577, 0.577); \n
void main() \n
{
uniform float pointRadius; \n uniform vec3 lightDir = vec3(0.577, 0.577, 0.577); \n void
main() \n {
\n
// calculate eye-space sphere normal from texture coordinates \n
vec3 N;
\n N.xy = gl_TexCoord[0].xy * vec2(2.0, -2.0) + vec2(-1.0, 1.0);
\n float r2 = dot(N.xy, N.xy);
\n
if (r2 > 1.0) discard; // kill pixels outside circle \n
N.z = sqrt(1.0 - r2);
\n
// calculate depth \n
vec4 eyeSpacePos =
vec4(gl_TexCoord[1].xyz + N * pointRadius, 1.0); // position of this pixel on sphere in eye space \n
vec4 clipSpacePos = gl_ProjectionMatrix * eyeSpacePos;
\n gl_FragDepth = (clipSpacePos.z / clipSpacePos.w) * 0.5 + 0.5;
\n
float diffuse = max(0.0, dot(N, lightDir));
\n
gl_FragColor = diffuse * gl_Color;
\n
} \n);
const char *passThruVS = STRINGIFY(void main() \n {
\n gl_Position = gl_Vertex;
\n gl_TexCoord[0] = gl_MultiTexCoord0;
\n gl_FrontColor = gl_Color;
\n
// calculate eye-space sphere normal from texture coordinates \n
vec3 N; \n
N.xy = gl_TexCoord[0].xy*vec2(2.0, -2.0) + vec2(-1.0, 1.0); \n
float r2 = dot(N.xy, N.xy); \n
} \n);
if (r2 > 1.0) discard; // kill pixels outside circle \n
N.z = sqrt(1.0-r2); \n
// calculate depth \n
vec4 eyeSpacePos = vec4(gl_TexCoord[1].xyz + N*pointRadius, 1.0); // position of this pixel on sphere in eye space \n
vec4 clipSpacePos = gl_ProjectionMatrix *eyeSpacePos; \n
gl_FragDepth = (clipSpacePos.z / clipSpacePos.w)*0.5+0.5; \n
float diffuse = max(0.0, dot(N, lightDir)); \n
gl_FragColor = diffuse *gl_Color; \n
} \n
);
const char *passThruVS = STRINGIFY(
void main() \n
{
\n
gl_Position = gl_Vertex; \n
gl_TexCoord[0] = gl_MultiTexCoord0; \n
gl_FrontColor = gl_Color; \n
} \n
);
const char *texture2DPS = STRINGIFY(
uniform sampler2D tex; \n
void main() \n
{
\n
gl_FragColor = texture2D(tex, gl_TexCoord[0].xy); \n
} \n
);
const char *texture2DPS = STRINGIFY(uniform sampler2D tex; \n void
main() \n {
\n gl_FragColor = texture2D(tex, gl_TexCoord[0].xy);
\n
} \n);
// 4 tap 3x3 gaussian blur
const char *blurPS = STRINGIFY(
uniform sampler2D tex; \n
uniform vec2 texelSize; \n
uniform float blurRadius; \n
void main() \n
{
\n
vec4 c; \n
c = texture2D(tex, gl_TexCoord[0].xy + vec2(-0.5, -0.5)*texelSize*blurRadius); \n
c += texture2D(tex, gl_TexCoord[0].xy + vec2(0.5, -0.5)*texelSize*blurRadius); \n
c += texture2D(tex, gl_TexCoord[0].xy + vec2(0.5, 0.5)*texelSize*blurRadius); \n
c += texture2D(tex, gl_TexCoord[0].xy + vec2(-0.5, 0.5)*texelSize*blurRadius); \n
c *= 0.25; \n
uniform sampler2D tex; \n uniform vec2 texelSize; \n uniform float blurRadius; \n void
main() \n {
\n vec4 c;
\n c = texture2D(tex, gl_TexCoord[0].xy + vec2(-0.5, -0.5) * texelSize * blurRadius);
\n c += texture2D(tex, gl_TexCoord[0].xy + vec2(0.5, -0.5) * texelSize * blurRadius);
\n c += texture2D(tex, gl_TexCoord[0].xy + vec2(0.5, 0.5) * texelSize * blurRadius);
\n c += texture2D(tex, gl_TexCoord[0].xy + vec2(-0.5, 0.5) * texelSize * blurRadius);
\n c *= 0.25;
\n
gl_FragColor = c; \n
} \n
);
gl_FragColor = c;
\n
} \n);
// floor shader
const char *floorVS = STRINGIFY(

View File

@@ -67,289 +67,300 @@
*/
#define HELPERGL_EXTERN_GL_FUNC_IMPLEMENTATION
#include <helper_gl.h>
#include "framebufferObject.h"
#include <helper_gl.h>
#include <iostream>
using namespace std;
FramebufferObject::FramebufferObject()
: m_fboId(_GenerateFboId()), m_savedFboId(0) {
// Bind this FBO so that it actually gets created now
_GuardedBind();
_GuardedUnbind();
: m_fboId(_GenerateFboId())
, m_savedFboId(0)
{
// Bind this FBO so that it actually gets created now
_GuardedBind();
_GuardedUnbind();
}
FramebufferObject::~FramebufferObject() {
glDeleteFramebuffersEXT(1, &m_fboId);
FramebufferObject::~FramebufferObject() { glDeleteFramebuffersEXT(1, &m_fboId); }
void FramebufferObject::Bind() { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboId); }
void FramebufferObject::Disable() { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); }
void FramebufferObject::AttachTexture(GLenum texTarget, GLuint texId, GLenum attachment, int mipLevel, int zSlice)
{
_GuardedBind();
/*
#ifndef NDEBUG
if( GetAttachedId(attachment) != texId ) {
#endif
*/
_FramebufferTextureND(attachment, texTarget, texId, mipLevel, zSlice);
/*
#ifndef NDEBUG
}
else {
cerr << "FramebufferObject::AttachTexture PERFORMANCE WARNING:\n"
<< "\tRedundant bind of texture (id = " << texId << ").\n"
<< "\tHINT : Compile with -DNDEBUG to remove this warning.\n";
}
#endif
*/
_GuardedUnbind();
}
void FramebufferObject::Bind() {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboId);
void FramebufferObject::AttachTextures(int numTextures,
GLenum texTarget[],
GLuint texId[],
GLenum attachment[],
int mipLevel[],
int zSlice[])
{
for (int i = 0; i < numTextures; ++i) {
AttachTexture(texTarget[i],
texId[i],
attachment ? attachment[i] : (GL_COLOR_ATTACHMENT0_EXT + i),
mipLevel ? mipLevel[i] : 0,
zSlice ? zSlice[i] : 0);
}
}
void FramebufferObject::Disable() {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
void FramebufferObject::AttachRenderBuffer(GLuint buffId, GLenum attachment)
{
_GuardedBind();
void FramebufferObject::AttachTexture(GLenum texTarget, GLuint texId,
GLenum attachment, int mipLevel,
int zSlice) {
_GuardedBind();
#ifndef NDEBUG
/*
#ifndef NDEBUG
if( GetAttachedId(attachment) != texId ) {
#endif
*/
if (GetAttachedId(attachment) != buffId) {
#endif
_FramebufferTextureND(attachment, texTarget, texId, mipLevel, zSlice);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment, GL_RENDERBUFFER_EXT, buffId);
/*
#ifndef NDEBUG
#ifndef NDEBUG
}
else {
cerr << "FramebufferObject::AttachTexture PERFORMANCE WARNING:\n"
<< "\tRedundant bind of texture (id = " << texId << ").\n"
<< "\tHINT : Compile with -DNDEBUG to remove this warning.\n";
cerr << "FramebufferObject::AttachRenderBuffer PERFORMANCE WARNING:\n"
<< "\tRedundant bind of Renderbuffer (id = " << buffId << ")\n"
<< "\tHINT : Compile with -DNDEBUG to remove this warning.\n";
}
#endif
*/
_GuardedUnbind();
}
void FramebufferObject::AttachTextures(int numTextures, GLenum texTarget[],
GLuint texId[], GLenum attachment[],
int mipLevel[], int zSlice[]) {
for (int i = 0; i < numTextures; ++i) {
AttachTexture(texTarget[i], texId[i],
attachment ? attachment[i] : (GL_COLOR_ATTACHMENT0_EXT + i),
mipLevel ? mipLevel[i] : 0, zSlice ? zSlice[i] : 0);
}
}
void FramebufferObject::AttachRenderBuffer(GLuint buffId, GLenum attachment) {
_GuardedBind();
#ifndef NDEBUG
if (GetAttachedId(attachment) != buffId) {
#endif
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment,
GL_RENDERBUFFER_EXT, buffId);
#ifndef NDEBUG
} else {
cerr << "FramebufferObject::AttachRenderBuffer PERFORMANCE WARNING:\n"
<< "\tRedundant bind of Renderbuffer (id = " << buffId << ")\n"
<< "\tHINT : Compile with -DNDEBUG to remove this warning.\n";
}
#endif
_GuardedUnbind();
_GuardedUnbind();
}
void FramebufferObject::AttachRenderBuffers(int numBuffers, GLuint buffId[],
GLenum attachment[]) {
for (int i = 0; i < numBuffers; ++i) {
AttachRenderBuffer(
buffId[i], attachment ? attachment[i] : (GL_COLOR_ATTACHMENT0_EXT + i));
}
void FramebufferObject::AttachRenderBuffers(int numBuffers, GLuint buffId[], GLenum attachment[])
{
for (int i = 0; i < numBuffers; ++i) {
AttachRenderBuffer(buffId[i], attachment ? attachment[i] : (GL_COLOR_ATTACHMENT0_EXT + i));
}
}
void FramebufferObject::Unattach(GLenum attachment) {
_GuardedBind();
GLenum type = GetAttachedType(attachment);
void FramebufferObject::Unattach(GLenum attachment)
{
_GuardedBind();
GLenum type = GetAttachedType(attachment);
switch (type) {
switch (type) {
case GL_NONE:
break;
break;
case GL_RENDERBUFFER_EXT:
AttachRenderBuffer(0, attachment);
break;
AttachRenderBuffer(0, attachment);
break;
case GL_TEXTURE:
AttachTexture(GL_TEXTURE_2D, 0, attachment);
break;
AttachTexture(GL_TEXTURE_2D, 0, attachment);
break;
default:
cerr << "FramebufferObject::unbind_attachment ERROR: Unknown attached "
"resource type\n";
}
cerr << "FramebufferObject::unbind_attachment ERROR: Unknown attached "
"resource type\n";
}
_GuardedUnbind();
_GuardedUnbind();
}
void FramebufferObject::UnattachAll() {
int numAttachments = GetMaxColorAttachments();
void FramebufferObject::UnattachAll()
{
int numAttachments = GetMaxColorAttachments();
for (int i = 0; i < numAttachments; ++i) {
Unattach(GL_COLOR_ATTACHMENT0_EXT + i);
}
for (int i = 0; i < numAttachments; ++i) {
Unattach(GL_COLOR_ATTACHMENT0_EXT + i);
}
}
int FramebufferObject::GetMaxColorAttachments() {
GLint maxAttach = 0;
glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &maxAttach);
return maxAttach;
int FramebufferObject::GetMaxColorAttachments()
{
GLint maxAttach = 0;
glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &maxAttach);
return maxAttach;
}
GLuint FramebufferObject::_GenerateFboId() {
GLuint id = 0;
glGenFramebuffersEXT(1, &id);
return id;
GLuint FramebufferObject::_GenerateFboId()
{
GLuint id = 0;
glGenFramebuffersEXT(1, &id);
return id;
}
void FramebufferObject::_GuardedBind() {
// Only binds if m_fboId is different than the currently bound FBO
glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &m_savedFboId);
void FramebufferObject::_GuardedBind()
{
// Only binds if m_fboId is different than the currently bound FBO
glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &m_savedFboId);
if (m_fboId != (GLuint)m_savedFboId) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboId);
}
if (m_fboId != (GLuint)m_savedFboId) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboId);
}
}
void FramebufferObject::_GuardedUnbind() {
// Returns FBO binding to the previously enabled FBO
if (m_fboId != (GLuint)m_savedFboId) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, (GLuint)m_savedFboId);
}
void FramebufferObject::_GuardedUnbind()
{
// Returns FBO binding to the previously enabled FBO
if (m_fboId != (GLuint)m_savedFboId) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, (GLuint)m_savedFboId);
}
}
void FramebufferObject::_FramebufferTextureND(GLenum attachment,
GLenum texTarget, GLuint texId,
int mipLevel, int zSlice) {
if (texTarget == GL_TEXTURE_1D) {
glFramebufferTexture1DEXT(GL_FRAMEBUFFER_EXT, attachment, GL_TEXTURE_1D,
texId, mipLevel);
} else if (texTarget == GL_TEXTURE_3D) {
glFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, attachment, GL_TEXTURE_3D,
texId, mipLevel, zSlice);
} else {
// Default is GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_ARB, or cube faces
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, texTarget, texId,
mipLevel);
}
GLenum texTarget,
GLuint texId,
int mipLevel,
int zSlice)
{
if (texTarget == GL_TEXTURE_1D) {
glFramebufferTexture1DEXT(GL_FRAMEBUFFER_EXT, attachment, GL_TEXTURE_1D, texId, mipLevel);
}
else if (texTarget == GL_TEXTURE_3D) {
glFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, attachment, GL_TEXTURE_3D, texId, mipLevel, zSlice);
}
else {
// Default is GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_ARB, or cube faces
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, texTarget, texId, mipLevel);
}
}
#ifndef NDEBUG
bool FramebufferObject::IsValid(ostream &ostr) {
_GuardedBind();
bool FramebufferObject::IsValid(ostream &ostr)
{
_GuardedBind();
bool isOK = false;
bool isOK = false;
GLenum status;
status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
GLenum status;
status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
switch (status) {
case GL_FRAMEBUFFER_COMPLETE_EXT: // Everything's OK
isOK = true;
break;
switch (status) {
case GL_FRAMEBUFFER_COMPLETE_EXT: // Everything's OK
isOK = true;
break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT\n";
isOK = false;
break;
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT\n";
isOK = false;
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT\n";
isOK = false;
break;
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT\n";
isOK = false;
break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT\n";
isOK = false;
break;
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT\n";
isOK = false;
break;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT\n";
isOK = false;
break;
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT\n";
isOK = false;
break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT\n";
isOK = false;
break;
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT\n";
isOK = false;
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT\n";
isOK = false;
break;
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT\n";
isOK = false;
break;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "GL_FRAMEBUFFER_UNSUPPORTED_EXT\n";
isOK = false;
break;
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "GL_FRAMEBUFFER_UNSUPPORTED_EXT\n";
isOK = false;
break;
default:
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "Unknown ERROR\n";
isOK = false;
}
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "Unknown ERROR\n";
isOK = false;
}
_GuardedUnbind();
return isOK;
_GuardedUnbind();
return isOK;
}
#endif // NDEBUG
#endif // NDEBUG
/// Accessors
GLenum FramebufferObject::GetAttachedType(GLenum attachment) {
// Returns GL_RENDERBUFFER_EXT or GL_TEXTURE
_GuardedBind();
GLint type = 0;
glGetFramebufferAttachmentParameterivEXT(
GL_FRAMEBUFFER_EXT, attachment, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT,
&type);
_GuardedUnbind();
return GLenum(type);
GLenum FramebufferObject::GetAttachedType(GLenum attachment)
{
// Returns GL_RENDERBUFFER_EXT or GL_TEXTURE
_GuardedBind();
GLint type = 0;
glGetFramebufferAttachmentParameterivEXT(
GL_FRAMEBUFFER_EXT, attachment, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT, &type);
_GuardedUnbind();
return GLenum(type);
}
GLuint FramebufferObject::GetAttachedId(GLenum attachment) {
_GuardedBind();
GLint id = 0;
glGetFramebufferAttachmentParameterivEXT(
GL_FRAMEBUFFER_EXT, attachment, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT,
&id);
_GuardedUnbind();
return GLuint(id);
GLuint FramebufferObject::GetAttachedId(GLenum attachment)
{
_GuardedBind();
GLint id = 0;
glGetFramebufferAttachmentParameterivEXT(
GL_FRAMEBUFFER_EXT, attachment, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT, &id);
_GuardedUnbind();
return GLuint(id);
}
GLint FramebufferObject::GetAttachedMipLevel(GLenum attachment) {
_GuardedBind();
GLint level = 0;
glGetFramebufferAttachmentParameterivEXT(
GL_FRAMEBUFFER_EXT, attachment,
GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT, &level);
_GuardedUnbind();
return level;
GLint FramebufferObject::GetAttachedMipLevel(GLenum attachment)
{
_GuardedBind();
GLint level = 0;
glGetFramebufferAttachmentParameterivEXT(
GL_FRAMEBUFFER_EXT, attachment, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT, &level);
_GuardedUnbind();
return level;
}
GLint FramebufferObject::GetAttachedCubeFace(GLenum attachment) {
_GuardedBind();
GLint level = 0;
glGetFramebufferAttachmentParameterivEXT(
GL_FRAMEBUFFER_EXT, attachment,
GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT, &level);
_GuardedUnbind();
return level;
GLint FramebufferObject::GetAttachedCubeFace(GLenum attachment)
{
_GuardedBind();
GLint level = 0;
glGetFramebufferAttachmentParameterivEXT(
GL_FRAMEBUFFER_EXT, attachment, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT, &level);
_GuardedUnbind();
return level;
}
GLint FramebufferObject::GetAttachedZSlice(GLenum attachment) {
_GuardedBind();
GLint slice = 0;
glGetFramebufferAttachmentParameterivEXT(
GL_FRAMEBUFFER_EXT, attachment,
GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT, &slice);
_GuardedUnbind();
return slice;
GLint FramebufferObject::GetAttachedZSlice(GLenum attachment)
{
_GuardedBind();
GLint slice = 0;
glGetFramebufferAttachmentParameterivEXT(
GL_FRAMEBUFFER_EXT, attachment, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT, &slice);
_GuardedUnbind();
return slice;
}

View File

@@ -69,6 +69,7 @@
#ifndef UCDAVIS_FRAMEBUFFER_OBJECT_H
#define UCDAVIS_FRAMEBUFFER_OBJECT_H
#include <helper_gl.h>
#include <iostream>
/*!
@@ -126,43 +127,47 @@ Performance Notes:
// OpenGL framebuffer.
FramebufferObject::Disable();
*/
class FramebufferObject {
public:
/// Ctor/Dtor
FramebufferObject();
virtual ~FramebufferObject();
class FramebufferObject
{
public:
/// Ctor/Dtor
FramebufferObject();
virtual ~FramebufferObject();
/// Bind this FBO as current render target
void Bind();
/// Bind this FBO as current render target
void Bind();
/// Bind a texture to the "attachment" point of this FBO
virtual void AttachTexture(GLenum texTarget, GLuint texId,
GLenum attachment = GL_COLOR_ATTACHMENT0_EXT,
int mipLevel = 0, int zSlice = 0);
/// Bind a texture to the "attachment" point of this FBO
virtual void AttachTexture(GLenum texTarget,
GLuint texId,
GLenum attachment = GL_COLOR_ATTACHMENT0_EXT,
int mipLevel = 0,
int zSlice = 0);
/// Bind an array of textures to multiple "attachment" points of this FBO
/// - By default, the first 'numTextures' attachments are used,
/// starting with GL_COLOR_ATTACHMENT0_EXT
virtual void AttachTextures(int numTextures, GLenum texTarget[],
GLuint texId[], GLenum attachment[] = NULL,
int mipLevel[] = NULL, int zSlice[] = NULL);
/// Bind an array of textures to multiple "attachment" points of this FBO
/// - By default, the first 'numTextures' attachments are used,
/// starting with GL_COLOR_ATTACHMENT0_EXT
virtual void AttachTextures(int numTextures,
GLenum texTarget[],
GLuint texId[],
GLenum attachment[] = NULL,
int mipLevel[] = NULL,
int zSlice[] = NULL);
/// Bind a render buffer to the "attachment" point of this FBO
virtual void AttachRenderBuffer(GLuint buffId,
GLenum attachment = GL_COLOR_ATTACHMENT0_EXT);
/// Bind a render buffer to the "attachment" point of this FBO
virtual void AttachRenderBuffer(GLuint buffId, GLenum attachment = GL_COLOR_ATTACHMENT0_EXT);
/// Bind an array of render buffers to corresponding "attachment" points
/// of this FBO.
/// - By default, the first 'numBuffers' attachments are used,
/// starting with GL_COLOR_ATTACHMENT0_EXT
virtual void AttachRenderBuffers(int numBuffers, GLuint buffId[],
GLenum attachment[] = NULL);
/// Bind an array of render buffers to corresponding "attachment" points
/// of this FBO.
/// - By default, the first 'numBuffers' attachments are used,
/// starting with GL_COLOR_ATTACHMENT0_EXT
virtual void AttachRenderBuffers(int numBuffers, GLuint buffId[], GLenum attachment[] = NULL);
/// Free any resource bound to the "attachment" point of this FBO
void Unattach(GLenum attachment);
/// Free any resource bound to the "attachment" point of this FBO
void Unattach(GLenum attachment);
/// Free any resources bound to any attachment points of this FBO
void UnattachAll();
/// Free any resources bound to any attachment points of this FBO
void UnattachAll();
/// Is this FBO currently a valid render target?
/// - Sends output to std::cerr by default but can
@@ -172,55 +177,54 @@ class FramebufferObject {
/// mode but always returns "true" if NDEBUG is
/// is defined (optimized builds)
#ifndef NDEBUG
bool IsValid(std::ostream &ostr = std::cerr);
bool IsValid(std::ostream &ostr = std::cerr);
#else
bool IsValid(std::ostream &ostr = std::cerr) { return true; }
bool IsValid(std::ostream &ostr = std::cerr) { return true; }
#endif
/// BEGIN : Accessors
/// Is attached type GL_RENDERBUFFER_EXT or GL_TEXTURE?
GLenum GetAttachedType(GLenum attachment);
/// BEGIN : Accessors
/// Is attached type GL_RENDERBUFFER_EXT or GL_TEXTURE?
GLenum GetAttachedType(GLenum attachment);
/// What is the Id of Renderbuffer/texture currently
/// attached to "attachment?"
GLuint GetAttachedId(GLenum attachment);
/// What is the Id of Renderbuffer/texture currently
/// attached to "attachment?"
GLuint GetAttachedId(GLenum attachment);
/// Which mipmap level is currently attached to "attachment?"
GLint GetAttachedMipLevel(GLenum attachment);
/// Which mipmap level is currently attached to "attachment?"
GLint GetAttachedMipLevel(GLenum attachment);
/// Which cube face is currently attached to "attachment?"
GLint GetAttachedCubeFace(GLenum attachment);
/// Which cube face is currently attached to "attachment?"
GLint GetAttachedCubeFace(GLenum attachment);
/// Which z-slice is currently attached to "attachment?"
GLint GetAttachedZSlice(GLenum attachment);
/// END : Accessors
/// Which z-slice is currently attached to "attachment?"
GLint GetAttachedZSlice(GLenum attachment);
/// END : Accessors
/// BEGIN : Static methods global to all FBOs
/// Return number of color attachments permitted
static int GetMaxColorAttachments();
/// BEGIN : Static methods global to all FBOs
/// Return number of color attachments permitted
static int GetMaxColorAttachments();
/// Disable all FBO rendering and return to traditional,
/// windowing-system controlled framebuffer
/// NOTE:
/// This is NOT an "unbind" for this specific FBO, but rather
/// disables all FBO rendering. This call is intentionally "static"
/// and named "Disable" instead of "Unbind" for this reason. The
/// motivation for this strange semantic is performance. Providing
/// "Unbind" would likely lead to a large number of unnecessary
/// FBO enabling/disabling.
static void Disable();
/// END : Static methods global to all FBOs
/// Disable all FBO rendering and return to traditional,
/// windowing-system controlled framebuffer
/// NOTE:
/// This is NOT an "unbind" for this specific FBO, but rather
/// disables all FBO rendering. This call is intentionally "static"
/// and named "Disable" instead of "Unbind" for this reason. The
/// motivation for this strange semantic is performance. Providing
/// "Unbind" would likely lead to a large number of unnecessary
/// FBO enabling/disabling.
static void Disable();
/// END : Static methods global to all FBOs
protected:
void _GuardedBind();
void _GuardedUnbind();
void _FramebufferTextureND(GLenum attachment, GLenum texTarget, GLuint texId,
int mipLevel, int zSlice);
static GLuint _GenerateFboId();
protected:
void _GuardedBind();
void _GuardedUnbind();
void _FramebufferTextureND(GLenum attachment, GLenum texTarget, GLuint texId, int mipLevel, int zSlice);
static GLuint _GenerateFboId();
private:
GLuint m_fboId;
GLint m_savedFboId;
private:
GLuint m_fboId;
GLint m_savedFboId;
};
#endif

View File

@@ -61,29 +61,29 @@
#define NV_MATH_H
#include <math.h>
#include <nvVector.h>
#include <nvMatrix.h>
#include <nvQuaternion.h>
#include <nvVector.h>
#define NV_PI float(3.1415926535897932384626433832795)
namespace nv {
typedef vec2<float> vec2f;
typedef vec3<float> vec3f;
typedef vec3<int> vec3i;
typedef vec2<float> vec2f;
typedef vec3<float> vec3f;
typedef vec3<int> vec3i;
typedef vec3<unsigned int> vec3ui;
typedef vec4<float> vec4f;
typedef matrix4<float> matrix4f;
typedef quaternion<float> quaternionf;
typedef vec4<float> vec4f;
typedef matrix4<float> matrix4f;
typedef quaternion<float> quaternionf;
inline void applyRotation(const quaternionf &r) {
float angle;
vec3f axis;
r.get_value(axis, angle);
glRotatef(angle / 3.1415926f * 180.0f, axis[0], axis[1], axis[2]);
inline void applyRotation(const quaternionf &r)
{
float angle;
vec3f axis;
r.get_value(axis, angle);
glRotatef(angle / 3.1415926f * 180.0f, axis[0], axis[1], axis[2]);
}
};
}; // namespace nv
#endif

View File

@@ -64,383 +64,419 @@
namespace nv {
template <class T>
class vec2;
template <class T>
class vec3;
template <class T>
class vec4;
template <class T> class vec2;
template <class T> class vec3;
template <class T> class vec4;
////////////////////////////////////////////////////////////////////////////////
//
// Matrix
//
////////////////////////////////////////////////////////////////////////////////
template <class T>
class matrix4 {
public:
matrix4() { make_identity(); }
template <class T> class matrix4
{
public:
matrix4() { make_identity(); }
matrix4(T t) { set_value(t); }
matrix4(T t) { set_value(t); }
matrix4(const T *m) { set_value(m); }
matrix4(const T *m) { set_value(m); }
matrix4(T a00, T a01, T a02, T a03, T a10, T a11, T a12, T a13, T a20, T a21,
T a22, T a23, T a30, T a31, T a32, T a33)
: _11(a00),
_12(a01),
_13(a02),
_14(a03),
_21(a10),
_22(a11),
_23(a12),
_24(a13),
_31(a20),
_32(a21),
_33(a22),
_34(a23),
_41(a30),
_42(a31),
_43(a32),
_44(a33) {}
void get_value(T *mp) const {
int c = 0;
for (int j = 0; j < 4; j++)
for (int i = 0; i < 4; i++) {
mp[c++] = element(i, j);
}
}
const T *get_value() const { return _array; }
void set_value(T *mp) {
int c = 0;
for (int j = 0; j < 4; j++)
for (int i = 0; i < 4; i++) {
element(i, j) = mp[c++];
}
}
void set_value(T r) {
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++) {
element(i, j) = r;
}
}
void make_identity() {
element(0, 0) = 1.0;
element(0, 1) = 0.0;
element(0, 2) = 0.0;
element(0, 3) = 0.0;
element(1, 0) = 0.0;
element(1, 1) = 1.0;
element(1, 2) = 0.0;
element(1, 3) = 0.0;
element(2, 0) = 0.0;
element(2, 1) = 0.0;
element(2, 2) = 1.0;
element(2, 3) = 0.0;
element(3, 0) = 0.0;
element(3, 1) = 0.0;
element(3, 2) = 0.0;
element(3, 3) = 1.0;
}
// set a uniform scale
void set_scale(T s) {
element(0, 0) = s;
element(1, 1) = s;
element(2, 2) = s;
}
void set_scale(const vec3<T> &s) {
for (int i = 0; i < 3; i++) {
element(i, i) = s[i];
}
}
void set_translate(const vec3<T> &t) {
for (int i = 0; i < 3; i++) {
element(i, 3) = t[i];
}
}
void set_row(int r, const vec4<T> &t) {
for (int i = 0; i < 4; i++) {
element(r, i) = t[i];
}
}
void set_column(int c, const vec4<T> &t) {
for (int i = 0; i < 4; i++) {
element(i, c) = t[i];
}
}
vec4<T> get_row(int r) const {
vec4<T> v;
for (int i = 0; i < 4; i++) {
v[i] = element(r, i);
matrix4(T a00,
T a01,
T a02,
T a03,
T a10,
T a11,
T a12,
T a13,
T a20,
T a21,
T a22,
T a23,
T a30,
T a31,
T a32,
T a33)
: _11(a00)
, _12(a01)
, _13(a02)
, _14(a03)
, _21(a10)
, _22(a11)
, _23(a12)
, _24(a13)
, _31(a20)
, _32(a21)
, _33(a22)
, _34(a23)
, _41(a30)
, _42(a31)
, _43(a32)
, _44(a33)
{
}
return v;
}
void get_value(T *mp) const
{
int c = 0;
vec4<T> get_column(int c) const {
vec4<T> v;
for (int i = 0; i < 4; i++) {
v[i] = element(i, c);
for (int j = 0; j < 4; j++)
for (int i = 0; i < 4; i++) {
mp[c++] = element(i, j);
}
}
return v;
}
const T *get_value() const { return _array; }
friend matrix4 inverse(const matrix4 &m) {
matrix4 minv;
void set_value(T *mp)
{
int c = 0;
T r1[8], r2[8], r3[8], r4[8];
T *s[4], *tmprow;
for (int j = 0; j < 4; j++)
for (int i = 0; i < 4; i++) {
element(i, j) = mp[c++];
}
}
s[0] = &r1[0];
s[1] = &r2[0];
s[2] = &r3[0];
s[3] = &r4[0];
void set_value(T r)
{
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++) {
element(i, j) = r;
}
}
register int i, j, p, jj;
void make_identity()
{
element(0, 0) = 1.0;
element(0, 1) = 0.0;
element(0, 2) = 0.0;
element(0, 3) = 0.0;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
s[i][j] = m.element(i, j);
element(1, 0) = 0.0;
element(1, 1) = 1.0;
element(1, 2) = 0.0;
element(1, 3) = 0.0;
if (i == j) {
s[i][j + 4] = 1.0;
} else {
s[i][j + 4] = 0.0;
element(2, 0) = 0.0;
element(2, 1) = 0.0;
element(2, 2) = 1.0;
element(2, 3) = 0.0;
element(3, 0) = 0.0;
element(3, 1) = 0.0;
element(3, 2) = 0.0;
element(3, 3) = 1.0;
}
// set a uniform scale
void set_scale(T s)
{
element(0, 0) = s;
element(1, 1) = s;
element(2, 2) = s;
}
void set_scale(const vec3<T> &s)
{
for (int i = 0; i < 3; i++) {
element(i, i) = s[i];
}
}
}
T scp[4];
void set_translate(const vec3<T> &t)
{
for (int i = 0; i < 3; i++) {
element(i, 3) = t[i];
}
}
for (i = 0; i < 4; i++) {
scp[i] = T(fabs(s[i][0]));
void set_row(int r, const vec4<T> &t)
{
for (int i = 0; i < 4; i++) {
element(r, i) = t[i];
}
}
for (j = 1; j < 4; j++)
if (T(fabs(s[i][j])) > scp[i]) {
scp[i] = T(fabs(s[i][j]));
void set_column(int c, const vec4<T> &t)
{
for (int i = 0; i < 4; i++) {
element(i, c) = t[i];
}
}
vec4<T> get_row(int r) const
{
vec4<T> v;
for (int i = 0; i < 4; i++) {
v[i] = element(r, i);
}
if (scp[i] == 0.0) {
return minv; // singular matrix!
}
return v;
}
int pivot_to;
T scp_max;
vec4<T> get_column(int c) const
{
vec4<T> v;
for (i = 0; i < 4; i++) {
// select pivot row
pivot_to = i;
scp_max = T(fabs(s[i][i] / scp[i]));
// find out which row should be on top
for (p = i + 1; p < 4; p++)
if (T(fabs(s[p][i] / scp[p])) > scp_max) {
scp_max = T(fabs(s[p][i] / scp[p]));
pivot_to = p;
for (int i = 0; i < 4; i++) {
v[i] = element(i, c);
}
// Pivot if necessary
if (pivot_to != i) {
tmprow = s[i];
s[i] = s[pivot_to];
s[pivot_to] = tmprow;
T tmpscp;
tmpscp = scp[i];
scp[i] = scp[pivot_to];
scp[pivot_to] = tmpscp;
}
T mji;
// perform gaussian elimination
for (j = i + 1; j < 4; j++) {
mji = s[j][i] / s[i][i];
s[j][i] = 0.0;
for (jj = i + 1; jj < 8; jj++) {
s[j][jj] -= mji * s[i][jj];
}
}
return v;
}
if (s[3][3] == 0.0) {
return minv; // singular matrix!
}
friend matrix4 inverse(const matrix4 &m)
{
matrix4 minv;
//
// Now we have an upper triangular matrix.
//
// x x x x | y y y y
// 0 x x x | y y y y
// 0 0 x x | y y y y
// 0 0 0 x | y y y y
//
// we'll back substitute to get the inverse
//
// 1 0 0 0 | z z z z
// 0 1 0 0 | z z z z
// 0 0 1 0 | z z z z
// 0 0 0 1 | z z z z
//
T r1[8], r2[8], r3[8], r4[8];
T *s[4], *tmprow;
T mij;
s[0] = &r1[0];
s[1] = &r2[0];
s[2] = &r3[0];
s[3] = &r4[0];
for (i = 3; i > 0; i--) {
for (j = i - 1; j > -1; j--) {
mij = s[j][i] / s[i][i];
register int i, j, p, jj;
for (jj = j + 1; jj < 8; jj++) {
s[j][jj] -= mij * s[i][jj];
}
}
}
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
s[i][j] = m.element(i, j);
for (i = 0; i < 4; i++)
for (j = 0; j < 4; j++) {
minv(i, j) = s[i][j + 4] / s[i][i];
}
return minv;
}
friend matrix4 transpose(const matrix4 &m) {
matrix4 mtrans;
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++) {
mtrans(i, j) = m.element(j, i);
}
return mtrans;
}
matrix4 &operator*=(const matrix4 &rhs) {
matrix4 mt(*this);
set_value(T(0));
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
for (int c = 0; c < 4; c++) {
element(i, j) += mt(i, c) * rhs(c, j);
if (i == j) {
s[i][j + 4] = 1.0;
}
else {
s[i][j + 4] = 0.0;
}
}
}
return *this;
}
T scp[4];
friend matrix4 operator*(const matrix4 &lhs, const matrix4 &rhs) {
matrix4 r(T(0));
for (i = 0; i < 4; i++) {
scp[i] = T(fabs(s[i][0]));
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
for (int c = 0; c < 4; c++) {
r.element(i, j) += lhs(i, c) * rhs(c, j);
for (j = 1; j < 4; j++)
if (T(fabs(s[i][j])) > scp[i]) {
scp[i] = T(fabs(s[i][j]));
}
if (scp[i] == 0.0) {
return minv; // singular matrix!
}
}
return r;
}
int pivot_to;
T scp_max;
// dst = M * src
vec4<T> operator*(const vec4<T> &src) const {
vec4<T> r;
for (i = 0; i < 4; i++) {
// select pivot row
pivot_to = i;
scp_max = T(fabs(s[i][i] / scp[i]));
for (int i = 0; i < 4; i++)
r[i] = (src[0] * element(i, 0) + src[1] * element(i, 1) +
src[2] * element(i, 2) + src[3] * element(i, 3));
// find out which row should be on top
for (p = i + 1; p < 4; p++)
if (T(fabs(s[p][i] / scp[p])) > scp_max) {
scp_max = T(fabs(s[p][i] / scp[p]));
pivot_to = p;
}
return r;
}
// Pivot if necessary
if (pivot_to != i) {
tmprow = s[i];
s[i] = s[pivot_to];
s[pivot_to] = tmprow;
T tmpscp;
tmpscp = scp[i];
scp[i] = scp[pivot_to];
scp[pivot_to] = tmpscp;
}
// dst = src * M
friend vec4<T> operator*(const vec4<T> &lhs, const matrix4 &rhs) {
vec4<T> r;
T mji;
for (int i = 0; i < 4; i++)
r[i] = (lhs[0] * rhs.element(0, i) + lhs[1] * rhs.element(1, i) +
lhs[2] * rhs.element(2, i) + lhs[3] * rhs.element(3, i));
// perform gaussian elimination
for (j = i + 1; j < 4; j++) {
mji = s[j][i] / s[i][i];
s[j][i] = 0.0;
return r;
}
for (jj = i + 1; jj < 8; jj++) {
s[j][jj] -= mji * s[i][jj];
}
}
}
T &operator()(int row, int col) { return element(row, col); }
if (s[3][3] == 0.0) {
return minv; // singular matrix!
}
const T &operator()(int row, int col) const { return element(row, col); }
//
// Now we have an upper triangular matrix.
//
// x x x x | y y y y
// 0 x x x | y y y y
// 0 0 x x | y y y y
// 0 0 0 x | y y y y
//
// we'll back substitute to get the inverse
//
// 1 0 0 0 | z z z z
// 0 1 0 0 | z z z z
// 0 0 1 0 | z z z z
// 0 0 0 1 | z z z z
//
T &element(int row, int col) { return _array[row | (col << 2)]; }
T mij;
const T &element(int row, int col) const { return _array[row | (col << 2)]; }
for (i = 3; i > 0; i--) {
for (j = i - 1; j > -1; j--) {
mij = s[j][i] / s[i][i];
matrix4 &operator*=(const T &r) {
for (int i = 0; i < 4; ++i) {
element(0, i) *= r;
element(1, i) *= r;
element(2, i) *= r;
element(3, i) *= r;
for (jj = j + 1; jj < 8; jj++) {
s[j][jj] -= mij * s[i][jj];
}
}
}
for (i = 0; i < 4; i++)
for (j = 0; j < 4; j++) {
minv(i, j) = s[i][j + 4] / s[i][i];
}
return minv;
}
return *this;
}
friend matrix4 transpose(const matrix4 &m)
{
matrix4 mtrans;
matrix4 &operator+=(const matrix4 &mat) {
for (int i = 0; i < 4; ++i) {
element(0, i) += mat.element(0, i);
element(1, i) += mat.element(1, i);
element(2, i) += mat.element(2, i);
element(3, i) += mat.element(3, i);
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++) {
mtrans(i, j) = m.element(j, i);
}
return mtrans;
}
return *this;
}
matrix4 &operator*=(const matrix4 &rhs)
{
matrix4 mt(*this);
set_value(T(0));
friend bool operator==(const matrix4 &lhs, const matrix4 &rhs) {
bool r = true;
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
for (int c = 0; c < 4; c++) {
element(i, j) += mt(i, c) * rhs(c, j);
}
for (int i = 0; i < 16; i++) {
r &= lhs._array[i] == rhs._array[i];
return *this;
}
return r;
}
friend matrix4 operator*(const matrix4 &lhs, const matrix4 &rhs)
{
matrix4 r(T(0));
friend bool operator!=(const matrix4 &lhs, const matrix4 &rhs) {
bool r = true;
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
for (int c = 0; c < 4; c++) {
r.element(i, j) += lhs(i, c) * rhs(c, j);
}
for (int i = 0; i < 16; i++) {
r &= lhs._array[i] != rhs._array[i];
return r;
}
return r;
}
// dst = M * src
vec4<T> operator*(const vec4<T> &src) const
{
vec4<T> r;
union {
struct {
T _11, _12, _13, _14; // standard names for components
T _21, _22, _23, _24; // standard names for components
T _31, _32, _33, _34; // standard names for components
T _41, _42, _43, _44; // standard names for components
for (int i = 0; i < 4; i++)
r[i] = (src[0] * element(i, 0) + src[1] * element(i, 1) + src[2] * element(i, 2) + src[3] * element(i, 3));
return r;
}
// dst = src * M
friend vec4<T> operator*(const vec4<T> &lhs, const matrix4 &rhs)
{
vec4<T> r;
for (int i = 0; i < 4; i++)
r[i] = (lhs[0] * rhs.element(0, i) + lhs[1] * rhs.element(1, i) + lhs[2] * rhs.element(2, i)
+ lhs[3] * rhs.element(3, i));
return r;
}
T &operator()(int row, int col) { return element(row, col); }
const T &operator()(int row, int col) const { return element(row, col); }
T &element(int row, int col) { return _array[row | (col << 2)]; }
const T &element(int row, int col) const { return _array[row | (col << 2)]; }
matrix4 &operator*=(const T &r)
{
for (int i = 0; i < 4; ++i) {
element(0, i) *= r;
element(1, i) *= r;
element(2, i) *= r;
element(3, i) *= r;
}
return *this;
}
matrix4 &operator+=(const matrix4 &mat)
{
for (int i = 0; i < 4; ++i) {
element(0, i) += mat.element(0, i);
element(1, i) += mat.element(1, i);
element(2, i) += mat.element(2, i);
element(3, i) += mat.element(3, i);
}
return *this;
}
friend bool operator==(const matrix4 &lhs, const matrix4 &rhs)
{
bool r = true;
for (int i = 0; i < 16; i++) {
r &= lhs._array[i] == rhs._array[i];
}
return r;
}
friend bool operator!=(const matrix4 &lhs, const matrix4 &rhs)
{
bool r = true;
for (int i = 0; i < 16; i++) {
r &= lhs._array[i] != rhs._array[i];
}
return r;
}
union
{
struct
{
T _11, _12, _13, _14; // standard names for components
T _21, _22, _23, _24; // standard names for components
T _31, _32, _33, _34; // standard names for components
T _41, _42, _43, _44; // standard names for components
};
T _array[16]; // array access
};
T _array[16]; // array access
};
};
};
}; // namespace nv
#endif

View File

@@ -63,12 +63,9 @@
namespace nv {
template <class T>
class vec2;
template <class T>
class vec3;
template <class T>
class vec4;
template <class T> class vec2;
template <class T> class vec3;
template <class T> class vec4;
////////////////////////////////////////////////////////////////////////////////
//
@@ -76,363 +73,383 @@ class vec4;
//
////////////////////////////////////////////////////////////////////////////////
template <class T>
class quaternion {
public:
quaternion() : x(0.0), y(0.0), z(0.0), w(0.0) {}
quaternion(const T v[4]) { set_value(v); }
quaternion(T q0, T q1, T q2, T q3) { set_value(q0, q1, q2, q3); }
quaternion(const matrix4<T> &m) { set_value(m); }
quaternion(const vec3<T> &axis, T radians) { set_value(axis, radians); }
quaternion(const vec3<T> &rotateFrom, const vec3<T> &rotateTo) {
set_value(rotateFrom, rotateTo);
}
quaternion(const vec3<T> &from_look, const vec3<T> &from_up,
const vec3<T> &to_look, const vec3<T> &to_up) {
set_value(from_look, from_up, to_look, to_up);
}
const T *get_value() const { return &_array[0]; }
void get_value(T &q0, T &q1, T &q2, T &q3) const {
q0 = _array[0];
q1 = _array[1];
q2 = _array[2];
q3 = _array[3];
}
quaternion &set_value(T q0, T q1, T q2, T q3) {
_array[0] = q0;
_array[1] = q1;
_array[2] = q2;
_array[3] = q3;
return *this;
}
void get_value(vec3<T> &axis, T &radians) const {
radians = T(acos(_array[3]) * T(2.0));
if (radians == T(0.0)) {
axis = vec3<T>(0.0, 0.0, 1.0);
} else {
axis[0] = _array[0];
axis[1] = _array[1];
axis[2] = _array[2];
axis = normalize(axis);
}
}
void get_value(matrix4<T> &m) const {
T s, xs, ys, zs, wx, wy, wz, xx, xy, xz, yy, yz, zz;
T norm = _array[0] * _array[0] + _array[1] * _array[1] +
_array[2] * _array[2] + _array[3] * _array[3];
s = (norm == T(0.0)) ? T(0.0) : (T(2.0) / norm);
xs = _array[0] * s;
ys = _array[1] * s;
zs = _array[2] * s;
wx = _array[3] * xs;
wy = _array[3] * ys;
wz = _array[3] * zs;
xx = _array[0] * xs;
xy = _array[0] * ys;
xz = _array[0] * zs;
yy = _array[1] * ys;
yz = _array[1] * zs;
zz = _array[2] * zs;
m(0, 0) = T(T(1.0) - (yy + zz));
m(1, 0) = T(xy + wz);
m(2, 0) = T(xz - wy);
m(0, 1) = T(xy - wz);
m(1, 1) = T(T(1.0) - (xx + zz));
m(2, 1) = T(yz + wx);
m(0, 2) = T(xz + wy);
m(1, 2) = T(yz - wx);
m(2, 2) = T(T(1.0) - (xx + yy));
m(3, 0) = m(3, 1) = m(3, 2) = m(0, 3) = m(1, 3) = m(2, 3) = T(0.0);
m(3, 3) = T(1.0);
}
quaternion &set_value(const T *qp) {
for (int i = 0; i < 4; i++) {
_array[i] = qp[i];
template <class T> class quaternion
{
public:
quaternion()
: x(0.0)
, y(0.0)
, z(0.0)
, w(0.0)
{
}
return *this;
}
quaternion(const T v[4]) { set_value(v); }
quaternion &set_value(const matrix4<T> &m) {
T tr, s;
int i, j, k;
const int nxt[3] = {1, 2, 0};
quaternion(T q0, T q1, T q2, T q3) { set_value(q0, q1, q2, q3); }
tr = m(0, 0) + m(1, 1) + m(2, 2);
quaternion(const matrix4<T> &m) { set_value(m); }
if (tr > T(0)) {
s = T(sqrt(tr + m(3, 3)));
_array[3] = T(s * 0.5);
s = T(0.5) / s;
quaternion(const vec3<T> &axis, T radians) { set_value(axis, radians); }
_array[0] = T((m(1, 2) - m(2, 1)) * s);
_array[1] = T((m(2, 0) - m(0, 2)) * s);
_array[2] = T((m(0, 1) - m(1, 0)) * s);
} else {
i = 0;
quaternion(const vec3<T> &rotateFrom, const vec3<T> &rotateTo) { set_value(rotateFrom, rotateTo); }
if (m(1, 1) > m(0, 0)) {
i = 1;
}
if (m(2, 2) > m(i, i)) {
i = 2;
}
j = nxt[i];
k = nxt[j];
s = T(sqrt((m(i, j) - (m(j, j) + m(k, k))) + T(1.0)));
_array[i] = T(s * 0.5);
s = T(0.5 / s);
_array[3] = T((m(j, k) - m(k, j)) * s);
_array[j] = T((m(i, j) + m(j, i)) * s);
_array[k] = T((m(i, k) + m(k, i)) * s);
quaternion(const vec3<T> &from_look, const vec3<T> &from_up, const vec3<T> &to_look, const vec3<T> &to_up)
{
set_value(from_look, from_up, to_look, to_up);
}
return *this;
}
const T *get_value() const { return &_array[0]; }
quaternion &set_value(const vec3<T> &axis, T theta) {
T sqnorm = square_norm(axis);
if (sqnorm == T(0.0)) {
// axis too small.
x = y = z = T(0.0);
w = T(1.0);
} else {
theta *= T(0.5);
T sin_theta = T(sin(theta));
if (sqnorm != T(1)) {
sin_theta /= T(sqrt(sqnorm));
}
x = sin_theta * axis[0];
y = sin_theta * axis[1];
z = sin_theta * axis[2];
w = T(cos(theta));
void get_value(T &q0, T &q1, T &q2, T &q3) const
{
q0 = _array[0];
q1 = _array[1];
q2 = _array[2];
q3 = _array[3];
}
return *this;
}
quaternion &set_value(const vec3<T> &rotateFrom, const vec3<T> &rotateTo) {
vec3<T> p1, p2;
T alpha;
p1 = normalize(rotateFrom);
p2 = normalize(rotateTo);
alpha = dot(p1, p2);
if (alpha == T(1.0)) {
*this = quaternion();
return *this;
quaternion &set_value(T q0, T q1, T q2, T q3)
{
_array[0] = q0;
_array[1] = q1;
_array[2] = q2;
_array[3] = q3;
return *this;
}
// ensures that the anti-parallel case leads to a positive dot
if (alpha == T(-1.0)) {
vec3<T> v;
void get_value(vec3<T> &axis, T &radians) const
{
radians = T(acos(_array[3]) * T(2.0));
if (p1[0] != p1[1] || p1[0] != p1[2]) {
v = vec3<T>(p1[1], p1[2], p1[0]);
} else {
v = vec3<T>(-p1[0], p1[1], p1[2]);
}
v -= p1 * dot(p1, v);
v = normalize(v);
set_value(v, T(3.1415926));
return *this;
if (radians == T(0.0)) {
axis = vec3<T>(0.0, 0.0, 1.0);
}
else {
axis[0] = _array[0];
axis[1] = _array[1];
axis[2] = _array[2];
axis = normalize(axis);
}
}
p1 = normalize(cross(p1, p2));
void get_value(matrix4<T> &m) const
{
T s, xs, ys, zs, wx, wy, wz, xx, xy, xz, yy, yz, zz;
set_value(p1, T(acos(alpha)));
T norm = _array[0] * _array[0] + _array[1] * _array[1] + _array[2] * _array[2] + _array[3] * _array[3];
return *this;
}
s = (norm == T(0.0)) ? T(0.0) : (T(2.0) / norm);
quaternion &set_value(const vec3<T> &from_look, const vec3<T> &from_up,
const vec3<T> &to_look, const vec3<T> &to_up) {
quaternion r_look = quaternion(from_look, to_look);
xs = _array[0] * s;
ys = _array[1] * s;
zs = _array[2] * s;
vec3<T> rotated_from_up(from_up);
r_look.mult_vec(rotated_from_up);
wx = _array[3] * xs;
wy = _array[3] * ys;
wz = _array[3] * zs;
quaternion r_twist = quaternion(rotated_from_up, to_up);
xx = _array[0] * xs;
xy = _array[0] * ys;
xz = _array[0] * zs;
*this = r_twist;
*this *= r_look;
return *this;
}
yy = _array[1] * ys;
yz = _array[1] * zs;
zz = _array[2] * zs;
quaternion &operator*=(const quaternion<T> &qr) {
quaternion ql(*this);
m(0, 0) = T(T(1.0) - (yy + zz));
m(1, 0) = T(xy + wz);
m(2, 0) = T(xz - wy);
w = ql.w * qr.w - ql.x * qr.x - ql.y * qr.y - ql.z * qr.z;
x = ql.w * qr.x + ql.x * qr.w + ql.y * qr.z - ql.z * qr.y;
y = ql.w * qr.y + ql.y * qr.w + ql.z * qr.x - ql.x * qr.z;
z = ql.w * qr.z + ql.z * qr.w + ql.x * qr.y - ql.y * qr.x;
m(0, 1) = T(xy - wz);
m(1, 1) = T(T(1.0) - (xx + zz));
m(2, 1) = T(yz + wx);
return *this;
}
m(0, 2) = T(xz + wy);
m(1, 2) = T(yz - wx);
m(2, 2) = T(T(1.0) - (xx + yy));
friend quaternion normalize(const quaternion<T> &q) {
quaternion r(q);
T rnorm = T(1.0) / T(sqrt(q.w * q.w + q.x * q.x + q.y * q.y + q.z * q.z));
r.x *= rnorm;
r.y *= rnorm;
r.z *= rnorm;
r.w *= rnorm;
}
friend quaternion<T> conjugate(const quaternion<T> &q) {
quaternion<T> r(q);
r._array[0] *= T(-1.0);
r._array[1] *= T(-1.0);
r._array[2] *= T(-1.0);
return r;
}
friend quaternion<T> inverse(const quaternion<T> &q) { return conjugate(q); }
//
// Quaternion multiplication with cartesian vector
// v' = q*v*q(star)
//
void mult_vec(const vec3<T> &src, vec3<T> &dst) const {
T v_coef = w * w - x * x - y * y - z * z;
T u_coef = T(2.0) * (src[0] * x + src[1] * y + src[2] * z);
T c_coef = T(2.0) * w;
dst.v[0] =
v_coef * src.v[0] + u_coef * x + c_coef * (y * src.v[2] - z * src.v[1]);
dst.v[1] =
v_coef * src.v[1] + u_coef * y + c_coef * (z * src.v[0] - x * src.v[2]);
dst.v[2] =
v_coef * src.v[2] + u_coef * z + c_coef * (x * src.v[1] - y * src.v[0]);
}
void mult_vec(vec3<T> &src_and_dst) const {
mult_vec(vec3<T>(src_and_dst), src_and_dst);
}
void scale_angle(T scaleFactor) {
vec3<T> axis;
T radians;
get_value(axis, radians);
radians *= scaleFactor;
set_value(axis, radians);
}
friend quaternion<T> slerp(const quaternion<T> &p, const quaternion<T> &q,
T alpha) {
quaternion r;
T cos_omega = p.x * q.x + p.y * q.y + p.z * q.z + p.w * q.w;
// if B is on opposite hemisphere from A, use -B instead
int bflip;
if ((bflip = (cos_omega < T(0)))) {
cos_omega = -cos_omega;
m(3, 0) = m(3, 1) = m(3, 2) = m(0, 3) = m(1, 3) = m(2, 3) = T(0.0);
m(3, 3) = T(1.0);
}
// complementary interpolation parameter
T beta = T(1) - alpha;
quaternion &set_value(const T *qp)
{
for (int i = 0; i < 4; i++) {
_array[i] = qp[i];
}
if (cos_omega >= T(1)) {
return p;
return *this;
}
T omega = T(acos(cos_omega));
T one_over_sin_omega = T(1.0) / T(sin(omega));
quaternion &set_value(const matrix4<T> &m)
{
T tr, s;
int i, j, k;
const int nxt[3] = {1, 2, 0};
beta = T(sin(omega * beta) * one_over_sin_omega);
alpha = T(sin(omega * alpha) * one_over_sin_omega);
tr = m(0, 0) + m(1, 1) + m(2, 2);
if (bflip) {
alpha = -alpha;
if (tr > T(0)) {
s = T(sqrt(tr + m(3, 3)));
_array[3] = T(s * 0.5);
s = T(0.5) / s;
_array[0] = T((m(1, 2) - m(2, 1)) * s);
_array[1] = T((m(2, 0) - m(0, 2)) * s);
_array[2] = T((m(0, 1) - m(1, 0)) * s);
}
else {
i = 0;
if (m(1, 1) > m(0, 0)) {
i = 1;
}
if (m(2, 2) > m(i, i)) {
i = 2;
}
j = nxt[i];
k = nxt[j];
s = T(sqrt((m(i, j) - (m(j, j) + m(k, k))) + T(1.0)));
_array[i] = T(s * 0.5);
s = T(0.5 / s);
_array[3] = T((m(j, k) - m(k, j)) * s);
_array[j] = T((m(i, j) + m(j, i)) * s);
_array[k] = T((m(i, k) + m(k, i)) * s);
}
return *this;
}
r.x = beta * p._array[0] + alpha * q._array[0];
r.y = beta * p._array[1] + alpha * q._array[1];
r.z = beta * p._array[2] + alpha * q._array[2];
r.w = beta * p._array[3] + alpha * q._array[3];
return r;
}
quaternion &set_value(const vec3<T> &axis, T theta)
{
T sqnorm = square_norm(axis);
T &operator[](int i) { return _array[i]; }
if (sqnorm == T(0.0)) {
// axis too small.
x = y = z = T(0.0);
w = T(1.0);
}
else {
theta *= T(0.5);
T sin_theta = T(sin(theta));
const T &operator[](int i) const { return _array[i]; }
if (sqnorm != T(1)) {
sin_theta /= T(sqrt(sqnorm));
}
friend bool operator==(const quaternion<T> &lhs, const quaternion<T> &rhs) {
bool r = true;
x = sin_theta * axis[0];
y = sin_theta * axis[1];
z = sin_theta * axis[2];
w = T(cos(theta));
}
for (int i = 0; i < 4; i++) {
r &= lhs._array[i] == rhs._array[i];
return *this;
}
return r;
}
quaternion &set_value(const vec3<T> &rotateFrom, const vec3<T> &rotateTo)
{
vec3<T> p1, p2;
T alpha;
friend bool operator!=(const quaternion<T> &lhs, const quaternion<T> &rhs) {
bool r = true;
p1 = normalize(rotateFrom);
p2 = normalize(rotateTo);
for (int i = 0; i < 4; i++) {
r &= lhs._array[i] == rhs._array[i];
alpha = dot(p1, p2);
if (alpha == T(1.0)) {
*this = quaternion();
return *this;
}
// ensures that the anti-parallel case leads to a positive dot
if (alpha == T(-1.0)) {
vec3<T> v;
if (p1[0] != p1[1] || p1[0] != p1[2]) {
v = vec3<T>(p1[1], p1[2], p1[0]);
}
else {
v = vec3<T>(-p1[0], p1[1], p1[2]);
}
v -= p1 * dot(p1, v);
v = normalize(v);
set_value(v, T(3.1415926));
return *this;
}
p1 = normalize(cross(p1, p2));
set_value(p1, T(acos(alpha)));
return *this;
}
return r;
}
quaternion &
set_value(const vec3<T> &from_look, const vec3<T> &from_up, const vec3<T> &to_look, const vec3<T> &to_up)
{
quaternion r_look = quaternion(from_look, to_look);
friend quaternion<T> operator*(const quaternion<T> &lhs,
const quaternion<T> &rhs) {
quaternion r(lhs);
r *= rhs;
return r;
}
vec3<T> rotated_from_up(from_up);
r_look.mult_vec(rotated_from_up);
union {
struct {
T x;
T y;
T z;
T w;
quaternion r_twist = quaternion(rotated_from_up, to_up);
*this = r_twist;
*this *= r_look;
return *this;
}
quaternion &operator*=(const quaternion<T> &qr)
{
quaternion ql(*this);
w = ql.w * qr.w - ql.x * qr.x - ql.y * qr.y - ql.z * qr.z;
x = ql.w * qr.x + ql.x * qr.w + ql.y * qr.z - ql.z * qr.y;
y = ql.w * qr.y + ql.y * qr.w + ql.z * qr.x - ql.x * qr.z;
z = ql.w * qr.z + ql.z * qr.w + ql.x * qr.y - ql.y * qr.x;
return *this;
}
friend quaternion normalize(const quaternion<T> &q)
{
quaternion r(q);
T rnorm = T(1.0) / T(sqrt(q.w * q.w + q.x * q.x + q.y * q.y + q.z * q.z));
r.x *= rnorm;
r.y *= rnorm;
r.z *= rnorm;
r.w *= rnorm;
}
friend quaternion<T> conjugate(const quaternion<T> &q)
{
quaternion<T> r(q);
r._array[0] *= T(-1.0);
r._array[1] *= T(-1.0);
r._array[2] *= T(-1.0);
return r;
}
friend quaternion<T> inverse(const quaternion<T> &q) { return conjugate(q); }
//
// Quaternion multiplication with cartesian vector
// v' = q*v*q(star)
//
void mult_vec(const vec3<T> &src, vec3<T> &dst) const
{
T v_coef = w * w - x * x - y * y - z * z;
T u_coef = T(2.0) * (src[0] * x + src[1] * y + src[2] * z);
T c_coef = T(2.0) * w;
dst.v[0] = v_coef * src.v[0] + u_coef * x + c_coef * (y * src.v[2] - z * src.v[1]);
dst.v[1] = v_coef * src.v[1] + u_coef * y + c_coef * (z * src.v[0] - x * src.v[2]);
dst.v[2] = v_coef * src.v[2] + u_coef * z + c_coef * (x * src.v[1] - y * src.v[0]);
}
void mult_vec(vec3<T> &src_and_dst) const { mult_vec(vec3<T>(src_and_dst), src_and_dst); }
void scale_angle(T scaleFactor)
{
vec3<T> axis;
T radians;
get_value(axis, radians);
radians *= scaleFactor;
set_value(axis, radians);
}
friend quaternion<T> slerp(const quaternion<T> &p, const quaternion<T> &q, T alpha)
{
quaternion r;
T cos_omega = p.x * q.x + p.y * q.y + p.z * q.z + p.w * q.w;
// if B is on opposite hemisphere from A, use -B instead
int bflip;
if ((bflip = (cos_omega < T(0)))) {
cos_omega = -cos_omega;
}
// complementary interpolation parameter
T beta = T(1) - alpha;
if (cos_omega >= T(1)) {
return p;
}
T omega = T(acos(cos_omega));
T one_over_sin_omega = T(1.0) / T(sin(omega));
beta = T(sin(omega * beta) * one_over_sin_omega);
alpha = T(sin(omega * alpha) * one_over_sin_omega);
if (bflip) {
alpha = -alpha;
}
r.x = beta * p._array[0] + alpha * q._array[0];
r.y = beta * p._array[1] + alpha * q._array[1];
r.z = beta * p._array[2] + alpha * q._array[2];
r.w = beta * p._array[3] + alpha * q._array[3];
return r;
}
T &operator[](int i) { return _array[i]; }
const T &operator[](int i) const { return _array[i]; }
friend bool operator==(const quaternion<T> &lhs, const quaternion<T> &rhs)
{
bool r = true;
for (int i = 0; i < 4; i++) {
r &= lhs._array[i] == rhs._array[i];
}
return r;
}
friend bool operator!=(const quaternion<T> &lhs, const quaternion<T> &rhs)
{
bool r = true;
for (int i = 0; i < 4; i++) {
r &= lhs._array[i] == rhs._array[i];
}
return r;
}
friend quaternion<T> operator*(const quaternion<T> &lhs, const quaternion<T> &rhs)
{
quaternion r(lhs);
r *= rhs;
return r;
}
union
{
struct
{
T x;
T y;
T z;
T w;
};
T _array[4];
};
T _array[4];
};
};
};
}; // namespace nv
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -31,19 +31,21 @@
#include "vector_types.h"
typedef unsigned int uint;
struct SimParams {
float3 gravity;
float globalDamping;
float noiseFreq;
float noiseAmp;
float3 cursorPos;
struct SimParams
{
float3 gravity;
float globalDamping;
float noiseFreq;
float noiseAmp;
float3 cursorPos;
float time;
float3 noiseSpeed;
float time;
float3 noiseSpeed;
};
struct float4x4 {
float m[16];
struct float4x4
{
float m[16];
};
#endif

View File

@@ -35,6 +35,10 @@
#include "helper_math.h"
#include "math_constants.h"
#include "particles_kernel.cuh"
#include "thrust/device_ptr.h"
#include "thrust/for_each.h"
#include "thrust/iterator/zip_iterator.h"
#include "thrust/sort.h"
cudaTextureObject_t noiseTex;
// simulation parameters
@@ -43,76 +47,75 @@ __constant__ SimParams cudaParams;
// look up in 3D noise texture
__device__ float3 noise3D(float3 p, cudaTextureObject_t noiseTex)
{
float4 n = tex3D<float4>(noiseTex, p.x, p.y, p.z);
return make_float3(n.x, n.y, n.z);
float4 n = tex3D<float4>(noiseTex, p.x, p.y, p.z);
return make_float3(n.x, n.y, n.z);
}
// integrate particle attributes
struct integrate_functor
{
float deltaTime;
cudaTextureObject_t noiseTex;
float deltaTime;
cudaTextureObject_t noiseTex;
__host__ __device__ integrate_functor(float delta_time,
cudaTextureObject_t noise_Tex)
: deltaTime(delta_time), noiseTex(noise_Tex) {}
template <typename Tuple>
__device__ void operator()(Tuple t)
{
volatile float4 posData = thrust::get<2>(t);
volatile float4 velData = thrust::get<3>(t);
float3 pos = make_float3(posData.x, posData.y, posData.z);
float3 vel = make_float3(velData.x, velData.y, velData.z);
// update particle age
float age = posData.w;
float lifetime = velData.w;
if (age < lifetime)
__host__ __device__ integrate_functor(float delta_time, cudaTextureObject_t noise_Tex)
: deltaTime(delta_time)
, noiseTex(noise_Tex)
{
age += deltaTime;
}
else
{
age = lifetime;
}
// apply accelerations
vel += cudaParams.gravity * deltaTime;
template <typename Tuple> __device__ void operator()(Tuple t)
{
volatile float4 posData = thrust::get<2>(t);
volatile float4 velData = thrust::get<3>(t);
// apply procedural noise
float3 noise = noise3D(
pos * cudaParams.noiseFreq + cudaParams.time * cudaParams.noiseSpeed, noiseTex);
vel += noise * cudaParams.noiseAmp;
float3 pos = make_float3(posData.x, posData.y, posData.z);
float3 vel = make_float3(velData.x, velData.y, velData.z);
// new position = old position + velocity * deltaTime
pos += vel * deltaTime;
// update particle age
float age = posData.w;
float lifetime = velData.w;
vel *= cudaParams.globalDamping;
if (age < lifetime) {
age += deltaTime;
}
else {
age = lifetime;
}
// store new position and velocity
thrust::get<0>(t) = make_float4(pos, age);
thrust::get<1>(t) = make_float4(vel, velData.w);
}
// apply accelerations
vel += cudaParams.gravity * deltaTime;
// apply procedural noise
float3 noise = noise3D(pos * cudaParams.noiseFreq + cudaParams.time * cudaParams.noiseSpeed, noiseTex);
vel += noise * cudaParams.noiseAmp;
// new position = old position + velocity * deltaTime
pos += vel * deltaTime;
vel *= cudaParams.globalDamping;
// store new position and velocity
thrust::get<0>(t) = make_float4(pos, age);
thrust::get<1>(t) = make_float4(vel, velData.w);
}
};
struct calcDepth_functor
{
float3 sortVector;
float3 sortVector;
__host__ __device__ calcDepth_functor(float3 sort_vector)
: sortVector(sort_vector) {}
__host__ __device__ calcDepth_functor(float3 sort_vector)
: sortVector(sort_vector)
{
}
template <typename Tuple>
__host__ __device__ void operator()(Tuple t)
{
volatile float4 p = thrust::get<0>(t);
float key = -dot(make_float3(p.x, p.y, p.z),
sortVector); // project onto sort vector
thrust::get<1>(t) = key;
}
template <typename Tuple> __host__ __device__ void operator()(Tuple t)
{
volatile float4 p = thrust::get<0>(t);
float key = -dot(make_float3(p.x, p.y, p.z),
sortVector); // project onto sort vector
thrust::get<1>(t) = key;
}
};
#endif

View File

@@ -50,14 +50,16 @@
*/
#define HELPERGL_EXTERN_GL_FUNC_IMPLEMENTATION
#include <helper_gl.h>
#include "renderbuffer.h"
#include <helper_gl.h>
#include <iostream>
using namespace std;
Renderbuffer::Renderbuffer()
: m_bufId(_CreateBufferId())
{}
{
}
Renderbuffer::Renderbuffer(GLenum internalFormat, int width, int height)
: m_bufId(_CreateBufferId())
@@ -65,27 +67,17 @@ Renderbuffer::Renderbuffer(GLenum internalFormat, int width, int height)
Set(internalFormat, width, height);
}
Renderbuffer::~Renderbuffer()
{
glDeleteRenderbuffersEXT(1, &m_bufId);
}
Renderbuffer::~Renderbuffer() { glDeleteRenderbuffersEXT(1, &m_bufId); }
void Renderbuffer::Bind()
{
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_bufId);
}
void Renderbuffer::Bind() { glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_bufId); }
void Renderbuffer::Unbind()
{
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
}
void Renderbuffer::Unbind() { glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); }
void Renderbuffer::Set(GLenum internalFormat, int width, int height)
{
int maxSize = Renderbuffer::GetMaxSize();
if (width > maxSize || height > maxSize)
{
if (width > maxSize || height > maxSize) {
cerr << "Renderbuffer::Renderbuffer() ERROR:\n\t"
<< "Size too big (" << width << ", " << height << ")\n";
return;
@@ -95,8 +87,7 @@ void Renderbuffer::Set(GLenum internalFormat, int width, int height)
GLint savedId = 0;
glGetIntegerv(GL_RENDERBUFFER_BINDING_EXT, &savedId);
if (savedId != (GLint)m_bufId)
{
if (savedId != (GLint)m_bufId) {
Bind();
}
@@ -104,16 +95,12 @@ void Renderbuffer::Set(GLenum internalFormat, int width, int height)
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, internalFormat, width, height);
// Guarded unbind
if (savedId != (GLint)m_bufId)
{
if (savedId != (GLint)m_bufId) {
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, savedId);
}
}
GLuint Renderbuffer::GetId() const
{
return m_bufId;
}
GLuint Renderbuffer::GetId() const { return m_bufId; }
GLint Renderbuffer::GetMaxSize()
{
@@ -128,4 +115,3 @@ GLuint Renderbuffer::_CreateBufferId()
glGenRenderbuffersEXT(1, &id);
return id;
}

View File

@@ -85,23 +85,22 @@ Usage Notes:
*/
class Renderbuffer
{
public:
/// Ctors/Dtors
Renderbuffer();
Renderbuffer(GLenum internalFormat, int width, int height);
~Renderbuffer();
public:
/// Ctors/Dtors
Renderbuffer();
Renderbuffer(GLenum internalFormat, int width, int height);
~Renderbuffer();
void Bind();
void Unbind();
void Set(GLenum internalFormat, int width, int height);
GLuint GetId() const;
void Bind();
void Unbind();
void Set(GLenum internalFormat, int width, int height);
GLuint GetId() const;
static GLint GetMaxSize();
static GLint GetMaxSize();
private:
GLuint m_bufId;
static GLuint _CreateBufferId();
private:
GLuint m_bufId;
static GLuint _CreateBufferId();
};
#endif