From f0a759724f140bd31438d3899436b24eb9b08190 Mon Sep 17 00:00:00 2001 From: Sally Kong Date: Sun, 11 Oct 2015 22:55:44 -0400 Subject: [PATCH 1/5] I have a cow --- src/main.cpp | 3 +- src/rasterize.cu | 178 +++++++++++++++++++++++++++++++++++++++++-- src/rasterize.h | 2 + src/rasterizeTools.h | 15 +++- 4 files changed, 189 insertions(+), 9 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index a125d7c..61eaa09 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,6 +7,7 @@ */ #include "main.hpp" +#include "rasterizeTools.h" //------------------------------- //-------------MAIN-------------- @@ -159,7 +160,7 @@ void initCuda() { // Use device with highest Gflops/s cudaGLSetGLDevice(0); - rasterizeInit(width, height); + rasterizeInit(width, height); // Clean up on program exit atexit(cleanupCuda); diff --git a/src/rasterize.cu b/src/rasterize.cu index 53103b5..f14d3a9 100644 --- a/src/rasterize.cu +++ b/src/rasterize.cu @@ -13,28 +13,38 @@ #include #include #include -#include "rasterizeTools.h" +#include +#include struct VertexIn { glm::vec3 pos; glm::vec3 nor; glm::vec3 col; + glm::vec2 uv; // TODO (optional) add other vertex attributes (e.g. texture coordinates) }; struct VertexOut { // TODO + glm::vec3 pos; + glm::vec3 nor; + glm::vec3 col; + glm::vec2 uv; + }; struct Triangle { VertexOut v[3]; }; struct Fragment { glm::vec3 color; + glm::vec3 position; + glm::vec3 normal; }; static int width = 0; static int height = 0; static int *dev_bufIdx = NULL; static VertexIn *dev_bufVertex = NULL; +static VertexOut *dev_bufVertex_out = NULL; static Triangle *dev_primitives = NULL; static Fragment *dev_depthbuffer = NULL; static glm::vec3 *dev_framebuffer = NULL; @@ -44,8 +54,7 @@ static int vertCount = 0; /** * Kernel that writes the image to the OpenGL PBO directly. */ -__global__ -void sendImageToPBO(uchar4 *pbo, int w, int h, glm::vec3 *image) { +__global__ void sendImageToPBO(uchar4 *pbo, int w, int h, glm::vec3 *image) { int x = (blockIdx.x * blockDim.x) + threadIdx.x; int y = (blockIdx.y * blockDim.y) + threadIdx.y; int index = x + (y * w); @@ -64,8 +73,7 @@ void sendImageToPBO(uchar4 *pbo, int w, int h, glm::vec3 *image) { } // Writes fragment colors to the framebuffer -__global__ -void render(int w, int h, Fragment *depthbuffer, glm::vec3 *framebuffer) { +__global__ void render(int w, int h, Fragment *depthbuffer, glm::vec3 *framebuffer) { int x = (blockIdx.x * blockDim.x) + threadIdx.x; int y = (blockIdx.y * blockDim.y) + threadIdx.y; int index = x + (y * w); @@ -75,18 +83,136 @@ void render(int w, int h, Fragment *depthbuffer, glm::vec3 *framebuffer) { } } +__global__ void vertexShading(int n, glm::mat4 view_projection, + VertexIn *vs_input, VertexOut *vs_output) { + + int index = (blockIdx.x * blockDim.x) + threadIdx.x; + + if (index < n) { + + VertexOut vert_out; + glm::vec4 input_pos = glm::vec4( + vs_input[index].pos.x, + vs_input[index].pos.y, + vs_input[index].pos.z, + 1.0f); + + glm::vec3 transformedPoint = multiplyMV(view_projection, input_pos); + vert_out.pos = transformedPoint; + + glm::vec4 input_normal = glm::vec4( + vs_input[index].nor.x, + vs_input[index].nor.y, + vs_input[index].nor.z, + 1.0f); + + glm::vec3 output_normal = multiplyMV(view_projection,input_normal); + vert_out.nor = output_normal; + + vert_out.col = vs_input[index].col; + + vs_output[index] = vert_out; + + } +} + +__global__ void primitiveAssembling(int n, VertexOut *vs_output, + Triangle *primitives) { + + int index = (blockIdx.x * blockDim.x) + threadIdx.x; + + if (index < n) { + primitives[index].v[0] = vs_output[3*index]; + primitives[index].v[1] = vs_output[3*index+1]; + primitives[index].v[2] = vs_output[3*index+2]; + } + +} + +__global__ void rasterizing(int n, int w, int h, + Triangle *primitives, Fragment *fs_input) { + + int index = (blockIdx.x * blockDim.x) + threadIdx.x; + if (index < n) { + Triangle tri = primitives[index]; + glm::vec3 vertices[3] = {tri.v[0].pos, tri.v[1].pos, tri.v[2].pos}; + AABB aabb = getAABBForTriangle(vertices); + + glm::vec2 pixel_min; + pixel_min.x = (aabb.min.x + 1) * w / 2.0f; + pixel_min.y = (aabb.min.y + 1) * h / 2.0f; + + glm::vec2 pixel_max; + pixel_max.x = (aabb.max.x + 1) * w / 2.0f; + pixel_max.y = (aabb.max.y + 1) * h / 2.0f; + + for (int i = glm::max(0.0f, pixel_min.x); i <= pixel_max.x; i++) { + for (int j = glm::max(0.0f, pixel_min.y); j <= pixel_max.y; j++) { + + float x = (i/float(w)) * 2.0f - 1; + float y = (j/float(h)) * 2.0f - 1; + + glm::vec3 barycentric = calculateBarycentricCoordinate(vertices, + glm::vec2(x,y)); + if (isBarycentricCoordInBounds(barycentric)) { + Fragment frag; + frag.color = (primitives[index].v[0].col + + primitives[index].v[1].col + + primitives[index].v[2].col) / 3.0f; + + frag.normal = (primitives[index].v[0].nor + + primitives[index].v[1].nor + + primitives[index].v[2].nor) / 3.0f; + + frag.position = barycentric; + + fs_input[j*w + i] = frag; + } + } + } + + + } +} + +__global__ void fragmentShading(int w, int h, Fragment *fs, glm::vec3 light_pos) { + int x = (blockIdx.x * blockDim.x) + threadIdx.x; + int y = (blockIdx.y * blockDim.y) + threadIdx.y; + int index = x + (y * w); + + if ( x < w && y < h) { + float diffuseTerm = 0.7f; + glm::vec3 light_color = glm::vec3(1.0f); + fs[index].color *= diffuseTerm * glm::max(0.0f, + glm::dot(glm::normalize(fs[index].normal), + glm::normalize(light_pos - fs[index].position))); + } + +} + +__global__ void fragmentsToDepth() { +} + +__global__ void depthTesting() { +} + +__global__ void fragmentToBuffer() { +} + /** * Called once at the beginning of the program to allocate memory. */ void rasterizeInit(int w, int h) { width = w; height = h; + cudaFree(dev_depthbuffer); cudaMalloc(&dev_depthbuffer, width * height * sizeof(Fragment)); cudaMemset(dev_depthbuffer, 0, width * height * sizeof(Fragment)); cudaFree(dev_framebuffer); cudaMalloc(&dev_framebuffer, width * height * sizeof(glm::vec3)); cudaMemset(dev_framebuffer, 0, width * height * sizeof(glm::vec3)); + checkCUDAError("rasterizeInit"); } @@ -110,10 +236,14 @@ void rasterizeSetBuffers( bufVertex[i].nor = glm::vec3(bufNor[j + 0], bufNor[j + 1], bufNor[j + 2]); bufVertex[i].col = glm::vec3(bufCol[j + 0], bufCol[j + 1], bufCol[j + 2]); } + cudaFree(dev_bufVertex); cudaMalloc(&dev_bufVertex, vertCount * sizeof(VertexIn)); cudaMemcpy(dev_bufVertex, bufVertex, vertCount * sizeof(VertexIn), cudaMemcpyHostToDevice); + cudaFree(dev_bufVertex_out); + cudaMalloc(&dev_bufVertex_out, vertCount * sizeof(VertexOut)); + cudaFree(dev_primitives); cudaMalloc(&dev_primitives, vertCount / 3 * sizeof(Triangle)); cudaMemset(dev_primitives, 0, vertCount / 3 * sizeof(Triangle)); @@ -130,9 +260,40 @@ void rasterize(uchar4 *pbo) { dim3 blockCount2d((width - 1) / blockSize2d.x + 1, (height - 1) / blockSize2d.y + 1); + dim3 blockSize1d(128); + dim3 blockCount1d((vertCount + 128 - 1) / 128); + // TODO: Execute your rasterization pipeline here - // (See README for rasterization pipeline outline.) + //view matrix + glm::mat4 view = glm::lookAt( + glm::vec3(0.0f, 1.5f, 5.0f), + glm::vec3(0.0f, 0.0f, -1.0f), + glm::vec3(0.0f, -1.0f, 0.0f)); + + //projection matrix + glm::mat4 projection = glm::perspective( + 45.0f, float(width)/float(height), 1.0f, 100.0f); + + glm::mat4 view_projection = projection * view; + vertexShading<<>>(vertCount, view_projection, + dev_bufVertex, dev_bufVertex_out); + checkCUDAError("vertex shader"); + + primitiveAssembling<<>>(vertCount/3, + dev_bufVertex_out, dev_primitives); + checkCUDAError("primitive assembling"); + + rasterizing<<>>(vertCount/3, width, height, + dev_primitives, dev_depthbuffer); + checkCUDAError("triangle rasterizing"); + + glm::vec3 light_pos = glm::vec3(-3.0f, 5.0f, 10.0f); + fragmentShading<<>>(width, height, dev_depthbuffer, + light_pos); + checkCUDAError("fragment shading"); + + // Copy depthbuffer colors into framebuffer render<<>>(width, height, dev_depthbuffer, dev_framebuffer); // Copy framebuffer into OpenGL buffer for OpenGL previewing @@ -150,12 +311,15 @@ void rasterizeFree() { cudaFree(dev_bufVertex); dev_bufVertex = NULL; + cudaFree(dev_bufVertex_out); + dev_bufVertex_out = NULL; + cudaFree(dev_primitives); dev_primitives = NULL; cudaFree(dev_depthbuffer); dev_depthbuffer = NULL; - + cudaFree(dev_framebuffer); dev_framebuffer = NULL; diff --git a/src/rasterize.h b/src/rasterize.h index a06b339..0807f59 100644 --- a/src/rasterize.h +++ b/src/rasterize.h @@ -9,6 +9,8 @@ #pragma once #include +#include +#include "rasterizeTools.h" void rasterizeInit(int width, int height); void rasterizeSetBuffers( diff --git a/src/rasterizeTools.h b/src/rasterizeTools.h index 46c701e..53cc513 100644 --- a/src/rasterizeTools.h +++ b/src/rasterizeTools.h @@ -17,12 +17,24 @@ struct AABB { glm::vec3 max; }; +struct Camera { + glm::ivec2 resolution; + glm::vec3 position; + glm::vec3 target; + glm::vec3 up; + glm::vec2 fov; + float nearPlane; + float farPlane; +}; + /** * Multiplies a glm::mat4 matrix and a vec4. */ __host__ __device__ static glm::vec3 multiplyMV(glm::mat4 m, glm::vec4 v) { - return glm::vec3(m * v); + //glm::vec4 product = m * v; + //return glm::vec3(product.x, product.y, product.z) / product.w; + return glm::vec3(m*v); } // CHECKITOUT @@ -99,3 +111,4 @@ float getZAtCoordinate(const glm::vec3 barycentricCoord, const glm::vec3 tri[3]) + barycentricCoord.y * tri[1].z + barycentricCoord.z * tri[2].z); } + From c938e160c904c4f05819b03b2ae2523564c6c9f4 Mon Sep 17 00:00:00 2001 From: Sally Kong Date: Sun, 11 Oct 2015 23:55:47 -0400 Subject: [PATCH 2/5] tried adding thrust random, but no --- src/rasterize.cu | 89 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 65 insertions(+), 24 deletions(-) diff --git a/src/rasterize.cu b/src/rasterize.cu index f14d3a9..68044f5 100644 --- a/src/rasterize.cu +++ b/src/rasterize.cu @@ -38,8 +38,26 @@ struct Fragment { glm::vec3 color; glm::vec3 position; glm::vec3 normal; + int depth; }; +__host__ __device__ inline unsigned int utilhash(unsigned int a) { + a = (a + 0x7ed55d16) + (a << 12); + a = (a ^ 0xc761c23c) ^ (a >> 19); + a = (a + 0x165667b1) + (a << 5); + a = (a + 0xd3a2646c) ^ (a << 9); + a = (a + 0xfd7046c5) + (a << 3); + a = (a ^ 0xb55a4f09) ^ (a >> 16); + return a; +} + + +__host__ __device__ +thrust::default_random_engine makeSeededRandomEngine(int iter, int index, int depth) { + int h = utilhash((1 << 31) | (depth << 22) | iter) ^ utilhash(index); + return thrust::default_random_engine(h); +} + static int width = 0; static int height = 0; static int *dev_bufIdx = NULL; @@ -83,6 +101,17 @@ __global__ void render(int w, int h, Fragment *depthbuffer, glm::vec3 *framebuff } } +__global__ void depthBufferClearing(int w, int h, Fragment *fragments) { + int x = (blockIdx.x * blockDim.x) + threadIdx.x; + int y = (blockIdx.y * blockDim.y) + threadIdx.y; + int index = x + (y * w); + + if ( x < w && y < h) { + fragments[index].depth = INT_MAX; + fragments[index].color = glm::vec3(0.0f); + } +} + __global__ void vertexShading(int n, glm::mat4 view_projection, VertexIn *vs_input, VertexOut *vs_output) { @@ -135,8 +164,8 @@ __global__ void rasterizing(int n, int w, int h, int index = (blockIdx.x * blockDim.x) + threadIdx.x; if (index < n) { Triangle tri = primitives[index]; - glm::vec3 vertices[3] = {tri.v[0].pos, tri.v[1].pos, tri.v[2].pos}; - AABB aabb = getAABBForTriangle(vertices); + glm::vec3 tri_verts[3] = {tri.v[0].pos, tri.v[1].pos, tri.v[2].pos}; + AABB aabb = getAABBForTriangle(tri_verts); glm::vec2 pixel_min; pixel_min.x = (aabb.min.x + 1) * w / 2.0f; @@ -149,24 +178,36 @@ __global__ void rasterizing(int n, int w, int h, for (int i = glm::max(0.0f, pixel_min.x); i <= pixel_max.x; i++) { for (int j = glm::max(0.0f, pixel_min.y); j <= pixel_max.y; j++) { - float x = (i/float(w)) * 2.0f - 1; - float y = (j/float(h)) * 2.0f - 1; + thrust::default_random_engine rng = makeSeededRandomEngine(0, index, 0); + thrust::uniform_real_distribution u01(0, 1); + + float x = ((i + u01(rng))/float(w)) * 2.0f - 1; + float y = ((j + u01(rng))/float(h)) * 2.0f - 1; - glm::vec3 barycentric = calculateBarycentricCoordinate(vertices, + glm::vec3 barycentric = calculateBarycentricCoordinate(tri_verts, glm::vec2(x,y)); if (isBarycentricCoordInBounds(barycentric)) { - Fragment frag; - frag.color = (primitives[index].v[0].col - + primitives[index].v[1].col - + primitives[index].v[2].col) / 3.0f; - frag.normal = (primitives[index].v[0].nor - + primitives[index].v[1].nor - + primitives[index].v[2].nor) / 3.0f; + int frag_index = j*w + i; + int depth = getZAtCoordinate(barycentric, tri_verts) * INT_MAX; + atomicMin(&fs_input[frag_index].depth, depth); + + if(fs_input[frag_index].depth == depth) { + + Fragment frag; + frag.color = (primitives[index].v[0].col + + primitives[index].v[1].col + + primitives[index].v[2].col) / 3.0f; - frag.position = barycentric; + frag.normal = (primitives[index].v[0].nor + + primitives[index].v[1].nor + + primitives[index].v[2].nor) / 3.0f; - fs_input[j*w + i] = frag; + frag.position = barycentric; + frag.depth = depth; + + fs_input[frag_index] = frag; + } } } } @@ -190,15 +231,6 @@ __global__ void fragmentShading(int w, int h, Fragment *fs, glm::vec3 light_pos) } -__global__ void fragmentsToDepth() { -} - -__global__ void depthTesting() { -} - -__global__ void fragmentToBuffer() { -} - /** * Called once at the beginning of the program to allocate memory. */ @@ -263,7 +295,13 @@ void rasterize(uchar4 *pbo) { dim3 blockSize1d(128); dim3 blockCount1d((vertCount + 128 - 1) / 128); - // TODO: Execute your rasterization pipeline here + //-----RATERIZATION PIPELINE---------- + + //---Clear Depth Buffer + depthBufferClearing<<>>(width, height, dev_depthbuffer); + checkCUDAError("depth buffer clearing"); + + //---Vertex Shader //view matrix glm::mat4 view = glm::lookAt( glm::vec3(0.0f, 1.5f, 5.0f), @@ -280,14 +318,17 @@ void rasterize(uchar4 *pbo) { dev_bufVertex, dev_bufVertex_out); checkCUDAError("vertex shader"); + //---Primitive Assembly primitiveAssembling<<>>(vertCount/3, dev_bufVertex_out, dev_primitives); checkCUDAError("primitive assembling"); + //---Rasterization rasterizing<<>>(vertCount/3, width, height, dev_primitives, dev_depthbuffer); checkCUDAError("triangle rasterizing"); + //--Fragment Shader glm::vec3 light_pos = glm::vec3(-3.0f, 5.0f, 10.0f); fragmentShading<<>>(width, height, dev_depthbuffer, light_pos); From 6a6afce80b488595312e40b9cd47b2174b3b4e9f Mon Sep 17 00:00:00 2001 From: Sally Kong Date: Mon, 12 Oct 2015 00:06:27 -0400 Subject: [PATCH 3/5] cow img --- renders/cow.PNG | Bin 0 -> 86675 bytes src/rasterize.cu | 10 +++++----- 2 files changed, 5 insertions(+), 5 deletions(-) create mode 100644 renders/cow.PNG diff --git a/renders/cow.PNG b/renders/cow.PNG new file mode 100644 index 0000000000000000000000000000000000000000..ff66c254b661203f56db850c09783c16bbee5226 GIT binary patch literal 86675 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 -t$!PqdRV(^Vz`3M|6T$+lnEH#dB?0q0f?d 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 buXR`2v#JPj=63Ib0Qg)SJ+P1LeUtweQwGm& literal 0 HcmV?d00001 diff --git a/src/rasterize.cu b/src/rasterize.cu index 68044f5..1d321ce 100644 --- a/src/rasterize.cu +++ b/src/rasterize.cu @@ -178,11 +178,11 @@ __global__ void rasterizing(int n, int w, int h, for (int i = glm::max(0.0f, pixel_min.x); i <= pixel_max.x; i++) { for (int j = glm::max(0.0f, pixel_min.y); j <= pixel_max.y; j++) { - thrust::default_random_engine rng = makeSeededRandomEngine(0, index, 0); - thrust::uniform_real_distribution u01(0, 1); + //thrust::default_random_engine rng = makeSeededRandomEngine(0, index, 0); + //thrust::uniform_real_distribution u01(0, 1); - float x = ((i + u01(rng))/float(w)) * 2.0f - 1; - float y = ((j + u01(rng))/float(h)) * 2.0f - 1; + float x = (i/float(w)) * 2.0f - 1; + float y = (j/float(h)) * 2.0f - 1; glm::vec3 barycentric = calculateBarycentricCoordinate(tri_verts, glm::vec2(x,y)); @@ -310,7 +310,7 @@ void rasterize(uchar4 *pbo) { //projection matrix glm::mat4 projection = glm::perspective( - 45.0f, float(width)/float(height), 1.0f, 100.0f); + 20.0f, float(width)/float(height), 1.0f, 100.0f); glm::mat4 view_projection = projection * view; From 4277dcf0813554fd4769a9c5d3be0c389e0da4bf Mon Sep 17 00:00:00 2001 From: Sally Kong Date: Mon, 12 Oct 2015 00:07:21 -0400 Subject: [PATCH 4/5] Update README.md --- README.md | 377 +----------------------------------------------------- 1 file changed, 5 insertions(+), 372 deletions(-) diff --git a/README.md b/README.md index f1e4738..38bed0c 100644 --- a/README.md +++ b/README.md @@ -3,377 +3,10 @@ CUDA Rasterizer **University of Pennsylvania, CIS 565: GPU Programming and Architecture, Project 4** -* (TODO) YOUR NAME HERE -* Tested on: (TODO) Windows 22, i7-2222 @ 2.22GHz 22GB, GTX 222 222MB (Moore 2222 Lab) +* Sally Kong +* Tested on: Windows 8, i7-5500U CPU @ 2.40GHz 2.40 GHz, GEForce 920M (Personal) -### (TODO: Your README) +A simplified rasterized graphics pipeline, similar to the OpenGL pipeline. I implemented a vertex shader, primitive assembly, rasterization, and a fragment shader (lambert). -*DO NOT* leave the README to the last minute! It is a crucial part of the -project, and we will not be able to grade you without a good README. - - -Instructions (delete me) -======================== - -This is due Sunday, October 11, evening at midnight. - -**Summary:** -In this project, you will use CUDA to implement a simplified -rasterized graphics pipeline, similar to the OpenGL pipeline. You will -implement vertex shading, primitive assembly, rasterization, fragment shading, -and a framebuffer. More information about the rasterized graphics pipeline can -be found in the class slides and in the CIS 560 lecture notes. - -The base code provided includes an OBJ loader and much of the I/O and -bookkeeping code. It also includes some functions that you may find useful, -described below. The core rasterization pipeline is left for you to implement. - -You are not required to use this base code if you don't want -to. You may also change any part of the base code as you please. -**This is YOUR project.** - -**Recommendation:** -Every image you save should automatically get a different -filename. Don't delete all of them! For the benefit of your README, keep a -bunch of them around so you can pick a few to document your progress. - - -### Contents - -* `src/` C++/CUDA source files. -* `util/` C++ utility files. -* `objs/` Example OBJ test files (# verts, # tris in buffers after loading) - * `tri.obj` (3v, 1t): The simplest possible geometric object. - * `cube.obj` (36v, 12t): A small model with low depth-complexity. - * `suzanne.obj` (2904 verts, 968 tris): A medium model with low depth-complexity. - * `suzanne_smooth.obj` (2904 verts, 968 tris): A medium model with low depth-complexity. - This model has normals which must be interpolated. - * `cow.obj` (17412 verts, 5804 tris): A large model with low depth-complexity. - * `cow_smooth.obj` (17412 verts, 5804 tris): A large model with low depth-complexity. - This model has normals which must be interpolated. - * `flower.obj` (1920 verts, 640 tris): A medium model with very high depth-complexity. - * `sponza.obj` (837,489 verts, 279,163 tris): A huge model with very high depth-complexity. -* `renders/` Debug render of an example OBJ. -* `external/` Includes and static libraries for 3rd party libraries. - -### Running the code - -The main function requires a scene description file. Call the program with -one as an argument: `cis565_rasterizer objs/cow.obj`. -(In Visual Studio, `../objs/cow.obj`.) - -If you are using Visual Studio, you can set this in the Debugging > Command -Arguments section in the Project properties. Note that this value is different -for every different configuration type. Make sure you get the path right; read -the console for errors. - -## Requirements - -**Ask on the mailing list for any clarifications.** - -In this project, you are given the following code: - -* A library for loading standard Alias/Wavefront `.obj` format mesh - files and converting them to OpenGL-style buffers of index and vertex data. - * This library does NOT read materials, and provides all colors as white by - default. You can use another library if you wish. -* Simple structs for some parts of the pipeline. -* Depth buffer to framebuffer copy. -* CUDA-GL interop. - -You will need to implement the following features/pipeline stages: - -* Vertex shading. -* (Vertex shader) perspective transformation. -* Primitive assembly with support for triangles read from buffers of index and - vertex data. -* Rasterization. -* Fragment shading. -* A depth buffer for storing and depth testing fragments. -* Fragment to depth buffer writing (**with** atomics for race avoidance). -* (Fragment shader) simple lighting scheme, such as Lambert or Blinn-Phong. - -See below for more guidance. - -You are also required to implement at least 3.0 "points" worth in extra features. -(point values are given in parentheses): - -* (1.0) Tile-based pipeline. -* Additional pipeline stages. - * (1.0) Tessellation shader. - * (1.0) Geometry shader, able to output a variable number of primitives per - input primitive, optimized using stream compaction (thrust allowed). - * (0.5 **if not doing geometry shader**) Backface culling, optimized using - stream compaction (thrust allowed). - * (1.0) Transform feedback. - * (0.5) Scissor test. - * (0.5) Blending (when writing into framebuffer). -* (1.0) Instancing: draw one set of vertex data multiple times, each run - through the vertex shader with a different ID. -* (0.5) Correct color interpolation between points on a primitive. -* (1.0) UV texture mapping with bilinear texture filtering and perspective - correct texture coordinates. -* Support for rasterizing additional primitives: - * (0.5) Lines or line strips. - * (0.5) Points. -* (1.0) Anti-aliasing. -* (1.0) Occlusion queries. -* (1.0) Order-independent translucency using a k-buffer. -* (0.5) **Mouse**-based interactive camera support. - -This extra feature list is not comprehensive. If you have a particular idea -you would like to implement, please **contact us first**. - -**IMPORTANT:** -For each extra feature, please provide the following brief analysis: - -* Concise overview write-up of the feature. -* Performance impact of adding the feature (slower or faster). -* If you did something to accelerate the feature, what did you do and why? -* How might this feature be optimized beyond your current implementation? - - -## Base Code Tour - -You will be working primarily in two files: `rasterize.cu`, and -`rasterizeTools.h`. Within these files, areas that you need to complete are -marked with a `TODO` comment. Areas that are useful to and serve as hints for -optional features are marked with `TODO (Optional)`. Functions that are useful -for reference are marked with the comment `CHECKITOUT`. **You should look at -all TODOs and CHECKITOUTs before starting!** There are not many. - -* `src/rasterize.cu` contains the core rasterization pipeline. - * A few pre-made structs are included for you to use, but those marked with - TODO will also be needed for a simple rasterizer. As with any part of the - base code, you may modify or replace these as you see fit. - -* `src/rasterizeTools.h` contains various useful tools - * Includes a number of barycentric coordinate related functions that you may - find useful in implementing scanline based rasterization. - -* `util/utilityCore.hpp` serves as a kitchen-sink of useful functions. - - -## Rasterization Pipeline - -Possible pipelines are described below. Pseudo-type-signatures are given. -Not all of the pseudocode arrays will necessarily actually exist in practice. - -### First-Try Pipeline - -This describes a minimal version of *one possible* graphics pipeline, similar -to modern hardware (DX/OpenGL). Yours need not match precisely. To begin, try -to write a minimal amount of code as described here. Verify some output after -implementing each pipeline step. This will reduce the necessary time spent -debugging. - -Start out by testing a single triangle (`tri.obj`). - -* Clear the depth buffer with some default value. -* Vertex shading: - * `VertexIn[n] vs_input -> VertexOut[n] vs_output` - * A minimal vertex shader will apply no transformations at all - it draws - directly in normalized device coordinates (-1 to 1 in each dimension). -* Primitive assembly. - * `VertexOut[n] vs_output -> Triangle[n/3] primitives` - * Start by supporting ONLY triangles. For a triangle defined by indices - `(a, b, c)` into `VertexOut` array `vo`, simply copy the appropriate values - into a `Triangle` object `(vo[a], vo[b], vo[c])`. -* Rasterization. - * `Triangle[n/3] primitives -> FragmentIn[m] fs_input` - * A scanline implementation is simpler to start with. -* Fragment shading. - * `FragmentIn[m] fs_input -> FragmentOut[m] fs_output` - * A super-simple test fragment shader: output same color for every fragment. - * Also try displaying various debug views (normals, etc.) -* Fragments to depth buffer. - * `FragmentOut[m] -> FragmentOut[width][height]` - * Results in race conditions - don't bother to fix these until it works! - * Can really be done inside the fragment shader, if you call the fragment - shader from the rasterization kernel for every fragment (including those - which get occluded). **OR,** this can be done before fragment shading, which - may be faster but means the fragment shader cannot change the depth. -* A depth buffer for storing and depth testing fragments. - * `FragmentOut[width][height] depthbuffer` - * An array of `fragment` objects. - * At the end of a frame, it should contain the fragments drawn to the screen. -* Fragment to framebuffer writing. - * `FragmentOut[width][height] depthbuffer -> vec3[width][height] framebuffer` - * Simply copies the colors out of the depth buffer into the framebuffer - (to be displayed on the screen). - -### A Useful Pipeline - -* Clear the depth buffer with some default value. -* Vertex shading: - * `VertexIn[n] vs_input -> VertexOut[n] vs_output` - * Apply some vertex transformation (e.g. model-view-projection matrix using - `glm::lookAt ` and `glm::perspective `). -* Primitive assembly. - * `VertexOut[n] vs_output -> Triangle[n/3] primitives` - * As above. - * Other primitive types are optional. -* Rasterization. - * `Triangle[n/3] primitives -> FragmentIn[m] fs_input` - * You may choose to do a tiled rasterization method, which should have lower - global memory bandwidth. - * A scanline optimization: when rasterizing a triangle, only scan over the - box around the triangle (`getAABBForTriangle`). -* Fragment shading. - * `FragmentIn[m] fs_input -> FragmentOut[m] fs_output` - * Add a shading method, such as Lambert or Blinn-Phong. Lights can be defined - by kernel parameters (like GLSL uniforms). -* Fragments to depth buffer. - * `FragmentOut[m] -> FragmentOut[width][height]` - * Can really be done inside the fragment shader, if you call the fragment - shader from the rasterization kernel for every fragment (including those - which get occluded). **OR,** this can be done before fragment shading, which - may be faster but means the fragment shader cannot change the depth. - * This result in an optimization: it allows you to do depth tests before - spending execution time in complex fragment shader code! - * Handle race conditions! Since multiple primitives write fragments to the - same fragment in the depth buffer, races must be avoided by using CUDA - atomics. - * *Approach 1:* Lock the location in the depth buffer during the time that - a thread is comparing old and new fragment depths (and possibly writing - a new fragment). This should work in all cases, but be slower. - See the section below on implementing this. - * *Approach 2:* Convert your depth value to a fixed-point `int`, and use - `atomicMin` to store it into an `int`-typed depth buffer `intdepth`. After - that, the value which is stored at `intdepth[i]` is (usually) that of the - fragment which should be stored into the `fragment` depth buffer. - * This may result in some rare race conditions (e.g. across blocks). - * The `flower.obj` test file is good for testing race conditions. -* A depth buffer for storing and depth testing fragments. - * `FragmentOut[width][height] depthbuffer` - * An array of `fragment` objects. - * At the end of a frame, it should contain the fragments drawn to the screen. -* Fragment to framebuffer writing. - * `FragmentOut[width][height] depthbuffer -> vec3[width][height] framebuffer` - * Simply copies the colors out of the depth buffer into the framebuffer - (to be displayed on the screen). - -This is a suggested sequence of pipeline steps, but you may choose to alter the -order of this sequence or merge entire kernels as you see fit. For example, if -you decide that doing has benefits, you can choose to merge the vertex shader -and primitive assembly kernels, or merge the perspective transform into another -kernel. There is not necessarily a right sequence of kernels, and you may -choose any sequence that works. Please document in your README what sequence -you choose and why. - - -## Resources - -### CUDA Mutexes - -Adapted from -[this StackOverflow question](http://stackoverflow.com/questions/21341495/cuda-mutex-and-atomiccas). - -``` -__global__ void kernelFunction(...) { - // Get a pointer to the mutex, which should be 0 right now. - unsigned int *mutex = ...; - - // Loop-wait until this thread is able to execute its critical section. - bool isSet; - do { - isSet = (atomicCAS(mutex, 0, 1) == 0); - if (isSet) { - // Critical section goes here. - // The critical section MUST be inside the wait loop; - // if it is afterward, a deadlock will occur. - } - if (isSet) { - mutex = 0; - } - } while (!isSet); -} -``` - -### Links - -The following resources may be useful for this project. - -* Line Rasterization slides, MIT EECS 6.837, Teller and Durand - * [Slides](http://groups.csail.mit.edu/graphics/classes/6.837/F02/lectures/6.837-7_Line.pdf) -* High-Performance Software Rasterization on GPUs - * [Paper (HPG 2011)](http://www.tml.tkk.fi/~samuli/publications/laine2011hpg_paper.pdf) - * [Code](http://code.google.com/p/cudaraster/) - * Note that looking over this code for reference with regard to the paper is - fine, but we most likely will not grant any requests to actually - incorporate any of this code into your project. - * [Slides](http://bps11.idav.ucdavis.edu/talks/08-gpuSoftwareRasterLaineAndPantaleoni-BPS2011.pdf) -* The Direct3D 10 System (SIGGRAPH 2006) - for those interested in doing - geometry shaders and transform feedback - * [Paper](http://dl.acm.org/citation.cfm?id=1141947) - * [Paper, through Penn Libraries proxy](http://proxy.library.upenn.edu:2247/citation.cfm?id=1141947) -* Multi-Fragment Effects on the GPU using the k-Buffer - for those who want to do - order-independent transparency using a k-buffer - * [Paper](http://www.inf.ufrgs.br/~comba/papers/2007/kbuffer_preprint.pdf) -* FreePipe: A Programmable, Parallel Rendering Architecture for Efficient - Multi-Fragment Effects (I3D 2010) - * [Paper](https://sites.google.com/site/hmcen0921/cudarasterizer) -* Writing A Software Rasterizer In Javascript - * [Part 1](http://simonstechblog.blogspot.com/2012/04/software-rasterizer-part-1.html) - * [Part 2](http://simonstechblog.blogspot.com/2012/04/software-rasterizer-part-2.html) - - -## Third-Party Code Policy - -* Use of any third-party code must be approved by asking on our Google Group. -* If it is approved, all students are welcome to use it. Generally, we approve - use of third-party code that is not a core part of the project. For example, - for the path tracer, we would approve using a third-party library for loading - models, but would not approve copying and pasting a CUDA function for doing - refraction. -* Third-party code **MUST** be credited in README.md. -* Using third-party code without its approval, including using another - student's code, is an academic integrity violation, and will, at minimum, - result in you receiving an F for the semester. - - -## README - -Replace the contents of this README.md in a clear manner with the following: - -* A brief description of the project and the specific features you implemented. -* At least one screenshot of your project running. -* A 30 second or longer video of your project running. -* A performance analysis (described below). - -### Performance Analysis - -The performance analysis is where you will investigate how to make your CUDA -programs more efficient using the skills you've learned in class. You must have -performed at least one experiment on your code to investigate the positive or -negative effects on performance. - -We encourage you to get creative with your tweaks. Consider places in your code -that could be considered bottlenecks and try to improve them. - -Provide summary of your optimizations (no more than one page), along with -tables and or graphs to visually explain any performance differences. - -* Include a breakdown of time spent in each pipeline stage for a few different - models. It is suggested that you use pie charts or 100% stacked bar charts. -* For optimization steps (like backface culling), include a performance - comparison to show the effectiveness. - - -## Submit - -If you have modified any of the `CMakeLists.txt` files at all (aside from the -list of `SOURCE_FILES`), you must test that your project can build in Moore -100B/C. Beware of any build issues discussed on the Google Group. - -1. Open a GitHub pull request so that we can see that you have finished. - The title should be "Submission: YOUR NAME". - * **ADDITIONALLY:** - In the body of the pull request, include a link to your repository. -2. Send an email to the TA (gmail: kainino1+cis565@) with: - * **Subject**: in the form of `[CIS565] Project N: PENNKEY`. - * Direct link to your pull request on GitHub. - * Estimate the amount of time you spent on the project. - * If there were any outstanding problems, or if you did any extra - work, *briefly* explain. - * Feedback on the project itself, if any. +### Sample Image of a cow +![](renders/cow.png) From c3d147b956b537c65845eabe5297050590ddbea2 Mon Sep 17 00:00:00 2001 From: Sally Kong Date: Mon, 12 Oct 2015 00:08:07 -0400 Subject: [PATCH 5/5] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 38bed0c..24e40ff 100644 --- a/README.md +++ b/README.md @@ -9,4 +9,4 @@ CUDA Rasterizer A simplified rasterized graphics pipeline, similar to the OpenGL pipeline. I implemented a vertex shader, primitive assembly, rasterization, and a fragment shader (lambert). ### Sample Image of a cow -![](renders/cow.png) +![](renders/cow.PNG)