我们正在尝试移植在cpu上计算的工作布料模拟,以便使用gpu上的着色器进行计算。基本概念如下:2个着色器通过,一个用于计算布料中每个点的位置,另一个用于绘制布料,并计算布料法线。我们正在使用2个FBO,其中3个纹理分别用于位置,前一个位置和法线。
在第一个着色器传递中,我们希望使用第一个FBO纹理作为输入,并将位置和先前位置写入第二个fbo纹理。 在第1步和第2步之间,我们提取位置数据并使用它来创建三角形的顶点数组而不是绘制步骤的奇点。 在第2遍中,我们使用新的顶点数组来绘制布料,并使用几何着色器重新计算法线,将其发送到片段着色器,最后将其输出到第二个FBO的法线纹理。然后FBO的交换位置为下一个循环。
这就是我们想要发生的事情。现在发生的事情是,在计算步骤中,对我们的纹理所写的内容似乎与我们的着色器中发生的内容完全无关,我们怀疑在绘制循环期间我们做错了连接纹理。任何指针都将非常感谢!
我们得到的每一点的输出是0.664063 0.742188 0.839844 1.000000
片段着色器:
#version 330
uniform sampler2D pos;
uniform sampler2D prev_pos;
uniform sampler2D normal;
uniform float damping;
uniform float mass;
uniform vec3 gravity;
uniform vec3 wind;
uniform float ts;
uniform vec2 texsize;
uniform vec2 patch_size;
uniform vec2 step;
uniform vec2 neighbours[12];
in vec2 frag_texcoord;
out vec4 outpos;
out vec4 outprev;
void main(void)
{
float movable_l = floor(frag_texcoord.x+(1.0-3*step.x))+floor(frag_texcoord.y+(1.0-step.y));
float movable_r = (1-floor(frag_texcoord.x+3*step.x))+(1-floor(frag_texcoord.y+step.y));
float movable = movable_r*movable_l;
vec3 curr_pos = texture(pos,frag_texcoord.yx).xyz;
if(movable >0){
vec3 p_pos = texture(prev_pos,frag_texcoord).xyz;
vec2 neighbourtexcoord;
vec3 neighbourpos;
for(int n=0;n<12;n++){
neighbourtexcoord = neighbours[n]*step;
neighbourtexcoord += frag_texcoord;
if(neighbourtexcoord.x<0.0 || neighbourtexcoord.x>(1.0-step.x)){
continue;
}
if(neighbourtexcoord.y<0.0 || neighbourtexcoord.y>(1.0-step.y)){
continue;
}
neighbourpos = texture(pos,neighbourtexcoord).xyz;
vec3 d = curr_pos-neighbourpos;
float dist = distance(curr_pos,neighbourpos);
float idist = length(neighbours[n])*step.x;
curr_pos += d*(1-(idist/dist));
}
vec3 windF = texture(normal,frag_texcoord).xyz*wind;
vec3 acc = windF+gravity;
float damp = 1-damping;
vec3 vel = curr_pos-p_pos;
curr_pos += acc*ts+vel;
}
outpos = vec4(curr_pos,1.0);
outprev = vec4(texture(pos,frag_texcoord).xyz,0.0);
}
顶点着色器:
#version 330
in vec3 in_Position;
out vec2 frag_texcoord;
void main(void)
{
gl_Position =vec4(in_Position, 1.0);
frag_texcoord=in_Position.xy;
}
主程序:
#include <math.h>
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/glut.h>
#include "SOIL.h"
#include <stdio.h>
#include <cassert>
#include <string.h>
#include <stddef.h>
#ifdef __APPLE__
#include <OpenGL/gl.h>
#include "MicroGlut.h"
// uses framework Cocoa
#else
// #include <GL/glut.h>
#endif
#include "GL_utilities.h"
#include "VectorUtils2.h"
#include "Cloth.h"
//#include "LoadTGA.h"
#define TIME_STEPSIZE2 0.5*0.5
#define CHECK_GL_ERRORS assert(glGetError()==GL_NO_ERROR);
#ifndef M_PI
#define M_PI 3.14159265
#endif
static long count = 0;
static long limit = -1;
static float startTime;
static GLfloat view_rotx = 90.0, view_roty = 0.0, view_rotz = 70.0;
static GLuint gear1, gear2, gear3; // Was display lists, now are VAOs
static GLfloat angle = 0.0;
//The value that controls the wind speed
float windForceZ = 0.0;
int gear1Triangles=0, gear2Triangles=0, gear3Triangles=0;
GLuint program, verletShader,clothVao, clothVbo, clothNbo, clothTbo, quadVao, quadVbo; // Shader
GLint colorPos;
float projectionMatrix[16];
static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
static GLuint quad[]={ -1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f};
#define W 512
#define H 512
//------------a structure for FBO information-------------------------------------
typedef struct
{
GLuint attachID[3];
GLuint fb;
GLuint rb;
GLuint depth;
int width, height;
} FBOstruct;
FBOstruct *fbo1, *fbo2;
GLenum color_attachments[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2};
float *gVert;
float *gNorm;
float *data;
static int numVertices;
static float currentNormalsX, currentNormalsY, currentNormalsZ;
GLuint texture_img;
GLint location_Texture, location_texCoord;
#define vDensity 8
#define hDensity 8
#define cloth_width 20
#define cloth_height 20
Cloth cloth1(cloth_height,cloth_width,vDensity,hDensity);
int size = (vDensity-1)*(hDensity-1)*9*2;
Point3D gravity, tmp1, wind;
void init_glsl_stuff(){
verletShader = loadShaders("verlet.vert", "verlet.frag");
CHECK_GL_ERRORS
glUseProgram(verletShader);
float neighbourarray[24] = {1,0,0,1,1,1,-1,1,-1,0,1-1,2,0,0,2,-2,0,0-2};
glUniform1i(glGetUniformLocation(verletShader,"pos"),0);
glUniform1i(glGetUniformLocation(verletShader,"prev_pos"),1);
glUniform1i(glGetUniformLocation(verletShader,"normal"),2);
glUniform1f(glGetUniformLocation(verletShader,"damping"), 0.01);
glUniform1f(glGetUniformLocation(verletShader,"mass"), 1.0);
glUniform3f(glGetUniformLocation(verletShader,"gravity"), 0.0,0.9,0.0);
glUniform3f(glGetUniformLocation(verletShader,"wind"), 0.0,0.0,0.0);
glUniform1f(glGetUniformLocation(verletShader,"ts"), 0.5*0.5);
CHECK_GL_ERRORS
glUniform2f(glGetUniformLocation(verletShader,"texsize"), (float)hDensity,(float)vDensity);
CHECK_GL_ERRORS
// eventuellt lägga till k värden för fjädrar
glUniform2f(glGetUniformLocation(verletShader,"patch_size"), (float)cloth_width/((float)hDensity-1.0),(float)cloth_height/((float)vDensity-1.0));
CHECK_GL_ERRORS
glUniform2f(glGetUniformLocation(verletShader,"step"),1.0/((float)vDensity-1.0), 1.0/((float)hDensity-1.0));
CHECK_GL_ERRORS
glUniform2fv(glGetUniformLocation(verletShader,"neighbours"),12,neighbourarray);
glBindFragDataLocation(verletShader, 0, "outpos");
glBindFragDataLocation(verletShader, 1, "outprev");
glLinkProgram(verletShader);
printProgramInfoLog(verletShader);
glUseProgram(0);
}
void addTexture(int width, int height,int int_method,GLuint mempos,float *data,int attachment_pos){
glBindTexture(GL_TEXTURE_2D,mempos);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
if (int_method == 0)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, data);
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment_pos, GL_TEXTURE_2D, mempos, 0);
}
//------------------------------------------------------------
//-----------------------FBO Init-----------------------------
//------------------------------------------------------------
void CHECK_FRAMEBUFFER_STATUS()
{
GLenum status;
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
fprintf(stderr, "Framebuffer not complete\n");
}
FBOstruct *initFBO(int width, int height, int int_method, float *positions, float *normals)
{
FBOstruct *fbo = new FBOstruct();
fbo->width = width;
fbo->height = height;
// create objects
glGenFramebuffers(1, &fbo->fb); // frame buffer id
glBindFramebuffer(GL_FRAMEBUFFER, fbo->fb);
glGenTextures(3, fbo->attachID);
addTexture(width,height,int_method,fbo->attachID[0],positions,color_attachments[0]);
addTexture(width,height,int_method,fbo->attachID[1],positions,color_attachments[1]);
addTexture(width,height,int_method,fbo->attachID[2],normals,color_attachments[2]);
fprintf(stderr, "Framebuffer object %d\n", fbo->fb);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return fbo;
}
//------------------------------------------------------------
//---------------------Draw on GPU----------------------------
//------------------------------------------------------------
void drawClothGPU(){
glViewport(0, 0, H, W);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo1->fb);
glDrawBuffers(3, color_attachments);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, fbo2->attachID[0]);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, fbo2->attachID[1]);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, fbo2->attachID[2]);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(verletShader);
glBindVertexArray(quadVao);
glBindBuffer(GL_ARRAY_BUFFER,quadVbo);
glDrawArrays(GL_TRIANGLES, 0, 18);
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindVertexArray(clothVao);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo2->fb);
glBindTexture(GL_TEXTURE_2D, fbo2->attachID[0]);
glReadBuffer(GL_COLOR_ATTACHMENT0);
int s = hDensity*vDensity*4;
data = new float[s];
glReadPixels(0, 0, hDensity, vDensity, GL_RGBA, GL_FLOAT, data);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
gVert = new float[size];
glUseProgram(program);
glBindBuffer(GL_ARRAY_BUFFER, clothVbo);
int count = 0;
for(int x = 0; x<vDensity-1; x++){
for(int y=0; y<hDensity-1; y++){
//(x+1,y)
printf("value : %f",data[4*(x + 1 + hDensity*y)]);
gVert[count] = data[4*(x + 1 + hDensity*y)];
gVert[count + 1] = data[4*(x + 1 + hDensity*y) + 1];
gVert[count + 2] = data[4*(x + 1 + hDensity*y) + 2];
//(x,y)
gVert[count + 3] = data[4*(x + hDensity*y)];
gVert[count + 4] = data[4*(x + hDensity*y) + 1];
gVert[count + 5] = data[4*(x + hDensity*y) + 2];
//(x,y+1)
gVert[count + 6] = data[4*(x + hDensity*(y+1))];
gVert[count + 7] = data[4*(x + hDensity*(y+1)) + 1];
gVert[count + 8] = data[4*(x + hDensity*(y+1)) + 2];
//(x+1,y+1)
gVert[count + 9] = data[4*(x + 1 + hDensity*(y+1))];
gVert[count + 10] = data[4*(x + 1 + hDensity*(y+1)) + 1];
gVert[count + 11] = data[4*(x + 1 + hDensity*(y+1)) + 2];
//(x+1,y)
gVert[count + 12] = data[4*(x + 1 + hDensity*y)];
gVert[count + 13] = data[4*(x + 1 + hDensity*y) + 1];
gVert[count + 14] = data[4*(x + 1 + hDensity*y) + 2];
//(x,y+1)
gVert[count + 15] = data[4*(x + hDensity*(y+1))];
gVert[count + 16] = data[4*(x + hDensity*(y+1)) + 1];
gVert[count + 17] = data[4*(x + hDensity*(y+1)) + 2];
count+=18;
}
}
int num_vertices = (count)/3;
int num_coordinates = count;
GLfloat* pData = (GLfloat*)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
memcpy(pData, &gVert[0], num_coordinates*sizeof(GLfloat));
glUnmapBuffer(GL_ARRAY_BUFFER);
glDrawArrays(GL_TRIANGLES, 0, num_vertices);
delete [] gVert;
delete [] data;
FBOstruct *tmp = fbo1;
fbo1 = fbo2;
fbo2 = tmp;
}
static void draw(void)
{
//CPU
//drawClothCPU(m);
//GPU
drawClothGPU();
glBindTexture(GL_TEXTURE_2D, 0);
glutSwapBuffers();
count++;
if (count == limit)
exit(0);
theTime = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
if (theTime >= startTime + 1.0)
{
//printf("%d fps\n", count);
startTime = theTime;
count = 0;
}
}
static void
init(void)
{
glDisable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
init_glsl_stuff(); //first shader stuff
program = loadShaders("gears.vert", "gears.frag");
glUseProgram(program);
glUniform4fv(glGetUniformLocation(program, "pos"), 1, pos);
glUniformMatrix4fv(glGetUniformLocation(program, "projectionMatrix"), 1, GL_TRUE, projectionMatrix);
colorPos = glGetUniformLocation(program, "color");
gVert = new float[size];
gNorm = new float[size];
float *pts = new float[vDensity*hDensity*4];
float *norm = new float[vDensity*hDensity*4];
int num = cloth1.drawShaded(gVert, gNorm);
cloth1.getPoints(pts,norm);
fbo1 = initFBO(hDensity, vDensity, 0,pts,norm);
fbo2 = initFBO(hDensity, vDensity, 0,pts,norm);
glGenVertexArrays(1, &clothVao);
glBindVertexArray(clothVao);
glGenBuffers(1, &clothVbo);
glGenBuffers(1, &clothNbo);
glGenBuffers(1, &clothTbo);
glBindBuffer(GL_ARRAY_BUFFER, clothVbo);
glBufferData(GL_ARRAY_BUFFER, num*9*sizeof(GLfloat), gVert, GL_STATIC_DRAW);
glVertexAttribPointer(glGetAttribLocation(program, "in_Position"), 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(glGetAttribLocation(program, "in_Position"));
//VAO for quad
glGenVertexArrays(1, &quadVao);
glBindVertexArray(quadVao);
//VBO for quad
glGenBuffers(1, &quadVbo);
glBindBuffer(GL_ARRAY_BUFFER, quadVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW);
glBindVertexArray(0);
delete [] gVert;
delete [] gNorm;
//texture
texture_img = loadTexture("C:/Users/Bohb/Downloads/boa.jpg");
location_Texture = glGetUniformLocation( program, "colorMap" );
if(location_Texture == -1)
fprintf( stderr, "Binding warning: Failed to locate uniform variable 'colorMap'.\n");
frustum(-1.0, 1.0, -1.0, 1.0, 5.0, 60.0, projectionMatrix);
startTime = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
glBindVertexArray(clothVao);
}