diff --git a/README.md b/README.md index ae0896a..6eced65 100644 --- a/README.md +++ b/README.md @@ -1,51 +1,22 @@ ------------------------------------------------------------------------------- -CIS565: Project 4: CUDA Rasterizer -------------------------------------------------------------------------------- -Fall 2014 -------------------------------------------------------------------------------- -Due Monday 10/27/2014 @ 12 PM +CIS565: Project 4: CUDA Rasterizer [Fall 2014] ------------------------------------------------------------------------------- -------------------------------------------------------------------------------- -NOTE: -------------------------------------------------------------------------------- -This project requires an NVIDIA graphics card with CUDA capability! Any card with CUDA compute capability 1.1 or higher will work fine for this project. For a full list of CUDA capable cards and their compute capability, please consult: http://developer.nvidia.com/cuda/cuda-gpus. If you do not have an NVIDIA graphics card in the machine you are working on, feel free to use any machine in the SIG Lab or in Moore100 labs. All machines in the SIG Lab and Moore100 are equipped with CUDA capable NVIDIA graphics cards. If this too proves to be a problem, please contact Patrick or Karl as soon as possible. +video demo: http://youtu.be/kjV3lIKWtjY +![alt tag](https://github.com/radiumyang/Project4-Rasterizer/blob/master/buddha_blinn_0.JPG) +![alt tag](https://github.com/radiumyang/Project4-Rasterizer/blob/master/dragon_blinn_0.JPG) +![alt tag](https://github.com/radiumyang/Project4-Rasterizer/blob/master/cow_blinn_1.JPG) ------------------------------------------------------------------------------- -INTRODUCTION: +INTRODUCTION ------------------------------------------------------------------------------- -In this project, you will implement a simplified CUDA based implementation of a standard rasterized graphics pipeline, similar to the OpenGL pipeline. In this project, you will implement vertex shading, primitive assembly, perspective transformation, rasterization, fragment shading, and write the resulting fragments to a framebuffer. More information about the rasterized graphics pipeline can be found in the class slides and in your notes from CIS560. - -The basecode provided includes an OBJ loader and much of the mundane I/O and bookkeeping code. The basecode also includes some functions that you may find useful, described below. The core rasterization pipeline is left for you to implement. +In this project, I implemented a simplified CUDA based implementation of a standard rasterized graphics pipeline, including vertex shading, primitive assembly, perspective transformation, rasterization, fragment shading, testing and rendering. This project is based on the basecode provided at class. -You MAY NOT use ANY raycasting/raytracing AT ALL in this project, EXCEPT in the fragment shader step. One of the purposes of this project is to see how a rasterization pipeline can generate graphics WITHOUT the need for raycasting! Raycasting may only be used in the fragment shader effect for interesting shading results, but is absolutely not allowed in any other stages of the pipeline. - -Also, you MAY NOT use OpenGL ANYWHERE in this project, aside from the given OpenGL code for drawing Pixel Buffer Objects to the screen. Use of OpenGL for any pipeline stage instead of your own custom implementation will result in an incomplete project. - -Finally, note that while this basecode is meant to serve as a strong starting point for a CUDA rasterizer, you are not required to use this basecode if you wish, and you may also change any part of the basecode specification as you please, so long as the final rendered result is correct. ------------------------------------------------------------------------------- -CONTENTS: +FEATURES ------------------------------------------------------------------------------- -The Project4 root directory contains the following subdirectories: - -* src/ contains the source code for the project. Both the Windows Visual Studio solution and the OSX makefile reference this folder for all source; the base source code compiles on OSX and Windows without modification. -* objs/ contains example obj test files: cow.obj, cube.obj, tri.obj. -* renders/ contains an example render of the given example cow.obj file with a z-depth fragment shader. -* windows/ contains a Windows Visual Studio 2010 project and all dependencies needed for building and running on Windows 7. - -The Windows and OSX versions of the project build and run exactly the same way as in Project0, Project1, and Project2. - -------------------------------------------------------------------------------- -REQUIREMENTS: -------------------------------------------------------------------------------- -In this project, you are given code for: - -* A library for loading/reading standard Alias/Wavefront .obj format mesh files and converting them to OpenGL style VBOs/IBOs -* A suggested order of kernels with which to implement the graphics pipeline -* Working code for CUDA-GL interop - -You will need to implement the following stages of the graphics pipeline and features: +I implemented following stages of the graphics pipeline and features: * Vertex Shading * Primitive Assembly with support for triangle VBOs/IBOs @@ -56,114 +27,82 @@ You will need to implement the following stages of the graphics pipeline and fea * Fragment to framebuffer writing * A simple lighting/shading scheme, such as Lambert or Blinn-Phong, implemented in the fragment shader -You are also required to implement at least 3 of the following features: - -* Additional pipeline stages. Each one of these stages can count as 1 feature: - * Geometry shader - * Transformation feedback +Extra features: * Back-face culling * Scissor test - * Stencil test - * Blending - -IMPORTANT: For each of these stages implemented, you must also add a section to your README stating what the expected performance impact of that pipeline stage is, and real performance comparisons between your rasterizer with that stage and without. - -* Correct color interpolation between points on a primitive -* Texture mapping WITH texture filtering and perspective correct texture coordinates -* Support for additional primitices. Each one of these can count as HALF of a feature. - * Lines - * Line strips - * Triangle fans - * Triangle strips - * Points -* Anti-aliasing -* Order-independent translucency using a k-buffer -* MOUSE BASED interactive camera support. Interactive camera support based only on the keyboard is not acceptable for this feature. + * Support for additional primitices + * Lines + * Points + * Anti-aliasing ------------------------------------------------------------------------------- -BASE CODE TOUR: +RUNNING THE CODE ------------------------------------------------------------------------------- -You will be working primarily in two files: rasterizeKernel.cu, and rasterizerTools.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 LOOK. +Right click project -> properties -> debugging -> put the obj file here. (obj files must contain v, vn, f) -* rasterizeKernels.cu contains the core rasterization pipeline. - * A suggested sequence of kernels exists in this file, but you may choose to alter the order of this sequence or merge entire kernels if 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 (although there are wrong sequences, such as placing fragment shading before vertex shading), and you may choose any sequence you want. Please document in your README what sequence you choose and why. - * The provided kernels have had their input parameters removed beyond basic inputs such as the framebuffer. You will have to decide what inputs should go into each stage of the pipeline, and what outputs there should be. +Screen interation: +* Press "1": Point Mode (show vertices only) +* Press "2": Wireframe Mode (show edges only) +* Press "3": Fragment Shader Mode (show everything) -* rasterizeTools.h contains various useful tools, including a number of barycentric coordinate related functions that you may find useful in implementing scanline based rasterization... - * A few pre-made structs are included for you to use, such as fragment and triangle. A simple rasterizer can be implemented with these structs as is. However, as with any part of the basecode, you may choose to modify, add to, use as-is, or outright ignore them as you see fit. - * If you do choose to add to the fragment struct, be sure to include in your README a rationale for why. +------------------------------------------------------------------------------- +PERFORMANCE EVALUATION +------------------------------------------------------------------------------- +###PRIMITICES RENDERING MODE +* Blinn-Phong Shader +![alt tag](https://github.com/radiumyang/Project4-Rasterizer/blob/master/buddha_blinn_1.JPG) +* Flat +![alt tag](https://github.com/radiumyang/Project4-Rasterizer/blob/master/dragon_flat_0.JPG) +* LINE +![alt tag](https://github.com/radiumyang/Project4-Rasterizer/blob/master/cow_wire_0.JPG) -You will also want to familiarize yourself with: +* POINT +![alt tag](https://github.com/radiumyang/Project4-Rasterizer/blob/master/buddha_dot_0.JPG) +To implement Point Mode, when rasterizing the triangle, just show the correspondent triangle vertices, no need to check whether one pixel is inside or outside the triangle. Thus, Point Mode has the highest FPS. -* main.cpp, which contains code that transfers VBOs/CBOs/IBOs to the rasterization pipeline. Interactive camera work will also have to be implemented in this file if you choose that feature. -* utilities.h, which serves as a kitchen-sink of useful functions +FPS Comparison between different modes: -------------------------------------------------------------------------------- -SOME RESOURCES: -------------------------------------------------------------------------------- -The following resources may be useful for this project: - -* 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. - * http://133.11.9.3/~takeo/course/2006/media/papers/Direct3D10_siggraph2006.pdf -* Multi-Fragment Effects on the GPU using the k-Buffer - for those who want to do a k-buffer - * http://www.inf.ufrgs.br/~comba/papers/2007/kbuffer_preprint.pdf -* FreePipe: A Programmable, Parallel Rendering Architecture for Efficient Multi-Fragment Effects (I3D 2010) - * 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 +![alt tag](https://github.com/radiumyang/Project4-Rasterizer/blob/master/chart_modes.JPG) -------------------------------------------------------------------------------- -NOTES ON GLM: -------------------------------------------------------------------------------- -This project uses GLM, the GL Math library, for linear algebra. You need to know two important points on how GLM is used in this project: +###BACK-FACE CULLING +without backcull: -* In this project, indices in GLM vectors (such as vec3, vec4), are accessed via swizzling. So, instead of v[0], v.x is used, and instead of v[1], v.y is used, and so on and so forth. -* GLM Matrix operations work fine on NVIDIA Fermi cards and later, but pre-Fermi cards do not play nice with GLM matrices. As such, in this project, GLM matrices are replaced with a custom matrix struct, called a cudaMat4, found in cudaMat4.h. A custom function for multiplying glm::vec4s and cudaMat4s is provided as multiplyMV() in intersections.h. +![alt tag](https://github.com/radiumyang/Project4-Rasterizer/blob/master/back00.JPG) -------------------------------------------------------------------------------- -README -------------------------------------------------------------------------------- -All students must replace or augment the contents of this Readme.md in a clear -manner with the following: +with backcull: -* 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. To create the video you - can use http://www.microsoft.com/expression/products/Encoder4_Overview.aspx -* A performance evaluation (described in detail below). +![alt tag](https://github.com/radiumyang/Project4-Rasterizer/blob/master/back01.JPG) -------------------------------------------------------------------------------- -PERFORMANCE EVALUATION -------------------------------------------------------------------------------- -The performance evaluation 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. +###ANTI-ALIASING +without anti-aliasing: + +![alt tag](https://github.com/radiumyang/Project4-Rasterizer/blob/master/antia_03.JPG) + +with anti-aliasing: + +![alt tag](https://github.com/radiumyang/Project4-Rasterizer/blob/master/antia_04.JPG) + +For pixel(i,j), I use the average color value of points from pixel(i-2, j-2) to pixel(i+2, j+2) as the color of current pixel(i,j). + +###SCISSOR TEST + +The Scissor Test is a Per-Sample Processing operation that discards Fragments that fall outside of a certain rectangular portion of the screen. + +When rasterizing the triangles, I set the scissor window as bounding box to limit the pixels that we need to process, which can help save efficiency on checking useless out-of-bound points. + +![alt tag](https://github.com/radiumyang/Project4-Rasterizer/blob/master/scissor.JPG) + -Each student should provide no more than a one page summary of their -optimizations along with tables and or graphs to visually explain any -performance differences. -------------------------------------------------------------------------------- -THIRD PARTY CODE POLICY -------------------------------------------------------------------------------- -* Use of any third-party code must be approved by asking on Piazza. 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 ray 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 result in you receiving an F for the semester. ------------------------------------------------------------------------------- -SELF-GRADING +References ------------------------------------------------------------------------------- -* On the submission date, email your grade, on a scale of 0 to 100, to Liam, harmoli+cis565@seas.upenn.edu, with a one paragraph explanation. Be concise and realistic. Recall that we reserve 30 points as a sanity check to adjust your grade. Your actual grade will be (0.7 * your grade) + (0.3 * our grade). We hope to only use this in extreme cases when your grade does not realistically reflect your work - it is either too high or too low. In most cases, we plan to give you the exact grade you suggest. -* Projects are not weighted evenly, e.g., Project 0 doesn't count as much as the path tracer. We will determine the weighting at the end of the semester based on the size of each project. +* Perspective/ Viewport Transformation: http://www.songho.ca/opengl/gl_transform.html +* Normal Transformation: http://www.songho.ca/opengl/gl_normaltransform.html +* Triangle Rasterization: http://fgiesen.wordpress.com/2013/02/08/triangle-rasterization-in-practice/ +* Blinn-Phong Fragment Shader: http://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_shading_model --- SUBMISSION diff --git a/antia_00.JPG b/antia_00.JPG new file mode 100644 index 0000000..1632005 Binary files /dev/null and b/antia_00.JPG differ diff --git a/antia_01.JPG b/antia_01.JPG new file mode 100644 index 0000000..58c4ba7 Binary files /dev/null and b/antia_01.JPG differ diff --git a/antia_03.JPG b/antia_03.JPG new file mode 100644 index 0000000..97bfd61 Binary files /dev/null and b/antia_03.JPG differ diff --git a/antia_04.JPG b/antia_04.JPG new file mode 100644 index 0000000..e9bb5c2 Binary files /dev/null and b/antia_04.JPG differ diff --git a/back00.JPG b/back00.JPG new file mode 100644 index 0000000..4af204c Binary files /dev/null and b/back00.JPG differ diff --git a/back01.JPG b/back01.JPG new file mode 100644 index 0000000..1a64d2e Binary files /dev/null and b/back01.JPG differ diff --git a/buddha_blinn_0.JPG b/buddha_blinn_0.JPG new file mode 100644 index 0000000..7916f21 Binary files /dev/null and b/buddha_blinn_0.JPG differ diff --git a/buddha_blinn_1.JPG b/buddha_blinn_1.JPG new file mode 100644 index 0000000..acfb218 Binary files /dev/null and b/buddha_blinn_1.JPG differ diff --git a/buddha_blinn_2.JPG b/buddha_blinn_2.JPG new file mode 100644 index 0000000..415b11e Binary files /dev/null and b/buddha_blinn_2.JPG differ diff --git a/buddha_dot_0.JPG b/buddha_dot_0.JPG new file mode 100644 index 0000000..eb7f48c Binary files /dev/null and b/buddha_dot_0.JPG differ diff --git a/chart_modes.JPG b/chart_modes.JPG new file mode 100644 index 0000000..cad290d Binary files /dev/null and b/chart_modes.JPG differ diff --git a/cow_blinn_0.JPG b/cow_blinn_0.JPG new file mode 100644 index 0000000..2d5329b Binary files /dev/null and b/cow_blinn_0.JPG differ diff --git a/cow_blinn_1.JPG b/cow_blinn_1.JPG new file mode 100644 index 0000000..1ecdaaf Binary files /dev/null and b/cow_blinn_1.JPG differ diff --git a/cow_blinn_2.JPG b/cow_blinn_2.JPG new file mode 100644 index 0000000..5f012de Binary files /dev/null and b/cow_blinn_2.JPG differ diff --git a/cow_dot_0.JPG b/cow_dot_0.JPG new file mode 100644 index 0000000..72cf24d Binary files /dev/null and b/cow_dot_0.JPG differ diff --git a/cow_wire_0.JPG b/cow_wire_0.JPG new file mode 100644 index 0000000..28780c0 Binary files /dev/null and b/cow_wire_0.JPG differ diff --git a/dragon_blinn_0.JPG b/dragon_blinn_0.JPG new file mode 100644 index 0000000..959dd13 Binary files /dev/null and b/dragon_blinn_0.JPG differ diff --git a/dragon_blinn_1.JPG b/dragon_blinn_1.JPG new file mode 100644 index 0000000..dd10a37 Binary files /dev/null and b/dragon_blinn_1.JPG differ diff --git a/dragon_dot_0.JPG b/dragon_dot_0.JPG new file mode 100644 index 0000000..4dd855f Binary files /dev/null and b/dragon_dot_0.JPG differ diff --git a/dragon_flat_0.JPG b/dragon_flat_0.JPG new file mode 100644 index 0000000..e73e9b1 Binary files /dev/null and b/dragon_flat_0.JPG differ diff --git a/dragon_has_antia.JPG b/dragon_has_antia.JPG new file mode 100644 index 0000000..1ef7685 Binary files /dev/null and b/dragon_has_antia.JPG differ diff --git a/dragon_has_antia2.JPG b/dragon_has_antia2.JPG new file mode 100644 index 0000000..36d3c82 Binary files /dev/null and b/dragon_has_antia2.JPG differ diff --git a/dragon_no_antia.JPG b/dragon_no_antia.JPG new file mode 100644 index 0000000..eebdb87 Binary files /dev/null and b/dragon_no_antia.JPG differ diff --git a/rasterizer_radiumyang.wmv b/rasterizer_radiumyang.wmv new file mode 100644 index 0000000..677177c Binary files /dev/null and b/rasterizer_radiumyang.wmv differ diff --git a/scissor.JPG b/scissor.JPG new file mode 100644 index 0000000..f245048 Binary files /dev/null and b/scissor.JPG differ diff --git a/src/main.cpp b/src/main.cpp index 13d8e67..4709a2a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,7 +2,6 @@ // Written by Yining Karl Li, Copyright (c) 2012 University of Pennsylvania #include "main.h" - //------------------------------- //-------------MAIN-------------- //------------------------------- @@ -18,6 +17,7 @@ int main(int argc, char** argv){ //renderScene = new scene(data); mesh = new obj(); objLoader* loader = new objLoader(data, mesh); + mesh->buildVBOs(); delete loader; loadedScene = true; @@ -25,10 +25,32 @@ int main(int argc, char** argv){ } if(!loadedScene){ - cout << "Usage: mesh=[obj file]" << endl; + cout << "Usage: mesh=[obj file]\n !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << endl; return 0; } + Mmodel = glm::mat4(1.0); + Mprojection = glm::perspective(fovy, float(width) / float(height), depth_near, depth_far); + Mview = glm::lookAt( Veye, Vcenter, Vup); + + // BMP img; + //char* filename = "texture0.bmp"; + //img.ReadFromFile(filename); + //texture_width = img.TellWidth(); + //texture_height = img.TellHeight(); + //textureBMP = new glm::vec3[texture_width * texture_height]; + //for(int j = 0; jRed/255.0f; + // float g = img(i,j)->Green/255.0f; + // float b = img(i,j)->Blue/255.0f; + // textureBMP[i+j*texture_height] = glm::vec3(r,g,b); + // // printf("r %f, g %f, b%f",r,g,b); + // } + // } + frame = 0; seconds = time (NULL); fpstracker = 0; @@ -93,14 +115,25 @@ void runCuda(){ ibo = mesh->getIBO(); ibosize = mesh->getIBOsize(); + nbo = mesh->getNBO(); + nbosize = mesh->getNBOsize(); + + /////ra + Mmodel = glm::rotate(Mmodel, (float)1.0f, glm::vec3(0,1,0)); + + cudaGLMapBufferObject((void**)&dptr, pbo); - cudaRasterizeCore(dptr, glm::vec2(width, height), frame, vbo, vbosize, cbo, cbosize, ibo, ibosize); + cudaRasterizeCore(dptr, glm::vec2(width, height), frame, vbo, vbosize, cbo, cbosize, ibo, ibosize, nbo, nbosize, Veye, Mmodel, Mview, Mprojection, depth_near, depth_far, mode); cudaGLUnmapBufferObject(pbo); vbo = NULL; cbo = NULL; ibo = NULL; + ///////ra + nbo = NULL; + + frame++; fpstracker++; @@ -281,4 +314,13 @@ void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS){ glfwSetWindowShouldClose(window, GL_TRUE); } + if(key == GLFW_KEY_1 && action == GLFW_PRESS){ + mode = 0; + } + if(key == GLFW_KEY_2 && action == GLFW_PRESS){ + mode = 1; + } + if(key == GLFW_KEY_3 && action == GLFW_PRESS){ + mode = 2; + } } \ No newline at end of file diff --git a/src/main.h b/src/main.h index 8999110..926120e 100644 --- a/src/main.h +++ b/src/main.h @@ -18,11 +18,12 @@ #include #include #include - +#include #include "rasterizeKernels.h" #include "utilities.h" + using namespace std; //------------------------------- @@ -50,6 +51,29 @@ int cbosize; int* ibo; int ibosize; +float* nbo; +int nbosize; + +// camera +float fovy = 60.0f; +float depth_near = 0.1f; +float depth_far = 100.0f; + + +//glm::vec3 Veye(0, 0.5, 2.8f); +glm::vec3 Veye(0, 0.8, 1.0f); +//glm::vec3 Vcenter(0, 1.0f, 0); +glm::vec3 Vcenter(0, 0.3f, 0); +glm::vec3 Vup(0, 1.0f, 0); + + +glm::mat4 Mmodel; +glm::mat4 Mprojection; +glm::mat4 Mview; + +int mode = 2; + + //------------------------------- //----------CUDA STUFF----------- //------------------------------- @@ -85,6 +109,8 @@ void initTextures(); void initVAO(); GLuint initShader(); + + //------------------------------- //---------CLEANUP STUFF--------- //------------------------------- diff --git a/src/rasterizeKernels.cu b/src/rasterizeKernels.cu index 10b0000..5881780 100644 --- a/src/rasterizeKernels.cu +++ b/src/rasterizeKernels.cu @@ -8,13 +8,26 @@ #include "rasterizeKernels.h" #include "rasterizeTools.h" +///////////////////features////////////////////////////// +#define BLINN_PHONG 1 +#define BACKFACECULL 0 +#define ANTI_ALIASING 1 +#define SCISSOR_TEST 0 +////////////////////////////////////////////////////////// + +#define LIGHTNUM 3 glm::vec3* framebuffer; fragment* depthbuffer; float* device_vbo; float* device_cbo; int* device_ibo; +float* device_nbo; triangle* primitives; +//ra +light* lights; +light* device_lights; + void checkCUDAError(const char *msg) { cudaError_t err = cudaGetLastError(); if( cudaSuccess != err) { @@ -129,50 +142,302 @@ __global__ void sendImageToPBO(uchar4* PBOpos, glm::vec2 resolution, glm::vec3* } //TODO: Implement a vertex shader -__global__ void vertexShadeKernel(float* vbo, int vbosize){ +__global__ void vertexShadeKernel(float* vbo, int vbosize, float* nbo, glm::mat4 Mmodel, glm::mat4 Mview, glm::mat4 Mprojection, glm::vec2 resolution, float depth_near, float depth_far){ int index = (blockIdx.x * blockDim.x) + threadIdx.x; - if(index 0.001f || newN.y > 0.001f || newN.z > 0.001f) + // printf("normal: %f, %f, %f", newNn.x, newNn.y, newNn.z); } } +__global__ void primitiveWorldPosKernel(float* vbo, int vbosize, int* ibo, int ibosize, triangle* primitives){ + ////////////////save world pos to triangle///////////////// + int index = (blockIdx.x * blockDim.x) + threadIdx.x; + int primitivesCount = ibosize/3; + if(index -depth_far) + { + depthbuffer[depthIndex] = myFrag; + } + } + } + + }//x + }//y } } + +__device__ glm::vec3 myNormalize(glm::vec3 norm) +{ + if(glm::length(norm)< 0.0001f) + return norm; + else + return glm::normalize(norm); +} + //TODO: Implement a fragment shader -__global__ void fragmentShadeKernel(fragment* depthbuffer, glm::vec2 resolution){ +__global__ void fragmentShadeKernel(fragment* depthbuffer, glm::vec2 resolution, light* lights, glm::vec3 Veye, glm::mat4 Mmodel, glm::mat4 Mprojection, glm::mat4 Mview){ int x = (blockIdx.x * blockDim.x) + threadIdx.x; int y = (blockIdx.y * blockDim.y) + threadIdx.y; int index = x + (y * resolution.x); if(x<=resolution.x && y<=resolution.y){ +#if BLINN_PHONG == 1 + ////// Blinn-Phong http://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_shading_model //////////// + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + glm::vec3 myPos = depthbuffer[index].position; + ///// change back to world coordination !!! ///// + glm::vec3 myPosWorld = glm::vec3((glm::inverse(Mprojection) * glm::inverse(Mmodel * Mview) * glm::vec4(myPos,1.0f))); + + glm::vec3 myNorm = glm::normalize(depthbuffer[index].normal); + + for(int l = 0; l < LIGHTNUM; l++) + { + glm::vec3 lightDir = myNormalize( lights[l].position - myPosWorld ); + float dist = glm::length(lightDir) * glm::length(lightDir); + + float NdotL = glm::dot(myNorm, lightDir); + NdotL = (NdotL > 0) ? NdotL : 0; + glm::vec3 diffuseColor = NdotL * depthbuffer[index].color/dist; + + glm::vec3 viewDir= myNormalize( Veye - myPosWorld ); + glm::vec3 H = myNormalize( lightDir + viewDir); + + float NdotH = glm::dot( myNorm, H); + NdotH = ( NdotH > 0) ? NdotH : 0; + float intensity = pow(NdotH, 20); + glm::vec3 specularColor = glm::vec3(1,1,1) * intensity/dist; + + depthbuffer[index].color += (lights[l].emit * lights[l].color * (0.7f * diffuseColor + 0.3f * specularColor))/(float)LIGHTNUM; + } + // printf("color: %f, %f, %f", depthbuffer[index].color.x, depthbuffer[index].color.y, depthbuffer[index].color.z); +#endif + +#if BLINN_PHONG == 0 + for(int l = 0; l < LIGHTNUM; l++) + { + depthbuffer[index].color += (lights[l].color) / (float)LIGHTNUM; + } +#endif } } //Writes fragment colors to the framebuffer -__global__ void render(glm::vec2 resolution, fragment* depthbuffer, glm::vec3* framebuffer){ +__global__ void render(glm::vec2 resolution, fragment* depthbuffer, glm::vec3* framebuffer, int mode){ int x = (blockIdx.x * blockDim.x) + threadIdx.x; int y = (blockIdx.y * blockDim.y) + threadIdx.y; int index = x + (y * resolution.x); + #if ANTI_ALIASING == 1 + if(mode == 2) //only apply to face mode + { glm::vec3 colorSum(0,0,0); + for(int i = -1; i<=1; i++) + { + for(int j = -1; j<=1; j++) + { + int newx = x+i; int newy = y+j; + if(newx >= 0 && newx < resolution.x && newy >= 0 && newy < resolution.y) + { + int tmp = newx + newy * resolution.x; + colorSum += depthbuffer[tmp].color; + } + } + } + framebuffer[index] = colorSum / 9.0f; + } + +#endif + if(x<=resolution.x && y<=resolution.y){ framebuffer[index] = depthbuffer[index].color; } } // Wrapper for the __global__ call that sets up the kernel calls and does a ton of memory management -void cudaRasterizeCore(uchar4* PBOpos, glm::vec2 resolution, float frame, float* vbo, int vbosize, float* cbo, int cbosize, int* ibo, int ibosize){ +void cudaRasterizeCore(uchar4* PBOpos, glm::vec2 resolution, float frame, float* vbo, int vbosize, float* cbo, int cbosize, int* ibo, int ibosize, float* nbo, int nbosize, glm::vec3 Veye, + glm::mat4 Mmodel, glm::mat4 Mview, glm::mat4 Mprojection, float depth_near, float depth_far, int mode){ // set up crucial magic int tileSize = 8; @@ -202,6 +467,22 @@ void cudaRasterizeCore(uchar4* PBOpos, glm::vec2 resolution, float frame, float* primitives = NULL; cudaMalloc((void**)&primitives, (ibosize/3)*sizeof(triangle)); + //ra + lights = new light[LIGHTNUM]; + lights[0].position = glm::vec3(-5, 10, 8); + lights[0].color = glm::vec3(0.9, 0.4, 0.9); + lights[0].emit = 8.0f; + lights[1].position = glm::vec3(7, -10, 12); + lights[1].color = glm::vec3(1, 0.8, 0); + lights[1].emit = 8.0f; + lights[2].position = glm::vec3(0, 20, 0); + lights[2].color = glm::vec3(0.2, 1, 0.3); + lights[2].emit = 7.0f; + + device_lights = NULL; + cudaMalloc((void**)&device_lights, LIGHTNUM*sizeof(light)); + cudaMemcpy( device_lights, lights, LIGHTNUM*sizeof(light), cudaMemcpyHostToDevice); + device_ibo = NULL; cudaMalloc((void**)&device_ibo, ibosize*sizeof(int)); cudaMemcpy( device_ibo, ibo, ibosize*sizeof(int), cudaMemcpyHostToDevice); @@ -214,38 +495,54 @@ void cudaRasterizeCore(uchar4* PBOpos, glm::vec2 resolution, float frame, float* cudaMalloc((void**)&device_cbo, cbosize*sizeof(float)); cudaMemcpy( device_cbo, cbo, cbosize*sizeof(float), cudaMemcpyHostToDevice); + device_nbo = NULL; + cudaMalloc((void**)&device_nbo, nbosize*sizeof(float)); + cudaMemcpy( device_nbo, nbo, nbosize*sizeof(float), cudaMemcpyHostToDevice); + + + tileSize = 32; int primitiveBlocks = ceil(((float)vbosize/3)/((float)tileSize)); + //------------------------------ + //save world vertex pos + //------------------------------ + primitiveBlocks = ceil(((float)ibosize/3)/((float)tileSize)); + primitiveWorldPosKernel<<>>(device_vbo, vbosize, device_ibo, ibosize, primitives); + cudaDeviceSynchronize(); + //------------------------------ //vertex shader //------------------------------ - vertexShadeKernel<<>>(device_vbo, vbosize); + primitiveBlocks = ceil(((float)vbosize/3)/((float)tileSize)); + vertexShadeKernel<<>>(device_vbo, vbosize, device_nbo, Mmodel, Mview, Mprojection, resolution, depth_near, depth_far); cudaDeviceSynchronize(); //------------------------------ //primitive assembly //------------------------------ primitiveBlocks = ceil(((float)ibosize/3)/((float)tileSize)); - primitiveAssemblyKernel<<>>(device_vbo, vbosize, device_cbo, cbosize, device_ibo, ibosize, primitives); + primitiveAssemblyKernel<<>>(device_vbo, vbosize, device_cbo, cbosize, device_ibo, ibosize, device_nbo, nbosize, primitives, Veye); cudaDeviceSynchronize(); //------------------------------ //rasterization //------------------------------ - rasterizationKernel<<>>(primitives, ibosize/3, depthbuffer, resolution); + rasterizationKernel<<>>(primitives, ibosize/3, depthbuffer, resolution, depth_near, depth_far, mode); cudaDeviceSynchronize(); //------------------------------ //fragment shader //------------------------------ - fragmentShadeKernel<<>>(depthbuffer, resolution); + if(mode == 2) {//face mode + fragmentShadeKernel<<>>(depthbuffer, resolution, device_lights, Veye, Mmodel, Mprojection, Mview); + } cudaDeviceSynchronize(); //------------------------------ //write fragments to framebuffer //------------------------------ - render<<>>(resolution, depthbuffer, framebuffer); + render<<>>(resolution, depthbuffer, framebuffer, mode); sendImageToPBO<<>>(PBOpos, resolution, framebuffer); cudaDeviceSynchronize(); @@ -260,6 +557,7 @@ void kernelCleanup(){ cudaFree( device_vbo ); cudaFree( device_cbo ); cudaFree( device_ibo ); + cudaFree( device_nbo ); cudaFree( framebuffer ); cudaFree( depthbuffer ); } diff --git a/src/rasterizeKernels.h b/src/rasterizeKernels.h index 784be17..6ff49f0 100644 --- a/src/rasterizeKernels.h +++ b/src/rasterizeKernels.h @@ -11,6 +11,7 @@ #include "glm/glm.hpp" void kernelCleanup(); -void cudaRasterizeCore(uchar4* pos, glm::vec2 resolution, float frame, float* vbo, int vbosize, float* cbo, int cbosize, int* ibo, int ibosize); +void cudaRasterizeCore(uchar4* pos, glm::vec2 resolution, float frame, float* vbo, int vbosize, float* cbo, int cbosize, int* ibo, int ibosize, float* nbo, int nbosize, glm::vec3 Veye, + glm::mat4 Mmodel, glm::mat4 Mview, glm::mat4 Mprojection, float depth_near, float depth_far, int mode); #endif //RASTERIZEKERNEL_H diff --git a/src/rasterizeTools.h b/src/rasterizeTools.h index e9b5dcc..d772b2c 100644 --- a/src/rasterizeTools.h +++ b/src/rasterizeTools.h @@ -16,6 +16,16 @@ struct triangle { glm::vec3 c0; glm::vec3 c1; glm::vec3 c2; + /////////////ra: normals + glm::vec3 n0; + glm::vec3 n1; + glm::vec3 n2; + /////////////ra: world pos + glm::vec3 pw0; + glm::vec3 pw1; + glm::vec3 pw2; + ////////////ra: back face cull + bool isdead; }; struct fragment{ @@ -24,6 +34,12 @@ struct fragment{ glm::vec3 position; }; +struct light{ + glm::vec3 color; + glm::vec3 position; + float emit; +}; + //Multiplies a cudaMat4 matrix and a vec4 __host__ __device__ glm::vec3 multiplyMV(cudaMat4 m, glm::vec4 v){ glm::vec3 r(1,1,1); diff --git a/windows/PROJ4_Rasterizer/PROJ4_Rasterizer/PROJ4_Rasterizer.vcxproj b/windows/PROJ4_Rasterizer/PROJ4_Rasterizer/PROJ4_Rasterizer.vcxproj index f640485..7a6dcc4 100644 --- a/windows/PROJ4_Rasterizer/PROJ4_Rasterizer/PROJ4_Rasterizer.vcxproj +++ b/windows/PROJ4_Rasterizer/PROJ4_Rasterizer/PROJ4_Rasterizer.vcxproj @@ -28,7 +28,7 @@ - + @@ -87,6 +87,6 @@ - + \ No newline at end of file