Renderização de cenas por traçado de raios na Placa Gráfica Fabiano Segadaes Romeiro Sistemas Gráficos 3D IMPA Sumário ► Introdução ► Programação da Placa Gráfica ► Traçado de raios na esfera ► Renderização da Cena ► Resultados Introdução ► Dada uma descrição de cena no formato apresentado na biblioteca do curso, realizar a sua renderização por traçado de raios na placa gráfica utilizando esferas como primitivas. Introdução ► Ponto fundamental: utilização da placa gráfica para realizar o traçado de raios. ► Vantagens: o traçado de raios pode ser realizado de maneira bem mais rápida, sem ocupar a cpu. Programação da Placa Gráfica ► Utilização da linguagem Cg e do OpenGL juntamente com a interface CgGL para a implementação. Programação da Placa Gráfica Localização do VP e do FP no pipeline da GPU ► Vertex Program: chamado para cada vértice dos polígonos. ► Fragment Program: chamado para cada pixel dos polígonos. Programação da Placa Gráfica Localização do VP e do FP no pipeline da GPU Traçado de raios da esfera ► Estrutura de dados usada na implementação: GLfloat cube[6][4][3]; // Cubo unitário centrado na origem de lado 2 // [-1,1]x[-1,1]x[-1,1] void draw_sphere(GLfloat s_center[3], GLfloat s_radius) { int x; // Set the variables on the VP and the FP cgGLSetParameter4f(center, s_center[0], s_center[1], s_center[2], 1.0f); cgGLSetParameter4f(center_fp, s_center[0], s_center[1], s_center[2], 1.0f); cgGLSetParameter4f(light, light_cg[0],light_cg[1], light_cg[2], 0.0f); // Pass a cube to the pipeline and let the VP/FP raytrace an inscribed sphere in it. float factor = s_radius; glBegin(GL_QUADS); for (x = 0; x < 6; x++) { glVertex3f(s_center[0] + factor*cube[x][0][0],s_center[1] + factor*cube[x][0][1],s_center[2] glVertex3f(s_center[0] + factor*cube[x][1][0],s_center[1] + factor*cube[x][1][1],s_center[2] glVertex3f(s_center[0] + factor*cube[x][2][0],s_center[1] + factor*cube[x][2][1],s_center[2] glVertex3f(s_center[0] + factor*cube[x][3][0],s_center[1] + factor*cube[x][3][1],s_center[2] } } glEnd(); + + + + factor*cube[x][0][2]); factor*cube[x][1][2]); factor*cube[x][2][2]); factor*cube[x][3][2]); Traçado de raios da esfera Estruturas de dados ► Parâmetros de entrada são setados no programa principal antes da renderização, através da API CgGL. struct appdata { float4 position float4 color float4 light float4 camera }; ► : POSITION; : COLOR0; : COLOR1; : TEXCOORD0; A saída do Vertex Program e’ do tipo vfconn e e’ a entrada do Fragment Program. struct vfconn { float4 HPos float4 Col0 float4 o float4 l float4 v }; : POSITION; : COLOR0; : TEXCOORD1; : COLOR1; : TEXCOORD0; Traçado de raios da esfera Vertex Program vfconn vp_main(appdata IN, uniform float4x4 ModelViewProj, uniform float4 center, uniform float radius) { vfconn OUT; // Find o OUT.o.xyz = (IN.position.xyz - center.xyz); OUT.o.w = 1.0f; // Find l OUT.l.xyz = normalize(IN.light.xyz); OUT.l.w = 0.0f; // Find v OUT.v.xyz = normalize(IN.position.xyz - IN.camera.xyz); OUT.v.w = 0.0f; OUT.HPos = mul(ModelViewProj, IN.position); OUT.Col0.xyz = IN.color.xyz; } return OUT; Traçado de raios da esfera Fragment Program void fp_main(in vfconn IN, out float4 color : COLOR0, out float depth : DEPTH, uniform float4x4 ModelViewProj, uniform float radius, uniform float4 center) { float3 norm_l = normalize(IN.l.xyz); float3 norm_v = normalize(IN.v.xyz); float oo = dot(IN.o.xyz,IN.o.xyz); float ov = dot(IN.o.xyz,norm_v); float delta = 4*(ov*ov - oo + radius*radius); } } if (delta <= 0.0f) { discard; } else { delta = sqrt(delta); float t = -ov - delta/2; ... float difuse = dot(normal,norm_l); float specular = dot(normal, halfvec); ... color.xyz = difuse*IN.Col0.xyz + specular*specularColor; …. (Calculo da profundidade) depth = (depto.z/depto.w); Renderização da Cena ► Leitura da cena no formato .scn da biblioteca s3d, suportando cenas com: Esferas Malhas poligonais (trilist), que são renderizadas usando esferas como primitivos: esferas são renderizadas nos vértices dos triângulos ou em toda a superfície do triangulo. Renderização da Cena ► Estruturas de dados: static Scene *s; Object *o; Poly *p; Color c; Light *l; GLfloat light_cg[3]; ► Na inicializacao: s = scene_read(); .... glutDisplayFunc(Draw); .... glutMainLoop(); Renderização da Cena ► Na rotina Draw: gluLookAt(s->view->center.x, s->view->center.y, s->view->center.z, s->view->center.x + s->view->normal.x, s->view->center.y + s->view->normal.y, s->view->center.z + s->view->normal.z, s->view->up.x, s->view->up.y, s->view->up.z); ........ l = s->lights; light_cg[0] = l->dir.x; light_cg[1] = l->dir.y; light_cg[2] = l->dir.z; ......... cgGLSetStateMatrixParameter(modelViewMatrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); cgGLSetStateMatrixParameter(modelViewMatrix_fp, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); cgGLSetParameter4f(camera_cg, s->view->center.x, s->view->center.y, s->view->center.z, 1.0f); Renderização da Cena for (o = s->objs; o != NULL; o = o->next) { color_c = o->mat->c; color_s = o->mat->s; s_color[0] = color_c.x; s_color[1] = color_c.y; s_color[2] = color_c.z; // Set up CG color parameters cgGLSetParameter4f(color, s_color[0], s_color[1], s_color[2], 1.0f); if (o->type == V_PRIM) { Sphere sph = o->u.prim->d; c = sph->c; s_center[0] = c.x; s_center[1] = c.y; s_center[2] = c.z; sph_radius = sph->r; // Set up object type specific CG parameters cgGLSetParameter1f(radius, sph_radius); cgGLSetParameter1f(radius_fp, sph_radius); draw_sphere(s_center, sph_radius); } Renderização da Cena else if (o->type == V_POLYLIST) { for (p = o->u.pols; p != NULL; p = p->next) v1[0] = p->v[0].x; v1[1] = p->v[0].y; v1[2] v2[0] = p->v[1].x; v2[1] = p->v[1].y; v2[2] v3[0] = p->v[2].x; v3[1] = p->v[2].y; v3[2] // Set up object type specific CG parameters cgGLSetParameter1f(radius, s_radius); cgGLSetParameter1f(radius_fp, s_radius); bilerp(v1, v2, v3, s_radius); } } } if (cg_enable) { // disable VP and FP cgGLDisableProfile(cgVertexProfile); cgGLDisableProfile(cgFragmentProfile); } glFlush (); glutSwapBuffers(); { = p->v[0].z; = p->v[1].z; = p->v[2].z; Renderização da Cena long bilerp(GLfloat v1[3], GLfloat v2[3], GLfloat v3[3], GLfloat s_radius) { long num_spheres = 0; int i,j, i_max, j_max; GLfloat s_center[3], vtemp[3]; float d_v1v2 = dist(v1,v2); float d_vtempv3; i_max = (int)floor(d_v1v2/s_radius); } if (bilerp_enable == TRUE) { for (i=0;i<=i_max;i++) { vtemp[0] = v1[0] + (float)((float)i/(float)i_max)*(v2[0]-v1[0]); vtemp[1] = v1[1] + (float)((float)i/(float)i_max)*(v2[1]-v1[1]); vtemp[2] = v1[2] + (float)((float)i/(float)i_max)*(v2[2]-v1[2]); j_max = (int)floor(dist(vtemp,v3)/s_radius); d_vtempv3 = dist(vtemp, v3); num_spheres += j_max; for(j=0;j<=j_max;j++) { s_center[0] = vtemp[0] + (float)((float)j/(float)j_max)*(v3[0]-vtemp[0]); s_center[1] = vtemp[1] + (float)((float)j/(float)j_max)*(v3[1]-vtemp[1]); s_center[2] = vtemp[2] + (float)((float)j/(float)j_max)*(v3[2]-vtemp[2]); draw_sphere(s_center, s_radius); } } } else { num_spheres+=3; draw_sphere(v1, s_radius); draw_sphere(v2, s_radius); draw_sphere(v3, s_radius); } return num_spheres; Resultados