diff options
Diffstat (limited to 'dev/MinGfx/src/default_shader.h')
-rw-r--r-- | dev/MinGfx/src/default_shader.h | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/dev/MinGfx/src/default_shader.h b/dev/MinGfx/src/default_shader.h new file mode 100644 index 0000000..677acae --- /dev/null +++ b/dev/MinGfx/src/default_shader.h @@ -0,0 +1,168 @@ +/* + This file is part of the MinGfx Project. + + Copyright (c) 2017,2018 Regents of the University of Minnesota. + All Rights Reserved. + + Original Author(s) of this File: + Dan Keefe, 2018, University of Minnesota + + Author(s) of Significant Updates/Modifications to the File: + ... + */ + +#ifndef SRC_DEFAULT_SHADER_H_ +#define SRC_DEFAULT_SHADER_H_ + +#include "color.h" +#include "point3.h" +#include "shader_program.h" +#include "texture2d.h" +#include "vector3.h" +#include "matrix4.h" +#include "mesh.h" + + + +namespace mingfx { + +/** A simple GLSL shader for textured per-fragment Phong shading with multiple + light sources. This can be used to draw 3D models stored in a mingfx::Mesh + data structure or you can use it with your own geometry data structures. + Lighting properties are stored within the class itself since these are considered + part of the shading model. Material properties are considered properties of the + meshes or other materials you wish to draw so these are stored outside of the + class and passed into the Draw() or UseProgram() functions. + + An example of using DefaultShader to render a mesh: + ~~~ + DefaultShader phong_shader; + Mesh teapot; + DefaultShader::MaterialProperties teapot_material; + + void Init() { + // initialize the shader + DefaultShader::LightProperties red_light; + red_light.position = Point3(-10, 5, 5); + red_light.diffuseIntensity = Color(1,0,0); + phong_shader.AddLight(red_light); + + // initialize the mesh + teapot.LoadFromOBJ(Platform::FindMinGfxDataFile("teapot.obj")); + } + + void DrawUsingOpenGL() { + Matrix4 M; + Matrix4 V = Matrix4::LookAt(Point3(0,0,3), Point3(0,0,0), Vector3(0,1,0)); + Matrix4 P = Matrix4::Perspective(60.0, aspect_ratio(), 0.1, 10.0); + phong_shader.Draw(M, V, P, teapot, teapot_material); + } + ~~~ + */ +class DefaultShader { +public: + + /// If changed, this needs to also be changed in the glsl shader code + static const unsigned int MAX_LIGHTS = 10; + + + /// Small data structure to hold properties of the material to be lit + class MaterialProperties { + public: + Color ambient_reflectance; + Color diffuse_reflectance; + Color specular_reflectance; + float shinniness; + Texture2D surface_texture; + // eventually, this might include a normal map, etc. + + // defaults + MaterialProperties() : + ambient_reflectance(0.25f, 0.25f, 0.25f), + diffuse_reflectance(0.6f, 0.6f, 0.6f), + specular_reflectance(0.4f, 0.4f, 0.4f), + shinniness(20.0f) {} + }; + + /// Small data structure to hold per-light properties + class LightProperties { + public: + Point3 position; + Color ambient_intensity; + Color diffuse_intensity; + Color specular_intensity; + + // defaults + LightProperties() : + position(10.0f, 10.0f, 10.0f), + ambient_intensity(0.25f, 0.25f, 0.25f), + diffuse_intensity(0.6f, 0.6f, 0.6f), + specular_intensity(0.6f, 0.6f, 0.6f) {} + }; + + /// The constructor defaults to adding a single white light to the scene at + /// (10,10,10). Change this by passing it 'false'. The constructor does + /// not load and compile the shader right away. This is done inside Init(). + DefaultShader(bool add_default_light=true); + + virtual ~DefaultShader(); + + /// Multiple lights are supported, this adds one to the end of the list. + /// Up to MAX_LIGHTS can be added. + void AddLight(LightProperties light); + + /// Changes the properties for a light that was already added. + void SetLight(int i, LightProperties light); + + + /// This loads vertex and fragment shaders from files, compiles them, and + /// links them. So, it must be called from within an active OpenGL context, + /// for example, from within GraphicsApp::Init() or GraphicsApp::DrawUsingOpenGL(). + /// If you call Draw() before calling Init(), then Init() will be called as + /// the first step within Draw(). So, if you do not mind a slowdown on the + /// very first frame of your program, it is fine to skip calling Init(). + void Init(); + + /// This starts the shader and sets its uniform variables based upon the + /// current set of lights, the material properties passed in, and the + /// model, view, and projection matrices. Then, it calls mesh->Draw(). + /// After drawing, it disables the shader. + void Draw(const Matrix4 &model, const Matrix4 &view, const Matrix4 &projection, + Mesh *mesh, const MaterialProperties &material); + + + /// Only needed if you do not want to draw a Mesh. + /// This does all of the same setup for drawing that the Draw() function does + /// and then it returns so that you may draw your own geometry however you want. + /// After doing your draw must call StopProgram() to turn off the shader. + void UseProgram(const Matrix4 &model, const Matrix4 &view, const Matrix4 &projection, + const MaterialProperties &material); + + /// Only needed if you do not want to draw a Mesh. Call this after UseProgram() + /// and after drawing your geometry to turn off the shader. + void StopProgram(); + + + int num_lights(); + + LightProperties light(int i); + + +private: + + std::vector<LightProperties> lights_; + + // cached raw float arrays store data to send directly to the gpu + // GLSL requires fixed size arrays for these + float lightPositions_[3*MAX_LIGHTS]; + float lightIas_[4*MAX_LIGHTS]; + float lightIds_[4*MAX_LIGHTS]; + float lightIss_[4*MAX_LIGHTS]; + void update_light_arrays(); + + ShaderProgram phongShader_; +}; + +} // end namespace + +#endif
\ No newline at end of file |