From 30c8058fca39e4d6566b2fc06ae2498c48c00717 Mon Sep 17 00:00:00 2001 From: victorfisac Date: Fri, 20 May 2016 17:18:07 +0200 Subject: [PATCH 1/6] Add standard lighting (1/3) - Ambient and lambert lighting added. - Ambient and diffuse colors linked to standard shader. - Single light linked to standard shader. - LoadStandardMaterial() and depending functions added. --- src/models.c | 6 +-- src/raylib.h | 9 ++-- src/rlgl.c | 149 ++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 131 insertions(+), 33 deletions(-) diff --git a/src/models.c b/src/models.c index 414f6716d..2629dffdb 100644 --- a/src/models.c +++ b/src/models.c @@ -732,13 +732,13 @@ Material LoadDefaultMaterial(void) return material; } -// Load standard material (uses standard models shader) +// Load standard material (uses material attributes and lighting shader) // NOTE: Standard shader supports multiple maps and lights Material LoadStandardMaterial(void) { Material material = LoadDefaultMaterial(); - //material.shader = GetStandardShader(); + material.shader = GetStandardShader(); return material; } @@ -1240,7 +1240,7 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota //Matrix matModel = MatrixMultiply(model.transform, matTransform); // Transform to world-space coordinates model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation); - model.material.colDiffuse = tint; + // model.material.colDiffuse = tint; rlglDrawMesh(model.mesh, model.material, model.transform); } diff --git a/src/raylib.h b/src/raylib.h index d98a0797f..48534fd6d 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -398,7 +398,7 @@ typedef struct Shader { // Uniform locations int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader) - int tintColorLoc; // Color uniform location point (fragment shader) + int tintColorLoc; // Diffuse color uniform location point (fragment shader) // Texture map locations int mapDiffuseLoc; // Diffuse map texture uniform location point (fragment shader) @@ -444,11 +444,8 @@ typedef struct LightData { float intensity; Color specular; - //float specFactor; // Specular intensity ? - - //Color ambient; // Required? - float coneAngle; // SpotLight + float coneAngle; // SpotLight } LightData, *Light; // Light types @@ -836,6 +833,7 @@ void SetModelTexture(Model *model, Texture2D texture); // Link a textur Material LoadMaterial(const char *fileName); // Load material data (from file) Material LoadDefaultMaterial(void); // Load default material (uses default models shader) +Material LoadStandardMaterial(void); // Load standard material (uses material attributes and lighting shader) void UnloadMaterial(Material material); // Unload material textures from VRAM void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) @@ -865,6 +863,7 @@ void UnloadShader(Shader shader); // Unload a void SetDefaultShader(void); // Set default shader to be used in batch draw void SetCustomShader(Shader shader); // Set custom shader to be used in batch draw Shader GetDefaultShader(void); // Get default shader +Shader GetStandardShader(void); // Get default shader Texture2D GetDefaultTexture(void); // Get default texture int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location diff --git a/src/rlgl.c b/src/rlgl.c index c5048affe..e2195e4d1 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -191,6 +191,7 @@ static bool useTempBuffer = false; // Shader Programs static Shader defaultShader; +static Shader standardShader; static Shader currentShader; // By default, defaultShader // Flags for supported extensions @@ -236,6 +237,7 @@ static Shader LoadDefaultShader(void); // Load default shader (just vertex static Shader LoadStandardShader(void); // Load standard shader (support materials and lighting) static void LoadDefaultShaderLocations(Shader *shader); // Bind default shader locations (attributes and uniforms) static void UnloadDefaultShader(void); // Unload default shader +static void UnloadStandardShader(void); // Unload standard shader static void LoadDefaultBuffers(void); // Load default internal buffers (lines, triangles, quads) static void UpdateDefaultBuffers(void); // Update default internal buffers (VAOs/VBOs) with vertex data @@ -1018,6 +1020,7 @@ void rlglInit(void) // Init default Shader (customized for GL 3.3 and ES2) defaultShader = LoadDefaultShader(); + standardShader = LoadStandardShader(); currentShader = defaultShader; LoadDefaultBuffers(); // Initialize default vertex arrays buffers (lines, triangles, quads) @@ -1046,6 +1049,7 @@ void rlglClose(void) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) UnloadDefaultShader(); + UnloadStandardShader(); UnloadDefaultBuffers(); // Delete default white texture @@ -1757,19 +1761,30 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) // Send combined model-view-projection matrix to shader glUniformMatrix4fv(material.shader.mvpLoc, 1, false, MatrixToFloat(matMVP)); - - // Setup shader uniforms for material related data - // TODO: Check if using standard shader to get location points // Upload to shader material.colDiffuse float vColorDiffuse[4] = { (float)material.colDiffuse.r/255, (float)material.colDiffuse.g/255, (float)material.colDiffuse.b/255, (float)material.colDiffuse.a/255 }; glUniform4fv(material.shader.tintColorLoc, 1, vColorDiffuse); + + // Check if using standard shader to get location points + // NOTE: standard shader specific locations are got at render time to keep Shader struct as simple as possible (with just default shader locations) + if(material.shader.id == standardShader.id) + { + // Send model transformations matrix to shader + glUniformMatrix4fv(glGetUniformLocation(material.shader.id, "modelMatrix"), 1, false, MatrixToFloat(transform)); + + // Setup shader uniforms for lights + SetShaderLights(material.shader); + + // Upload to shader material.colAmbient + glUniform4f(glGetUniformLocation(material.shader.id, "colAmbient"), (float)material.colAmbient.r/255, (float)material.colAmbient.g/255, (float)material.colAmbient.b/255, (float)material.colAmbient.a/255); + + // Upload to shader material.colSpecular + glUniform4f(glGetUniformLocation(material.shader.id, "colSpecular"), (float)material.colSpecular.r/255, (float)material.colSpecular.g/255, (float)material.colSpecular.b/255, (float)material.colSpecular.a/255); - // TODO: Upload to shader material.colAmbient - // glUniform4f(???, (float)material.colAmbient.r/255, (float)material.colAmbient.g/255, (float)material.colAmbient.b/255, (float)material.colAmbient.a/255); - - // TODO: Upload to shader material.colSpecular - // glUniform4f(???, (float)material.colSpecular.r/255, (float)material.colSpecular.g/255, (float)material.colSpecular.b/255, (float)material.colSpecular.a/255); + // TODO: Upload to shader glossiness + //glUniform1f(???, material.glossiness); + } // Set shader textures (diffuse, normal, specular) glActiveTexture(GL_TEXTURE0); @@ -1791,13 +1806,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, material.texSpecular.id); glUniform1i(material.shader.mapSpecularLoc, 2); // Texture fits in active texture unit 2 - - // TODO: Upload to shader glossiness - //glUniform1f(???, material.glossiness); } - - // Setup shader uniforms for lights - //SetShaderLights(material.shader); if (vaoSupported) { @@ -2148,6 +2157,17 @@ Shader GetDefaultShader(void) #endif } +// Get default shader +Shader GetStandardShader(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + return standardShader; +#else + Shader shader = { 0 }; + return shader; +#endif +} + // Get shader uniform location int GetShaderLocation(Shader shader, const char *uniformName) { @@ -2499,13 +2519,75 @@ static Shader LoadStandardShader(void) { Shader shader; - char *vShaderStr; - char *fShaderStr; - - // TODO: Implement standard uber-shader, supporting all features (GLSL 100 / GLSL 330) - - // NOTE: Shader could be quite extensive so it could be implemented in external files (standard.vs/standard.fs) - + // Vertex shader directly defined, no external file required +#if defined(GRAPHICS_API_OPENGL_33) + char vShaderStr[] = "#version 330 \n" + "in vec3 vertexPosition; \n" + "in vec3 vertexNormal; \n" + "in vec2 vertexTexCoord; \n" + "in vec4 vertexColor; \n" + "out vec2 fragTexCoord; \n" + "out vec4 fragColor; \n" + "out vec3 fragNormal; \n" +#elif defined(GRAPHICS_API_OPENGL_ES2) + char vShaderStr[] = "#version 100 \n" + "attribute vec3 vertexPosition; \n" + "attribute vec3 vertexNormal; \n" + "attribute vec2 vertexTexCoord; \n" + "attribute vec4 vertexColor; \n" + "varying vec2 fragTexCoord; \n" + "varying vec4 fragColor; \n" + "varying vec3 fragNormal; \n" +#endif + "uniform mat4 mvpMatrix; \n" + "uniform mat4 modelMatrix; \n" + "void main() \n" + "{ \n" + " fragTexCoord = vertexTexCoord; \n" + " fragColor = vertexColor; \n" + " mat3 normalMatrix = transpose(inverse(mat3(modelMatrix))); \n" + " fragNormal = normalize(normalMatrix*vertexNormal); \n" + " gl_Position = mvpMatrix*vec4(vertexPosition, 1.0); \n" + "} \n"; + + // TODO: add specular calculation, multi-lights structs and light type calculations (directional, point, spot) + // Fragment shader directly defined, no external file required +#if defined(GRAPHICS_API_OPENGL_33) + char fShaderStr[] = "#version 330 \n" + "in vec2 fragTexCoord; \n" + "in vec4 fragColor; \n" + "in vec3 fragNormal; \n" + "out vec4 finalColor; \n" +#elif defined(GRAPHICS_API_OPENGL_ES2) + char fShaderStr[] = "#version 100 \n" + "precision mediump float; \n" // precision required for OpenGL ES2 (WebGL) + "varying vec2 fragTexCoord; \n" + "varying vec4 fragColor; \n" + "varying vec3 fragNormal; \n" +#endif + "uniform sampler2D texture0; \n" + "uniform vec4 fragTintColor; \n" + "uniform vec4 colAmbient; \n" + "uniform vec4 colSpecular; \n" + "uniform vec3 lightDir; \n" + "vec3 LambertLighting(in vec3 n, in vec3 l) \n" + "{ \n" + " return clamp(dot(n, l), 0, 1)*fragTintColor.rgb; \n" + "} \n" + + "void main() \n" + "{ \n" + " vec3 n = normalize(fragNormal); \n" + " vec3 l = normalize(lightDir); \n" +#if defined(GRAPHICS_API_OPENGL_33) + " vec4 texelColor = texture(texture0, fragTexCoord); \n" + " finalColor = vec4(texelColor.rgb*(colAmbient.rgb + LambertLighting(n, l)) - colSpecular.rgb + colSpecular.rgb, texelColor.a*fragTintColor.a); \n" // Stupid specular color operation to avoid shader location errors +#elif defined(GRAPHICS_API_OPENGL_ES2) + " vec4 texelColor = texture2D(texture0, fragTexCoord); \n" // NOTE: texture2D() is deprecated on OpenGL 3.3 and ES 3.0 + " gl_FragColor = texelColor*fragTintColor*fragColor; \n" +#endif + "} \n"; + shader.id = LoadShaderProgram(vShaderStr, fShaderStr); if (shader.id != 0) TraceLog(INFO, "[SHDR ID %i] Standard shader loaded successfully", shader.id); @@ -2554,10 +2636,23 @@ static void UnloadDefaultShader(void) //glDetachShader(defaultShader, vertexShader); //glDetachShader(defaultShader, fragmentShader); //glDeleteShader(vertexShader); // Already deleted on shader compilation - //glDeleteShader(fragmentShader); // Already deleted on sahder compilation + //glDeleteShader(fragmentShader); // Already deleted on shader compilation glDeleteProgram(defaultShader.id); } +// Unload standard shader +static void UnloadStandardShader(void) +{ + glUseProgram(0); + + //glDetachShader(defaultShader, vertexShader); + //glDetachShader(defaultShader, fragmentShader); + //glDeleteShader(vertexShader); // Already deleted on shader compilation + //glDeleteShader(fragmentShader); // Already deleted on shader compilation + glDeleteProgram(standardShader.id); +} + + // Load default internal buffers (lines, triangles, quads) static void LoadDefaultBuffers(void) { @@ -3006,6 +3101,9 @@ static void UnloadDefaultBuffers(void) // TODO: Review memcpy() and parameters pass static void SetShaderLights(Shader shader) { + // Note: currently working with one light (index 0) + // TODO: add multi-lights feature (http://www.learnopengl.com/#!Lighting/Multiple-lights) + /* // NOTE: Standard Shader must include the following data: @@ -3023,7 +3121,7 @@ static void SetShaderLights(Shader shader) uniform Light lights[maxLights]; */ - int locPoint; + /*int locPoint; char locName[32] = "lights[x].position\0"; glUseProgram(shader.id); @@ -3052,9 +3150,10 @@ static void SetShaderLights(Shader shader) glUniform1f(locPoint, lights[i]->intensity); // TODO: Pass to the shader any other required data from LightData struct - } + }*/ - glUseProgram(0); + int locPoint = GetShaderLocation(shader, "lightDir"); + glUniform3f(locPoint, lights[0]->position.x, lights[0]->position.y, lights[0]->position.z); } // Read text data from file From cf71e1242e593de5b77d6ff219569e8c0d2c7fd9 Mon Sep 17 00:00:00 2001 From: victorfisac Date: Sat, 21 May 2016 18:08:09 +0200 Subject: [PATCH 2/6] Fix some audio module compile warnings --- src/audio.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/audio.c b/src/audio.c index 43e8be14e..0c61c0fa8 100644 --- a/src/audio.c +++ b/src/audio.c @@ -384,7 +384,7 @@ RawAudioContext InitRawAudioContext(int sampleRate, int channels, bool floatingP for(mixIndex = 0; mixIndex < MAX_MIX_CHANNELS; mixIndex++) // find empty mix channel slot { if(mixChannelsActive_g[mixIndex] == NULL) break; - else if(mixIndex = MAX_MIX_CHANNELS - 1) return -1; // error + else if(mixIndex == MAX_MIX_CHANNELS - 1) return -1; // error } if(InitMixChannel(sampleRate, mixIndex, channels, floatingPoint)) @@ -772,7 +772,7 @@ int PlayMusicStream(int musicIndex, char *fileName) for(mixIndex = 0; mixIndex < MAX_MIX_CHANNELS; mixIndex++) // find empty mix channel slot { if(mixChannelsActive_g[mixIndex] == NULL) break; - else if(mixIndex = MAX_MIX_CHANNELS - 1) return 2; // error + else if(mixIndex == MAX_MIX_CHANNELS - 1) return 2; // error } if (strcmp(GetExtension(fileName),"ogg") == 0) @@ -956,7 +956,7 @@ float GetMusicTimeLength(int index) // Get current music time played (in seconds) float GetMusicTimePlayed(int index) { - float secondsPlayed; + float secondsPlayed = 0.0f; if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc) { if (currentMusic[index].chipTune) @@ -972,7 +972,6 @@ float GetMusicTimePlayed(int index) secondsPlayed = (float)samplesPlayed / (currentMusic[index].mixc->sampleRate * currentMusic[index].mixc->channels); } } - return secondsPlayed; } From 30941c0dd1f7904b5a0b50c05ec17265f8d69baa Mon Sep 17 00:00:00 2001 From: victorfisac Date: Sat, 21 May 2016 18:10:06 +0200 Subject: [PATCH 3/6] Add Draw3DLine function and fixed MLT glossiness import value In standard shader, material glossiness is a value from 0 to 1000 like in MLT files. So, it doesn't need to be normalized. --- src/models.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/models.c b/src/models.c index 2629dffdb..aef79626b 100644 --- a/src/models.c +++ b/src/models.c @@ -65,6 +65,16 @@ static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize); // Module Functions Definition //---------------------------------------------------------------------------------- +// Draw a line in 3D world space +void Draw3DLine(Vector3 startPos, Vector3 endPos, Color color) +{ + rlBegin(RL_LINES); + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex3f(startPos.x, startPos.y, startPos.z); + rlVertex3f(endPos.x, endPos.y, endPos.z); + rlEnd(); +} + // Draw cube // NOTE: Cube position is the center position void DrawCube(Vector3 position, float width, float height, float length, Color color) @@ -2071,8 +2081,7 @@ static Material LoadMTL(const char *fileName) int shininess = 0; sscanf(buffer, "Ns %i", &shininess); - // Normalize shininess value to material glossiness attribute - material.glossiness = (float)shininess/1000; + material.glossiness = (float)shininess; } else if (buffer[1] == 'i') // Ni int Refraction index. { From 80eb4f3f50bb9773dd0e5d4b70c50e18df8996e5 Mon Sep 17 00:00:00 2001 From: victorfisac Date: Sat, 21 May 2016 18:11:25 +0200 Subject: [PATCH 4/6] Remove deprecated phong lighting shaders and example --- examples/resources/shaders/glsl330/phong.fs | 85 ---------- examples/resources/shaders/glsl330/phong.vs | 29 ---- examples/shaders_basic_lighting.c | 171 -------------------- 3 files changed, 285 deletions(-) delete mode 100644 examples/resources/shaders/glsl330/phong.fs delete mode 100644 examples/resources/shaders/glsl330/phong.vs delete mode 100644 examples/shaders_basic_lighting.c diff --git a/examples/resources/shaders/glsl330/phong.fs b/examples/resources/shaders/glsl330/phong.fs deleted file mode 100644 index c14b346a9..000000000 --- a/examples/resources/shaders/glsl330/phong.fs +++ /dev/null @@ -1,85 +0,0 @@ -#version 330 - -// Input vertex attributes (from vertex shader) -in vec2 fragTexCoord; -in vec3 fragNormal; - -// Input uniform values -uniform sampler2D texture0; -uniform vec4 fragTintColor; - -// Output fragment color -out vec4 finalColor; - -// NOTE: Add here your custom variables - -// Light uniform values -uniform vec3 lightAmbientColor = vec3(0.6, 0.3, 0.0); -uniform vec3 lightDiffuseColor = vec3(1.0, 0.5, 0.0); -uniform vec3 lightSpecularColor = vec3(0.0, 1.0, 0.0); -uniform float lightIntensity = 1.0; -uniform float lightSpecIntensity = 1.0; - -// Material uniform values -uniform vec3 matAmbientColor = vec3(1.0, 1.0, 1.0); -uniform vec3 matSpecularColor = vec3(1.0, 1.0, 1.0); -uniform float matGlossiness = 50.0; - -// World uniform values -uniform vec3 lightPosition; -uniform vec3 cameraPosition; - -// Fragment shader output data -out vec4 fragColor; - -// Calculate ambient lighting component -vec3 AmbientLighting() -{ - return (matAmbientColor*lightAmbientColor); -} - -// Calculate diffuse lighting component -vec3 DiffuseLighting(in vec3 N, in vec3 L) -{ - // Lambertian reflection calculation - float diffuse = clamp(dot(N, L), 0, 1); - - return (fragTintColor.xyz*lightDiffuseColor*lightIntensity*diffuse); -} - -// Calculate specular lighting component -vec3 SpecularLighting(in vec3 N, in vec3 L, in vec3 V) -{ - float specular = 0.0; - - // Calculate specular reflection only if the surface is oriented to the light source - if (dot(N, L) > 0) - { - // Calculate half vector - vec3 H = normalize(L + V); - - // Calculate specular intensity - specular = pow(dot(N, H), 3 + matGlossiness); - } - - return (matSpecularColor*lightSpecularColor*lightSpecIntensity*specular); -} - -void main() -{ - // Normalize input vectors - vec3 L = normalize(lightPosition); - vec3 V = normalize(cameraPosition); - vec3 N = normalize(fragNormal); - - // Calculate lighting components - vec3 ambient = AmbientLighting(); - vec3 diffuse = DiffuseLighting(N, L); - vec3 specular = SpecularLighting(N, L, V); - - // Texel color fetching from texture sampler - vec4 texelColor = texture(texture0, fragTexCoord); - - // Calculate final fragment color - finalColor = vec4(texelColor.rgb*(ambient + diffuse + specular), texelColor.a); -} \ No newline at end of file diff --git a/examples/resources/shaders/glsl330/phong.vs b/examples/resources/shaders/glsl330/phong.vs deleted file mode 100644 index d68d9b3fc..000000000 --- a/examples/resources/shaders/glsl330/phong.vs +++ /dev/null @@ -1,29 +0,0 @@ -#version 330 - -// Input vertex attributes -in vec3 vertexPosition; -in vec2 vertexTexCoord; -in vec3 vertexNormal; - -// Input uniform values -uniform mat4 mvpMatrix; - -// Output vertex attributes (to fragment shader) -out vec2 fragTexCoord; -out vec3 fragNormal; - -// NOTE: Add here your custom variables -uniform mat4 modelMatrix; - -void main() -{ - // Send vertex attributes to fragment shader - fragTexCoord = vertexTexCoord; - - // Calculate view vector normal from model - mat3 normalMatrix = transpose(inverse(mat3(modelMatrix))); - fragNormal = normalize(normalMatrix*vertexNormal); - - // Calculate final vertex position - gl_Position = mvpMatrix*vec4(vertexPosition, 1.0); -} \ No newline at end of file diff --git a/examples/shaders_basic_lighting.c b/examples/shaders_basic_lighting.c deleted file mode 100644 index d72eb4176..000000000 --- a/examples/shaders_basic_lighting.c +++ /dev/null @@ -1,171 +0,0 @@ -/******************************************************************************************* -* -* raylib [shaders] example - Basic lighting: Blinn-Phong -* -* This example has been created using raylib 1.3 (www.raylib.com) -* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) -* -* Copyright (c) 2014 Ramon Santamaria (@raysan5) -* -********************************************************************************************/ - -#include "raylib.h" - -#define SHININESS_SPEED 1.0f -#define LIGHT_SPEED 0.25f - -// Light type -typedef struct Light { - Vector3 position; - Vector3 direction; - float intensity; - float specIntensity; - Color diffuse; - Color ambient; - Color specular; -} Light; - -int main() -{ - // Initialization - //-------------------------------------------------------------------------------------- - const int screenWidth = 800; - const int screenHeight = 450; - - SetConfigFlags(FLAG_MSAA_4X_HINT); - InitWindow(screenWidth, screenHeight, "raylib [shaders] example - basic lighting"); - - // Camera initialization - Camera camera = {{ 8.0f, 8.0f, 8.0f }, { 0.0f, 3.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f }; - - // Model initialization - Vector3 position = { 0.0f, 0.0f, 0.0f }; - Model model = LoadModel("resources/model/dwarf.obj"); - Shader shader = LoadShader("resources/shaders/glsl330/phong.vs", "resources/shaders/glsl330/phong.fs"); - SetModelShader(&model, shader); - - // Shader locations initialization - int lIntensityLoc = GetShaderLocation(shader, "lightIntensity"); - int lAmbientLoc = GetShaderLocation(shader, "lightAmbientColor"); - int lDiffuseLoc = GetShaderLocation(shader, "lightDiffuseColor"); - int lSpecularLoc = GetShaderLocation(shader, "lightSpecularColor"); - int lSpecIntensityLoc = GetShaderLocation(shader, "lightSpecIntensity"); - - int mAmbientLoc = GetShaderLocation(shader, "matAmbientColor"); - int mSpecularLoc = GetShaderLocation(shader, "matSpecularColor"); - int mGlossLoc = GetShaderLocation(shader, "matGlossiness"); - - // Camera and light vectors shader locations - int cameraLoc = GetShaderLocation(shader, "cameraPosition"); - int lightLoc = GetShaderLocation(shader, "lightPosition"); - - // Model and View matrix locations (required for lighting) - int modelLoc = GetShaderLocation(shader, "modelMatrix"); - //int viewLoc = GetShaderLocation(shader, "viewMatrix"); // Not used - - // Light and material definitions - Light light; - Material matBlinn; - - // Light initialization - light.position = (Vector3){ 4.0f, 2.0f, 0.0f }; - light.direction = (Vector3){ 5.0f, 1.0f, 1.0f }; - light.intensity = 1.0f; - light.diffuse = WHITE; - light.ambient = (Color){ 150, 75, 0, 255 }; - light.specular = WHITE; - light.specIntensity = 1.0f; - - // Material initialization - matBlinn.colDiffuse = WHITE; - matBlinn.colAmbient = (Color){ 50, 50, 50, 255 }; - matBlinn.colSpecular = WHITE; - matBlinn.glossiness = 50.0f; - - // Setup camera - SetCameraMode(CAMERA_FREE); // Set camera mode - SetCameraPosition(camera.position); // Set internal camera position to match our camera position - SetCameraTarget(camera.target); // Set internal camera target to match our camera target - - SetTargetFPS(60); - //-------------------------------------------------------------------------------------- - - // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key - { - // Update - //---------------------------------------------------------------------------------- - UpdateCamera(&camera); // Update camera position - - // NOTE: Model transform can be set in model.transform or directly with params at draw... WATCH OUT! - SetShaderValueMatrix(shader, modelLoc, model.transform); // Send model matrix to shader - //SetShaderValueMatrix(shader, viewLoc, GetCameraMatrix(camera)); // Not used - - // Glossiness input control - if(IsKeyDown(KEY_UP)) matBlinn.glossiness += SHININESS_SPEED; - else if(IsKeyDown(KEY_DOWN)) - { - matBlinn.glossiness -= SHININESS_SPEED; - if( matBlinn.glossiness < 0) matBlinn.glossiness = 0.0f; - } - - // Light X movement - if (IsKeyDown(KEY_D)) light.position.x += LIGHT_SPEED; - else if(IsKeyDown(KEY_A)) light.position.x -= LIGHT_SPEED; - - // Light Y movement - if (IsKeyDown(KEY_LEFT_SHIFT)) light.position.y += LIGHT_SPEED; - else if (IsKeyDown(KEY_LEFT_CONTROL)) light.position.y -= LIGHT_SPEED; - - // Light Z movement - if (IsKeyDown(KEY_S)) light.position.z += LIGHT_SPEED; - else if (IsKeyDown(KEY_W)) light.position.z -= LIGHT_SPEED; - - // Send light values to shader - SetShaderValue(shader, lIntensityLoc, &light.intensity, 1); - SetShaderValue(shader, lAmbientLoc, ColorToFloat(light.ambient), 3); - SetShaderValue(shader, lDiffuseLoc, ColorToFloat(light.diffuse), 3); - SetShaderValue(shader, lSpecularLoc, ColorToFloat(light.specular), 3); - SetShaderValue(shader, lSpecIntensityLoc, &light.specIntensity, 1); - - // Send material values to shader - SetShaderValue(shader, mAmbientLoc, ColorToFloat(matBlinn.colAmbient), 3); - SetShaderValue(shader, mSpecularLoc, ColorToFloat(matBlinn.colSpecular), 3); - SetShaderValue(shader, mGlossLoc, &matBlinn.glossiness, 1); - - // Send camera and light transform values to shader - SetShaderValue(shader, cameraLoc, VectorToFloat(camera.position), 3); - SetShaderValue(shader, lightLoc, VectorToFloat(light.position), 3); - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); - - ClearBackground(RAYWHITE); - - Begin3dMode(camera); - - DrawModel(model, position, 4.0f, matBlinn.colDiffuse); - DrawSphere(light.position, 0.5f, GOLD); - - DrawGrid(20, 1.0f); - - End3dMode(); - - DrawFPS(10, 10); // Draw FPS - - EndDrawing(); - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - UnloadShader(shader); - UnloadModel(model); - - CloseWindow(); // Close window and OpenGL context - //-------------------------------------------------------------------------------------- - - return 0; -} From c320a21f2b0e96f7605624e84048ccab9700b516 Mon Sep 17 00:00:00 2001 From: victorfisac Date: Sat, 21 May 2016 18:16:39 +0200 Subject: [PATCH 5/6] Add standard lighting (2/3) - 3 light types added (point, directional, spot). - DrawLights() function added using line shapes. - Standard lighting example added. - Removed useless struct variables from material and light. - Fixed light attributes dynamic locations errors. - Standard vertex and fragment shaders temporally added until rewrite it as char pointers in rlgl. TODO: - Add normal and specular maps calculations in standard shader. - Add control structs to handle which attributes needs to be calculated (textures, specular...). - Adapt standard shader to version 110. - Rewrite standard shader as char pointers in rlgl. --- examples/resources/shaders/standard.fs | 136 ++++++++++++++++ examples/resources/shaders/standard.vs | 23 +++ examples/shaders_standard_lighting.c | 118 ++++++++++++++ src/raylib.h | 15 +- src/rlgl.c | 215 +++++++++++-------------- src/rlgl.h | 32 ++-- 6 files changed, 389 insertions(+), 150 deletions(-) create mode 100644 examples/resources/shaders/standard.fs create mode 100644 examples/resources/shaders/standard.vs create mode 100644 examples/shaders_standard_lighting.c diff --git a/examples/resources/shaders/standard.fs b/examples/resources/shaders/standard.fs new file mode 100644 index 000000000..30c841d2d --- /dev/null +++ b/examples/resources/shaders/standard.fs @@ -0,0 +1,136 @@ +#version 330 + +in vec3 fragPosition; +in vec2 fragTexCoord; +in vec4 fragColor; +in vec3 fragNormal; + +out vec4 finalColor; + +uniform sampler2D texture0; + +uniform vec4 colAmbient; +uniform vec4 colDiffuse; +uniform vec4 colSpecular; +uniform float glossiness; + +uniform mat4 modelMatrix; +uniform vec3 viewDir; + +struct Light { + int enabled; + int type; + vec3 position; + vec3 direction; + vec4 diffuse; + float intensity; + float attenuation; + float coneAngle; +}; + +const int maxLights = 8; +uniform int lightsCount; +uniform Light lights[maxLights]; + +vec3 CalcPointLight(Light l, vec3 n, vec3 v) +{ + vec3 surfacePos = vec3(modelMatrix*vec4(fragPosition, 1)); + vec3 surfaceToLight = l.position - surfacePos; + + // Diffuse shading + float brightness = clamp(dot(n, surfaceToLight)/(length(surfaceToLight)*length(n)), 0, 1); + float diff = 1.0/dot(surfaceToLight/l.attenuation, surfaceToLight/l.attenuation)*brightness*l.intensity; + + // Specular shading + float spec = 0.0; + if(diff > 0.0) + { + vec3 h = normalize(-l.direction + v); + spec = pow(dot(n, h), 3 + glossiness); + } + + return (diff*l.diffuse.rgb*colDiffuse.rgb + spec*colSpecular.rgb); +} + +vec3 CalcDirectionalLight(Light l, vec3 n, vec3 v) +{ + vec3 lightDir = normalize(-l.direction); + + // Diffuse shading + float diff = clamp(dot(n, lightDir), 0.0, 1.0)*l.intensity; + + // Specular shading + float spec = 0.0; + if(diff > 0.0) + { + vec3 h = normalize(lightDir + v); + spec = pow(dot(n, h), 3 + glossiness); + } + + // Combine results + return (diff*l.intensity*l.diffuse.rgb*colDiffuse.rgb + spec*colSpecular.rgb); +} + +vec3 CalcSpotLight(Light l, vec3 n, vec3 v) +{ + vec3 surfacePos = vec3(modelMatrix*vec4(fragPosition, 1)); + vec3 lightToSurface = normalize(surfacePos - l.position); + vec3 lightDir = normalize(-l.direction); + + // Diffuse shading + float diff = clamp(dot(n, lightDir), 0.0, 1.0)*l.intensity; + + // Spot attenuation + float attenuation = clamp(dot(n, lightToSurface), 0.0, 1.0); + attenuation = dot(lightToSurface, -lightDir); + float lightToSurfaceAngle = degrees(acos(attenuation)); + if(lightToSurfaceAngle > l.coneAngle) attenuation = 0.0; + float falloff = (l.coneAngle - lightToSurfaceAngle)/l.coneAngle; + + // Combine diffuse and attenuation + float diffAttenuation = diff*attenuation; + + // Specular shading + float spec = 0.0; + if(diffAttenuation > 0.0) + { + vec3 h = normalize(lightDir + v); + spec = pow(dot(n, h), 3 + glossiness); + } + + return falloff*(diffAttenuation*l.diffuse.rgb + spec*colSpecular.rgb); +} + +void main() +{ + // Calculate fragment normal in screen space + mat3 normalMatrix = transpose(inverse(mat3(modelMatrix))); + vec3 normal = normalize(normalMatrix*fragNormal); + + // Normalize normal and view direction vectors + vec3 n = normalize(normal); + vec3 v = normalize(viewDir); + + // Calculate diffuse texture color fetching + vec4 texelColor = texture(texture0, fragTexCoord); + vec3 lighting = colAmbient.rgb; + + for(int i = 0; i < lightsCount; i++) + { + // Check if light is enabled + if(lights[i].enabled == 1) + { + // Calculate lighting based on light type + switch(lights[i].type) + { + case 0: lighting += CalcPointLight(lights[i], n, v); break; + case 1: lighting += CalcDirectionalLight(lights[i], n, v); break; + case 2: lighting += CalcSpotLight(lights[i], n, v); break; + default: break; + } + } + } + + // Calculate final fragment color + finalColor = vec4(texelColor.rgb*lighting, texelColor.a); +} diff --git a/examples/resources/shaders/standard.vs b/examples/resources/shaders/standard.vs new file mode 100644 index 000000000..fc0a5ff40 --- /dev/null +++ b/examples/resources/shaders/standard.vs @@ -0,0 +1,23 @@ +#version 330 + +in vec3 vertexPosition; +in vec3 vertexNormal; +in vec2 vertexTexCoord; +in vec4 vertexColor; + +out vec3 fragPosition; +out vec2 fragTexCoord; +out vec4 fragColor; +out vec3 fragNormal; + +uniform mat4 mvpMatrix; + +void main() +{ + fragPosition = vertexPosition; + fragTexCoord = vertexTexCoord; + fragColor = vertexColor; + fragNormal = vertexNormal; + + gl_Position = mvpMatrix*vec4(vertexPosition, 1.0); +} \ No newline at end of file diff --git a/examples/shaders_standard_lighting.c b/examples/shaders_standard_lighting.c new file mode 100644 index 000000000..7a9cc086d --- /dev/null +++ b/examples/shaders_standard_lighting.c @@ -0,0 +1,118 @@ +/******************************************************************************************* +* +* raylib [shaders] example - Standard lighting (materials and lights) +* +* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support, +* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version. +* +* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3), to test this example +* on OpenGL ES 2.0 platforms (Android, Raspberry Pi, HTML5), use #version 100 shaders +* raylib comes with shaders ready for both versions, check raylib/shaders install folder +* +* This example has been created using raylib 1.3 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2016 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" +#include "raymath.h" + +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + int screenWidth = 800; + int screenHeight = 450; + + SetConfigFlags(FLAG_MSAA_4X_HINT); // Enable Multi Sampling Anti Aliasing 4x (if available) + + InitWindow(screenWidth, screenHeight, "raylib [shaders] example - model shader"); + + // Define the camera to look into our 3d world + Camera camera = {{ 4.0f, 4.0f, 4.0f }, { 0.0f, 1.5f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f }; + Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position + + Model dwarf = LoadModel("resources/model/dwarf.obj"); // Load OBJ model + Texture2D texDiffuse = LoadTexture("resources/model/dwarf_diffuse.png"); // Load model diffuse texture + + Material material = LoadStandardMaterial(); + material.texDiffuse = texDiffuse; + material.colDiffuse = (Color){255, 255, 255, 255}; + material.colAmbient = (Color){0, 0, 10, 255}; + material.colSpecular = (Color){255, 255, 255, 255}; + material.glossiness = 50.0f; + dwarf.material = material; // Apply material to model + + Light spotLight = CreateLight(LIGHT_SPOT, (Vector3){3.0f, 5.0f, 2.0f}, (Color){255, 255, 255, 255}); + spotLight->target = (Vector3){0.0f, 0.0f, 0.0f}; + spotLight->intensity = 2.0f; + spotLight->diffuse = (Color){255, 100, 100, 255}; + spotLight->coneAngle = 60.0f; + + Light dirLight = CreateLight(LIGHT_DIRECTIONAL, (Vector3){0.0f, -3.0f, -3.0f}, (Color){255, 255, 255, 255}); + dirLight->target = (Vector3){1.0f, -2.0f, -2.0f}; + dirLight->intensity = 2.0f; + dirLight->diffuse = (Color){100, 255, 100, 255}; + + Light pointLight = CreateLight(LIGHT_POINT, (Vector3){0.0f, 4.0f, 5.0f}, (Color){255, 255, 255, 255}); + pointLight->intensity = 2.0f; + pointLight->diffuse = (Color){100, 100, 255, 255}; + pointLight->attenuation = 3.0f; + + // Setup orbital camera + SetCameraMode(CAMERA_ORBITAL); // Set a orbital camera mode + SetCameraPosition(camera.position); // Set internal camera position to match our camera position + SetCameraTarget(camera.target); // Set internal camera target to match our camera target + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateCamera(&camera); // Update internal camera and our camera + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + Begin3dMode(camera); + + DrawModel(dwarf, position, 2.0f, WHITE); // Draw 3d model with texture + + DrawLights(); // Draw all created lights in 3D world + + DrawGrid(10, 1.0f); // Draw a grid + + End3dMode(); + + DrawText("(c) Dwarf 3D model by David Moreno", screenWidth - 200, screenHeight - 20, 10, GRAY); + + DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadMaterial(material); // Unload material and assigned textures + UnloadModel(dwarf); // Unload model + + // Destroy all created lights + DestroyLight(pointLight); + DestroyLight(dirLight); + DestroyLight(spotLight); + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/src/raylib.h b/src/raylib.h index 48534fd6d..9cd02fd8d 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -418,7 +418,7 @@ typedef struct Material { Color colAmbient; // Ambient color Color colSpecular; // Specular color - float glossiness; // Glossiness level + float glossiness; // Glossiness level (Ranges from 0 to 1000) float normalDepth; // Normal map depth } Material; @@ -430,22 +430,19 @@ typedef struct Model { } Model; // Light type -// TODO: Review contained data to support different light types and features typedef struct LightData { int id; int type; // LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT bool enabled; Vector3 position; - Vector3 direction; // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction) - float attenuation; // Lost of light intensity with distance (use radius?) + Vector3 target; // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) + float attenuation; // Lost of light intensity with distance (world distance) - Color diffuse; // Use Vector3 diffuse (including intensities)? + Color diffuse; // Use Vector3 diffuse float intensity; - Color specular; - - float coneAngle; // SpotLight + float coneAngle; // Spot light max angle } LightData, *Light; // Light types @@ -805,6 +802,7 @@ const char *SubText(const char *text, int position, int length); //------------------------------------------------------------------------------------ // Basic 3d Shapes Drawing Functions (Module: models) //------------------------------------------------------------------------------------ +void Draw3DLine(Vector3 startPos, Vector3 endPos, Color color); // Draw a line in 3D world space void DrawCube(Vector3 position, float width, float height, float lenght, Color color); // Draw cube void DrawCubeV(Vector3 position, Vector3 size, Color color); // Draw cube (Vector version) void DrawCubeWires(Vector3 position, float width, float height, float lenght, Color color); // Draw cube wires @@ -874,6 +872,7 @@ void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // S void SetBlendMode(int mode); // Set blending mode (alpha, additive, multiplied) Light CreateLight(int type, Vector3 position, Color diffuse); // Create a new light, initialize it and add to pool +void DrawLights(void); // Draw all created lights in 3D world void DestroyLight(Light light); // Destroy a light and take it out of the list //---------------------------------------------------------------------------------- diff --git a/src/rlgl.c b/src/rlgl.c index e2195e4d1..55677f3e8 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1773,6 +1773,9 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) // Send model transformations matrix to shader glUniformMatrix4fv(glGetUniformLocation(material.shader.id, "modelMatrix"), 1, false, MatrixToFloat(transform)); + // Send view transformation matrix to shader. View matrix 8, 9 and 10 are view direction vector axis values (target - position) + glUniform3f(glGetUniformLocation(material.shader.id, "viewDir"), matView.m8, matView.m9, matView.m10); + // Setup shader uniforms for lights SetShaderLights(material.shader); @@ -1782,8 +1785,8 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) // Upload to shader material.colSpecular glUniform4f(glGetUniformLocation(material.shader.id, "colSpecular"), (float)material.colSpecular.r/255, (float)material.colSpecular.g/255, (float)material.colSpecular.b/255, (float)material.colSpecular.a/255); - // TODO: Upload to shader glossiness - //glUniform1f(???, material.glossiness); + // Upload to shader glossiness + glUniform1f(glGetUniformLocation(material.shader.id, "glossiness"), material.glossiness); } // Set shader textures (diffuse, normal, specular) @@ -2245,7 +2248,6 @@ void SetBlendMode(int mode) } // Create a new light, initialize it and add to pool -// TODO: Review creation parameters (only generic ones) Light CreateLight(int type, Vector3 position, Color diffuse) { // Allocate dynamic memory @@ -2257,10 +2259,9 @@ Light CreateLight(int type, Vector3 position, Color diffuse) light->enabled = true; light->position = position; - light->direction = (Vector3){ 0.0f, 0.0f, 0.0f }; + light->target = (Vector3){ 0.0f, 0.0f, 0.0f }; light->intensity = 1.0f; light->diffuse = diffuse; - light->specular = WHITE; // Add new light to the array lights[lightsCount] = light; @@ -2271,6 +2272,31 @@ Light CreateLight(int type, Vector3 position, Color diffuse) return light; } +// Draw all created lights in 3D world +void DrawLights(void) +{ + for (int i = 0; i < lightsCount; i++) + { + switch (lights[i]->type) + { + case LIGHT_POINT: DrawSphereWires(lights[i]->position, 0.3f*lights[i]->intensity, 4, 8, (lights[i]->enabled ? lights[i]->diffuse : BLACK)); break; + case LIGHT_DIRECTIONAL: + { + Draw3DLine(lights[i]->position, lights[i]->target, (lights[i]->enabled ? lights[i]->diffuse : BLACK)); + DrawSphereWires(lights[i]->position, 0.3f*lights[i]->intensity, 4, 8, (lights[i]->enabled ? lights[i]->diffuse : BLACK)); + DrawCubeWires(lights[i]->target, 0.3f, 0.3f, 0.3f, (lights[i]->enabled ? lights[i]->diffuse : BLACK)); + } + case LIGHT_SPOT: + { + Draw3DLine(lights[i]->position, lights[i]->target, (lights[i]->enabled ? lights[i]->diffuse : BLACK)); + DrawCylinderWires(lights[i]->position, 0.0f, 0.3f*lights[i]->coneAngle/50, 0.6f, 5, (lights[i]->enabled ? lights[i]->diffuse : BLACK)); + DrawCubeWires(lights[i]->target, 0.3f, 0.3f, 0.3f, (lights[i]->enabled ? lights[i]->diffuse : BLACK)); + } break; + default: break; + } + } +} + // Destroy a light and take it out of the list void DestroyLight(Light light) { @@ -2488,15 +2514,15 @@ static Shader LoadDefaultShader(void) "varying vec4 fragColor; \n" #endif "uniform sampler2D texture0; \n" - "uniform vec4 fragTintColor; \n" + "uniform vec4 colDiffuse; \n" "void main() \n" "{ \n" #if defined(GRAPHICS_API_OPENGL_33) " vec4 texelColor = texture(texture0, fragTexCoord); \n" - " finalColor = texelColor*fragTintColor*fragColor; \n" + " finalColor = texelColor*colDiffuse*fragColor; \n" #elif defined(GRAPHICS_API_OPENGL_ES2) " vec4 texelColor = texture2D(texture0, fragTexCoord); \n" // NOTE: texture2D() is deprecated on OpenGL 3.3 and ES 3.0 - " gl_FragColor = texelColor*fragTintColor*fragColor; \n" + " gl_FragColor = texelColor*colDiffuse*fragColor; \n" #endif "} \n"; @@ -2513,87 +2539,17 @@ static Shader LoadDefaultShader(void) // Load standard shader // NOTE: This shader supports: // - Up to 3 different maps: diffuse, normal, specular -// - Material properties: colDiffuse, colAmbient, colSpecular, glossiness, normalDepth +// - Material properties: colAmbient, colDiffuse, colSpecular, glossiness, normalDepth // - Up to 8 lights: Point, Directional or Spot static Shader LoadStandardShader(void) { - Shader shader; - - // Vertex shader directly defined, no external file required -#if defined(GRAPHICS_API_OPENGL_33) - char vShaderStr[] = "#version 330 \n" - "in vec3 vertexPosition; \n" - "in vec3 vertexNormal; \n" - "in vec2 vertexTexCoord; \n" - "in vec4 vertexColor; \n" - "out vec2 fragTexCoord; \n" - "out vec4 fragColor; \n" - "out vec3 fragNormal; \n" -#elif defined(GRAPHICS_API_OPENGL_ES2) - char vShaderStr[] = "#version 100 \n" - "attribute vec3 vertexPosition; \n" - "attribute vec3 vertexNormal; \n" - "attribute vec2 vertexTexCoord; \n" - "attribute vec4 vertexColor; \n" - "varying vec2 fragTexCoord; \n" - "varying vec4 fragColor; \n" - "varying vec3 fragNormal; \n" -#endif - "uniform mat4 mvpMatrix; \n" - "uniform mat4 modelMatrix; \n" - "void main() \n" - "{ \n" - " fragTexCoord = vertexTexCoord; \n" - " fragColor = vertexColor; \n" - " mat3 normalMatrix = transpose(inverse(mat3(modelMatrix))); \n" - " fragNormal = normalize(normalMatrix*vertexNormal); \n" - " gl_Position = mvpMatrix*vec4(vertexPosition, 1.0); \n" - "} \n"; - - // TODO: add specular calculation, multi-lights structs and light type calculations (directional, point, spot) - // Fragment shader directly defined, no external file required -#if defined(GRAPHICS_API_OPENGL_33) - char fShaderStr[] = "#version 330 \n" - "in vec2 fragTexCoord; \n" - "in vec4 fragColor; \n" - "in vec3 fragNormal; \n" - "out vec4 finalColor; \n" -#elif defined(GRAPHICS_API_OPENGL_ES2) - char fShaderStr[] = "#version 100 \n" - "precision mediump float; \n" // precision required for OpenGL ES2 (WebGL) - "varying vec2 fragTexCoord; \n" - "varying vec4 fragColor; \n" - "varying vec3 fragNormal; \n" -#endif - "uniform sampler2D texture0; \n" - "uniform vec4 fragTintColor; \n" - "uniform vec4 colAmbient; \n" - "uniform vec4 colSpecular; \n" - "uniform vec3 lightDir; \n" - "vec3 LambertLighting(in vec3 n, in vec3 l) \n" - "{ \n" - " return clamp(dot(n, l), 0, 1)*fragTintColor.rgb; \n" - "} \n" - - "void main() \n" - "{ \n" - " vec3 n = normalize(fragNormal); \n" - " vec3 l = normalize(lightDir); \n" -#if defined(GRAPHICS_API_OPENGL_33) - " vec4 texelColor = texture(texture0, fragTexCoord); \n" - " finalColor = vec4(texelColor.rgb*(colAmbient.rgb + LambertLighting(n, l)) - colSpecular.rgb + colSpecular.rgb, texelColor.a*fragTintColor.a); \n" // Stupid specular color operation to avoid shader location errors -#elif defined(GRAPHICS_API_OPENGL_ES2) - " vec4 texelColor = texture2D(texture0, fragTexCoord); \n" // NOTE: texture2D() is deprecated on OpenGL 3.3 and ES 3.0 - " gl_FragColor = texelColor*fragTintColor*fragColor; \n" -#endif - "} \n"; - - shader.id = LoadShaderProgram(vShaderStr, fShaderStr); + // Load standard shader (TODO: rewrite as char pointers) + Shader shader = LoadShader("resources/shaders/standard.vs", "resources/shaders/standard.fs"); if (shader.id != 0) TraceLog(INFO, "[SHDR ID %i] Standard shader loaded successfully", shader.id); else TraceLog(WARNING, "[SHDR ID %i] Standard shader could not be loaded", shader.id); - if (shader.id != 0) LoadDefaultShaderLocations(&shader); // TODO: Review locations fetching + if (shader.id != 0) LoadDefaultShaderLocations(&shader); return shader; } @@ -2622,7 +2578,7 @@ static void LoadDefaultShaderLocations(Shader *shader) shader->mvpLoc = glGetUniformLocation(shader->id, "mvpMatrix"); // Get handles to GLSL uniform locations (fragment shader) - shader->tintColorLoc = glGetUniformLocation(shader->id, "fragTintColor"); + shader->tintColorLoc = glGetUniformLocation(shader->id, "colDiffuse"); shader->mapDiffuseLoc = glGetUniformLocation(shader->id, "texture0"); shader->mapNormalLoc = glGetUniformLocation(shader->id, "texture1"); shader->mapSpecularLoc = glGetUniformLocation(shader->id, "texture2"); @@ -3098,62 +3054,75 @@ static void UnloadDefaultBuffers(void) // Sets shader uniform values for lights array // NOTE: It would be far easier with shader UBOs but are not supported on OpenGL ES 2.0f -// TODO: Review memcpy() and parameters pass static void SetShaderLights(Shader shader) { - // Note: currently working with one light (index 0) - // TODO: add multi-lights feature (http://www.learnopengl.com/#!Lighting/Multiple-lights) - - /* - // NOTE: Standard Shader must include the following data: - - // Shader Light struct - struct Light { - vec3 position; - vec3 direction; - - vec3 diffuse; - float intensity; - } - - const int maxLights = 8; - uniform int lightsCount; // Number of lights - uniform Light lights[maxLights]; - */ - - /*int locPoint; - char locName[32] = "lights[x].position\0"; - - glUseProgram(shader.id); - - locPoint = glGetUniformLocation(shader.id, "lightsCount"); + int locPoint = glGetUniformLocation(shader.id, "lightsCount"); glUniform1i(locPoint, lightsCount); + + char locName[32] = "lights[x].position\0"; for (int i = 0; i < lightsCount; i++) { locName[7] = '0' + i; - memcpy(&locName[10], "position\0", strlen("position\0")); - locPoint = glGetUniformLocation(shader.id, locName); - glUniform3f(locPoint, lights[i]->position.x, lights[i]->position.y, lights[i]->position.z); + memcpy(&locName[10], "enabled\0", strlen("enabled\0") + 1); + locPoint = GetShaderLocation(shader, locName); + glUniform1i(locPoint, lights[i]->enabled); - memcpy(&locName[10], "direction\0", strlen("direction\0")); - locPoint = glGetUniformLocation(shader.id, locName); - glUniform3f(locPoint, lights[i]->direction.x, lights[i]->direction.y, lights[i]->direction.z); - - memcpy(&locName[10], "diffuse\0", strlen("diffuse\0")); + memcpy(&locName[10], "type\0", strlen("type\0") + 1); + locPoint = GetShaderLocation(shader, locName); + glUniform1i(locPoint, lights[i]->type); + + memcpy(&locName[10], "diffuse\0", strlen("diffuse\0") + 2); locPoint = glGetUniformLocation(shader.id, locName); - glUniform4f(locPoint, (float)lights[i]->diffuse.r/255, (float)lights[i]->diffuse.g/255, (float)lights[i]->diffuse.b/255, (float)lights[i]->diffuse.a/255 ); + glUniform4f(locPoint, (float)lights[i]->diffuse.r/255, (float)lights[i]->diffuse.g/255, (float)lights[i]->diffuse.b/255, (float)lights[i]->diffuse.a/255); memcpy(&locName[10], "intensity\0", strlen("intensity\0")); locPoint = glGetUniformLocation(shader.id, locName); glUniform1f(locPoint, lights[i]->intensity); + switch(lights[i]->type) + { + case LIGHT_POINT: + { + memcpy(&locName[10], "position\0", strlen("position\0") + 1); + locPoint = GetShaderLocation(shader, locName); + glUniform3f(locPoint, lights[i]->position.x, lights[i]->position.y, lights[i]->position.z); + + memcpy(&locName[10], "attenuation\0", strlen("attenuation\0")); + locPoint = GetShaderLocation(shader, locName); + glUniform1f(locPoint, lights[i]->attenuation); + } break; + case LIGHT_DIRECTIONAL: + { + memcpy(&locName[10], "direction\0", strlen("direction\0") + 2); + locPoint = GetShaderLocation(shader, locName); + Vector3 direction = { lights[i]->target.x - lights[i]->position.x, lights[i]->target.y - lights[i]->position.y, lights[i]->target.z - lights[i]->position.z }; + VectorNormalize(&direction); + glUniform3f(locPoint, direction.x, direction.y, direction.z); + } break; + case LIGHT_SPOT: + { + memcpy(&locName[10], "position\0", strlen("position\0") + 1); + locPoint = GetShaderLocation(shader, locName); + glUniform3f(locPoint, lights[i]->position.x, lights[i]->position.y, lights[i]->position.z); + + memcpy(&locName[10], "direction\0", strlen("direction\0") + 2); + locPoint = GetShaderLocation(shader, locName); + + Vector3 direction = { lights[i]->target.x - lights[i]->position.x, lights[i]->target.y - lights[i]->position.y, lights[i]->target.z - lights[i]->position.z }; + VectorNormalize(&direction); + glUniform3f(locPoint, direction.x, direction.y, direction.z); + + memcpy(&locName[10], "coneAngle\0", strlen("coneAngle\0")); + locPoint = GetShaderLocation(shader, locName); + glUniform1f(locPoint, lights[i]->coneAngle); + } break; + default: break; + } + // TODO: Pass to the shader any other required data from LightData struct - }*/ - - int locPoint = GetShaderLocation(shader, "lightDir"); - glUniform3f(locPoint, lights[0]->position.x, lights[0]->position.y, lights[0]->position.z); + } } // Read text data from file diff --git a/src/rlgl.h b/src/rlgl.h index 39941b33c..0765a8a7a 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -196,40 +196,34 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion; // Material type typedef struct Material { - Shader shader; + Shader shader; // Standard shader (supports 3 map types: diffuse, normal, specular) - Texture2D texDiffuse; // Diffuse texture - Texture2D texNormal; // Normal texture - Texture2D texSpecular; // Specular texture + Texture2D texDiffuse; // Diffuse texture + Texture2D texNormal; // Normal texture + Texture2D texSpecular; // Specular texture - Color colDiffuse; - Color colAmbient; - Color colSpecular; + Color colDiffuse; // Diffuse color + Color colAmbient; // Ambient color + Color colSpecular; // Specular color - float glossiness; - float normalDepth; + float glossiness; // Glossiness level (Ranges from 0 to 1000) + float normalDepth; // Normal map depth } Material; // Light type - // TODO: Review contained data to support different light types and features typedef struct LightData { int id; int type; // LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT bool enabled; Vector3 position; - Vector3 direction; // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction) - float attenuation; // Lost of light intensity with distance (use radius?) + Vector3 target; // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) + float attenuation; // Lost of light intensity with distance (world distance) - Color diffuse; // Use Vector3 diffuse (including intensities)? + Color diffuse; // Use Vector3 diffuse float intensity; - Color specular; - //float specFactor; // Specular intensity ? - - //Color ambient; // Required? - - float coneAngle; // SpotLight + float coneAngle; // Spot light max angle } LightData, *Light; // Color blending modes (pre-defined) From dcd6942ed1ab703625f5c7072cbcfd823c681db7 Mon Sep 17 00:00:00 2001 From: victorfisac Date: Sat, 21 May 2016 18:22:15 +0200 Subject: [PATCH 6/6] Fix small bug and spacing --- examples/resources/shaders/standard.fs | 14 ++++---- src/models.c | 46 +++++++++++++------------- src/rlgl.c | 10 +++--- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/examples/resources/shaders/standard.fs b/examples/resources/shaders/standard.fs index 30c841d2d..3c3bef4b4 100644 --- a/examples/resources/shaders/standard.fs +++ b/examples/resources/shaders/standard.fs @@ -43,7 +43,7 @@ vec3 CalcPointLight(Light l, vec3 n, vec3 v) // Specular shading float spec = 0.0; - if(diff > 0.0) + if (diff > 0.0) { vec3 h = normalize(-l.direction + v); spec = pow(dot(n, h), 3 + glossiness); @@ -61,7 +61,7 @@ vec3 CalcDirectionalLight(Light l, vec3 n, vec3 v) // Specular shading float spec = 0.0; - if(diff > 0.0) + if (diff > 0.0) { vec3 h = normalize(lightDir + v); spec = pow(dot(n, h), 3 + glossiness); @@ -84,7 +84,7 @@ vec3 CalcSpotLight(Light l, vec3 n, vec3 v) float attenuation = clamp(dot(n, lightToSurface), 0.0, 1.0); attenuation = dot(lightToSurface, -lightDir); float lightToSurfaceAngle = degrees(acos(attenuation)); - if(lightToSurfaceAngle > l.coneAngle) attenuation = 0.0; + if (lightToSurfaceAngle > l.coneAngle) attenuation = 0.0; float falloff = (l.coneAngle - lightToSurfaceAngle)/l.coneAngle; // Combine diffuse and attenuation @@ -92,7 +92,7 @@ vec3 CalcSpotLight(Light l, vec3 n, vec3 v) // Specular shading float spec = 0.0; - if(diffAttenuation > 0.0) + if (diffAttenuation > 0.0) { vec3 h = normalize(lightDir + v); spec = pow(dot(n, h), 3 + glossiness); @@ -115,13 +115,13 @@ void main() vec4 texelColor = texture(texture0, fragTexCoord); vec3 lighting = colAmbient.rgb; - for(int i = 0; i < lightsCount; i++) + for (int i = 0; i < lightsCount; i++) { // Check if light is enabled - if(lights[i].enabled == 1) + if (lights[i].enabled == 1) { // Calculate lighting based on light type - switch(lights[i].type) + switch (lights[i].type) { case 0: lighting += CalcPointLight(lights[i], n, v); break; case 1: lighting += CalcDirectionalLight(lights[i], n, v); break; diff --git a/src/models.c b/src/models.c index aef79626b..07dee7209 100644 --- a/src/models.c +++ b/src/models.c @@ -302,9 +302,9 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color rlBegin(RL_TRIANGLES); rlColor4ub(color.r, color.g, color.b, color.a); - for(int i = 0; i < (rings + 2); i++) + for (int i = 0; i < (rings + 2); i++) { - for(int j = 0; j < slices; j++) + for (int j = 0; j < slices; j++) { rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*i)) * sin(DEG2RAD*(j*360/slices)), sin(DEG2RAD*(270+(180/(rings + 1))*i)), @@ -341,9 +341,9 @@ void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Col rlBegin(RL_LINES); rlColor4ub(color.r, color.g, color.b, color.a); - for(int i = 0; i < (rings + 2); i++) + for (int i = 0; i < (rings + 2); i++) { - for(int j = 0; j < slices; j++) + for (int j = 0; j < slices; j++) { rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*i)) * sin(DEG2RAD*(j*360/slices)), sin(DEG2RAD*(270+(180/(rings + 1))*i)), @@ -386,7 +386,7 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h if (radiusTop > 0) { // Draw Body ------------------------------------------------------------------------------------- - for(int i = 0; i < 360; i += 360/sides) + for (int i = 0; i < 360; i += 360/sides) { rlVertex3f(sin(DEG2RAD*i) * radiusBottom, 0, cos(DEG2RAD*i) * radiusBottom); //Bottom Left rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusBottom, 0, cos(DEG2RAD*(i+360/sides)) * radiusBottom); //Bottom Right @@ -398,7 +398,7 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h } // Draw Cap -------------------------------------------------------------------------------------- - for(int i = 0; i < 360; i += 360/sides) + for (int i = 0; i < 360; i += 360/sides) { rlVertex3f(0, height, 0); rlVertex3f(sin(DEG2RAD*i) * radiusTop, height, cos(DEG2RAD*i) * radiusTop); @@ -408,7 +408,7 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h else { // Draw Cone ------------------------------------------------------------------------------------- - for(int i = 0; i < 360; i += 360/sides) + for (int i = 0; i < 360; i += 360/sides) { rlVertex3f(0, height, 0); rlVertex3f(sin(DEG2RAD*i) * radiusBottom, 0, cos(DEG2RAD*i) * radiusBottom); @@ -417,7 +417,7 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h } // Draw Base ----------------------------------------------------------------------------------------- - for(int i = 0; i < 360; i += 360/sides) + for (int i = 0; i < 360; i += 360/sides) { rlVertex3f(0, 0, 0); rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusBottom, 0, cos(DEG2RAD*(i+360/sides)) * radiusBottom); @@ -431,7 +431,7 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h // NOTE: It could be also used for pyramid and cone void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color) { - if(sides < 3) sides = 3; + if (sides < 3) sides = 3; rlPushMatrix(); rlTranslatef(position.x, position.y, position.z); @@ -439,7 +439,7 @@ void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, fl rlBegin(RL_LINES); rlColor4ub(color.r, color.g, color.b, color.a); - for(int i = 0; i < 360; i += 360/sides) + for (int i = 0; i < 360; i += 360/sides) { rlVertex3f(sin(DEG2RAD*i) * radiusBottom, 0, cos(DEG2RAD*i) * radiusBottom); rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusBottom, 0, cos(DEG2RAD*(i+360/sides)) * radiusBottom); @@ -500,7 +500,7 @@ void DrawGrid(int slices, float spacing) int halfSlices = slices / 2; rlBegin(RL_LINES); - for(int i = -halfSlices; i <= halfSlices; i++) + for (int i = -halfSlices; i <= halfSlices; i++) { if (i == 0) { @@ -798,9 +798,9 @@ static Mesh GenMeshHeightmap(Image heightmap, Vector3 size) Vector3 scaleFactor = { size.x/mapX, size.y/255.0f, size.z/mapZ }; - for(int z = 0; z < mapZ-1; z++) + for (int z = 0; z < mapZ-1; z++) { - for(int x = 0; x < mapX-1; x++) + for (int x = 0; x < mapX-1; x++) { // Fill vertices array with data //---------------------------------------------------------- @@ -1417,7 +1417,7 @@ bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius float vector = VectorDotProduct(raySpherePos, ray.direction); float d = sphereRadius*sphereRadius - (distance*distance - vector*vector); - if(d >= 0.0f) collision = true; + if (d >= 0.0f) collision = true; return collision; } @@ -1432,14 +1432,14 @@ bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadi float vector = VectorDotProduct(raySpherePos, ray.direction); float d = sphereRadius*sphereRadius - (distance*distance - vector*vector); - if(d >= 0.0f) collision = true; + if (d >= 0.0f) collision = true; // Calculate collision point Vector3 offset = ray.direction; float collisionDistance = 0; // Check if ray origin is inside the sphere to calculate the correct collision point - if(distance < sphereRadius) collisionDistance = vector + sqrt(d); + if (distance < sphereRadius) collisionDistance = vector + sqrt(d); else collisionDistance = vector - sqrt(d); VectorScale(&offset, collisionDistance); @@ -1777,11 +1777,11 @@ static Mesh LoadOBJ(const char *fileName) // First reading pass: Get numVertex, numNormals, numTexCoords, numTriangles // NOTE: vertex, texcoords and normals could be optimized (to be used indexed on faces definition) // NOTE: faces MUST be defined as TRIANGLES (3 vertex per face) - while(!feof(objFile)) + while (!feof(objFile)) { fscanf(objFile, "%c", &dataType); - switch(dataType) + switch (dataType) { case '#': // Comments case 'o': // Object name (One OBJ file can contain multible named meshes) @@ -1842,11 +1842,11 @@ static Mesh LoadOBJ(const char *fileName) // Second reading pass: Get vertex data to fill intermediate arrays // NOTE: This second pass is required in case of multiple meshes defined in same OBJ // TODO: Consider that different meshes can have different vertex data available (position, texcoords, normals) - while(!feof(objFile)) + while (!feof(objFile)) { fscanf(objFile, "%c", &dataType); - switch(dataType) + switch (dataType) { case '#': case 'o': case 'g': case 's': case 'm': case 'u': case 'f': fgets(comments, 200, objFile); break; case 'v': @@ -1903,11 +1903,11 @@ static Mesh LoadOBJ(const char *fileName) if (numNormals == 0) TraceLog(INFO, "[%s] No normals data on OBJ, normals will be generated from faces data", fileName); // Third reading pass: Get faces (triangles) data and fill VertexArray - while(!feof(objFile)) + while (!feof(objFile)) { fscanf(objFile, "%c", &dataType); - switch(dataType) + switch (dataType) { case '#': case 'o': case 'g': case 's': case 'm': case 'u': case 'v': fgets(comments, 200, objFile); break; case 'f': @@ -2023,7 +2023,7 @@ static Material LoadMTL(const char *fileName) return material; } - while(!feof(mtlFile)) + while (!feof(mtlFile)) { fgets(buffer, MAX_BUFFER_SIZE, mtlFile); diff --git a/src/rlgl.c b/src/rlgl.c index 55677f3e8..85c0cae29 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1397,7 +1397,7 @@ RenderTexture2D rlglLoadRenderTexture(int width, int height) { TraceLog(WARNING, "Framebuffer object could not be created..."); - switch(status) + switch (status) { case GL_FRAMEBUFFER_UNSUPPORTED: TraceLog(WARNING, "Framebuffer is unsupported"); break; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: TraceLog(WARNING, "Framebuffer incomplete attachment"); break; @@ -1768,7 +1768,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) // Check if using standard shader to get location points // NOTE: standard shader specific locations are got at render time to keep Shader struct as simple as possible (with just default shader locations) - if(material.shader.id == standardShader.id) + if (material.shader.id == standardShader.id) { // Send model transformations matrix to shader glUniformMatrix4fv(glGetUniformLocation(material.shader.id, "modelMatrix"), 1, false, MatrixToFloat(transform)); @@ -2285,7 +2285,7 @@ void DrawLights(void) Draw3DLine(lights[i]->position, lights[i]->target, (lights[i]->enabled ? lights[i]->diffuse : BLACK)); DrawSphereWires(lights[i]->position, 0.3f*lights[i]->intensity, 4, 8, (lights[i]->enabled ? lights[i]->diffuse : BLACK)); DrawCubeWires(lights[i]->target, 0.3f, 0.3f, 0.3f, (lights[i]->enabled ? lights[i]->diffuse : BLACK)); - } + } break; case LIGHT_SPOT: { Draw3DLine(lights[i]->position, lights[i]->target, (lights[i]->enabled ? lights[i]->diffuse : BLACK)); @@ -3081,7 +3081,7 @@ static void SetShaderLights(Shader shader) locPoint = glGetUniformLocation(shader.id, locName); glUniform1f(locPoint, lights[i]->intensity); - switch(lights[i]->type) + switch (lights[i]->type) { case LIGHT_POINT: { @@ -3295,7 +3295,7 @@ static void TraceLog(int msgType, const char *text, ...) va_list args; va_start(args, text); - switch(msgType) + switch (msgType) { case INFO: fprintf(stdout, "INFO: "); break; case ERROR: fprintf(stdout, "ERROR: "); break;