From c6c71fe73c897981c2ddfb40dd82cc09c61f8aff Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 4 Jul 2022 17:47:47 +0200 Subject: [PATCH] REVIEWED: `DrawMesh()` #2511 Disable color vertex attribute if not provided by mesh --- .../resources/shaders/glsl330/lighting.fs | 2 +- .../shaders/glsl330/lighting_instancing.vs | 4 +- examples/shaders/shaders_mesh_instancing.c | 7 +- src/rmodels.c | 115 +++++++++++------- 4 files changed, 75 insertions(+), 53 deletions(-) diff --git a/examples/shaders/resources/shaders/glsl330/lighting.fs b/examples/shaders/resources/shaders/glsl330/lighting.fs index 93be20edd..58845c86b 100644 --- a/examples/shaders/resources/shaders/glsl330/lighting.fs +++ b/examples/shaders/resources/shaders/glsl330/lighting.fs @@ -3,7 +3,7 @@ // Input vertex attributes (from vertex shader) in vec3 fragPosition; in vec2 fragTexCoord; -in vec4 fragColor; +//in vec4 fragColor; in vec3 fragNormal; // Input uniform values diff --git a/examples/shaders/resources/shaders/glsl330/lighting_instancing.vs b/examples/shaders/resources/shaders/glsl330/lighting_instancing.vs index 7f16dc62f..6775a2eb6 100644 --- a/examples/shaders/resources/shaders/glsl330/lighting_instancing.vs +++ b/examples/shaders/resources/shaders/glsl330/lighting_instancing.vs @@ -4,7 +4,7 @@ in vec3 vertexPosition; in vec2 vertexTexCoord; in vec3 vertexNormal; -in vec4 vertexColor; +//in vec4 vertexColor; // Not required in mat4 instanceTransform; @@ -28,7 +28,7 @@ void main() // Send vertex attributes to fragment shader fragPosition = vec3(mvpi*vec4(vertexPosition, 1.0)); fragTexCoord = vertexTexCoord; - fragColor = vertexColor; + //fragColor = vertexColor; fragNormal = normalize(vec3(matNormal*vec4(vertexNormal, 1.0))); // Calculate final vertex position diff --git a/examples/shaders/shaders_mesh_instancing.c b/examples/shaders/shaders_mesh_instancing.c index c1e48c021..08618d6e6 100644 --- a/examples/shaders/shaders_mesh_instancing.c +++ b/examples/shaders/shaders_mesh_instancing.c @@ -19,7 +19,6 @@ #include "rlights.h" #include // Required for: calloc(), free() -#include // Required for: #if defined(PLATFORM_DESKTOP) #define GLSL_VERSION 330 @@ -27,7 +26,7 @@ #define GLSL_VERSION 100 #endif -#define MAX_INSTANCES 8000 +#define MAX_INSTANCES 10000 //------------------------------------------------------------------------------------ // Program main entry point @@ -87,7 +86,9 @@ int main(void) matInstances.shader = shader; matInstances.maps[MATERIAL_MAP_DIFFUSE].color = RED; - // Create a defult material with default internal shader for non-instanced mesh drawing + // Load default material (using raylib intenral default shader) for non-instanced mesh drawing + // WARNING: Default shader enables vertex color attribute BUT GenMeshCube() does not generate vertex colors, so, + // when drawing the color attribute is disabled and a default color value is provided as input for thevertex attribute Material matDefault = LoadMaterialDefault(); matDefault.maps[MATERIAL_MAP_DIFFUSE].color = BLUE; diff --git a/src/rmodels.c b/src/rmodels.c index a088d4443..8b75f6397 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -152,7 +152,7 @@ void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color) // WARNING: Be careful with internal buffer vertex alignment // when using RL_LINES or RL_TRIANGLES, data is aligned to fit // lines-triangles-quads in the same indexed buffers!!! - rlCheckRenderBatchLimit(8); + //rlCheckRenderBatchLimit(8); rlBegin(RL_LINES); rlColor4ub(color.r, color.g, color.b, color.a); @@ -164,7 +164,7 @@ void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color) // Draw a point in 3D space, actually a small line void DrawPoint3D(Vector3 position, Color color) { - rlCheckRenderBatchLimit(8); + //rlCheckRenderBatchLimit(8); rlPushMatrix(); rlTranslatef(position.x, position.y, position.z); @@ -179,7 +179,7 @@ void DrawPoint3D(Vector3 position, Color color) // Draw a circle in 3D world space void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color) { - rlCheckRenderBatchLimit(2*36); + //rlCheckRenderBatchLimit(2*36); rlPushMatrix(); rlTranslatef(center.x, center.y, center.z); @@ -200,7 +200,7 @@ void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rota // Draw a color-filled triangle (vertex in counter-clockwise order!) void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color) { - rlCheckRenderBatchLimit(8); + //rlCheckRenderBatchLimit(8); rlBegin(RL_TRIANGLES); rlColor4ub(color.r, color.g, color.b, color.a); @@ -215,7 +215,7 @@ void DrawTriangleStrip3D(Vector3 *points, int pointCount, Color color) { if (pointCount >= 3) { - rlCheckRenderBatchLimit(3*(pointCount - 2)); + //rlCheckRenderBatchLimit(3*(pointCount - 2)); rlBegin(RL_TRIANGLES); rlColor4ub(color.r, color.g, color.b, color.a); @@ -247,7 +247,7 @@ void DrawCube(Vector3 position, float width, float height, float length, Color c float y = 0.0f; float z = 0.0f; - rlCheckRenderBatchLimit(36); + //rlCheckRenderBatchLimit(36); rlPushMatrix(); // NOTE: Transformation is applied in inverse order (scale -> rotate -> translate) @@ -328,7 +328,7 @@ void DrawCubeWires(Vector3 position, float width, float height, float length, Co float y = 0.0f; float z = 0.0f; - rlCheckRenderBatchLimit(36); + //rlCheckRenderBatchLimit(36); rlPushMatrix(); rlTranslatef(position.x, position.y, position.z); @@ -405,7 +405,7 @@ void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float hei float y = position.y; float z = position.z; - rlCheckRenderBatchLimit(36); + //rlCheckRenderBatchLimit(36); rlSetTexture(texture.id); @@ -468,7 +468,7 @@ void DrawCubeTextureRec(Texture2D texture, Rectangle source, Vector3 position, f float texWidth = (float)texture.width; float texHeight = (float)texture.height; - rlCheckRenderBatchLimit(36); + //rlCheckRenderBatchLimit(36); rlSetTexture(texture.id); @@ -555,8 +555,8 @@ void DrawSphere(Vector3 centerPos, float radius, Color color) // Draw sphere with extended parameters void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color) { - int numVertex = (rings + 2)*slices*6; - rlCheckRenderBatchLimit(numVertex); + //int numVertex = (rings + 2)*slices*6; + //rlCheckRenderBatchLimit(numVertex); rlPushMatrix(); // NOTE: Transformation is applied in inverse order (scale -> translate) @@ -598,8 +598,8 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color // Draw sphere wires void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color) { - int numVertex = (rings + 2)*slices*6; - rlCheckRenderBatchLimit(numVertex); + //int numVertex = (rings + 2)*slices*6; + //rlCheckRenderBatchLimit(numVertex); rlPushMatrix(); // NOTE: Transformation is applied in inverse order (scale -> translate) @@ -645,8 +645,8 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h { if (sides < 3) sides = 3; - int numVertex = sides*6; - rlCheckRenderBatchLimit(numVertex); + //int numVertex = sides*6; + //rlCheckRenderBatchLimit(numVertex); rlPushMatrix(); rlTranslatef(position.x, position.y, position.z); @@ -704,8 +704,8 @@ void DrawCylinderEx(Vector3 startPos, Vector3 endPos, float startRadius, float e { if (sides < 3) sides = 3; - int numVertex = sides*6; - rlCheckRenderBatchLimit(numVertex); + //int numVertex = sides*6; + //rlCheckRenderBatchLimit(numVertex); Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z }; if ((direction.x == 0) && (direction.y == 0) && (direction.z == 0)) return; @@ -763,8 +763,8 @@ void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, fl { if (sides < 3) sides = 3; - int numVertex = sides*8; - rlCheckRenderBatchLimit(numVertex); + //int numVertex = sides*8; + //rlCheckRenderBatchLimit(numVertex); rlPushMatrix(); rlTranslatef(position.x, position.y, position.z); @@ -797,8 +797,8 @@ void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, fl { if (sides < 3) sides = 3; - int numVertex = sides*6; - rlCheckRenderBatchLimit(numVertex); + //int numVertex = sides*6; + //rlCheckRenderBatchLimit(numVertex); Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z }; if ((direction.x == 0) && (direction.y == 0) && (direction.z == 0))return; @@ -843,7 +843,7 @@ void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, fl // Draw a plane void DrawPlane(Vector3 centerPos, Vector2 size, Color color) { - rlCheckRenderBatchLimit(4); + //rlCheckRenderBatchLimit(4); // NOTE: Plane is always created on XZ ground rlPushMatrix(); @@ -881,7 +881,7 @@ void DrawGrid(int slices, float spacing) { int halfSlices = slices/2; - rlCheckRenderBatchLimit((slices + 2)*4); + //rlCheckRenderBatchLimit((slices + 2)*4); rlBegin(RL_LINES); for (int i = -halfSlices; i <= halfSlices; i++) @@ -1087,7 +1087,7 @@ void UploadMesh(Mesh *mesh, bool dynamic) mesh->vaoId = rlLoadVertexArray(); rlEnableVertexArray(mesh->vaoId); - // NOTE: Attributes must be uploaded considering default locations points + // NOTE: Vertex attributes must be uploaded considering default locations points and available vertex data // Enable vertex attributes: position (shader-location = 0) void *vertices = mesh->animVertices != NULL ? mesh->animVertices : mesh->vertices; @@ -1100,6 +1100,9 @@ void UploadMesh(Mesh *mesh, bool dynamic) rlSetVertexAttribute(1, 2, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(1); + // WARNING: When setting default vertex attribute values, the values for each generic vertex attribute + // is part of current state and it is maintained even if a different program object is used + if (mesh->normals != NULL) { // Enable vertex attributes: normals (shader-location = 2) @@ -1110,7 +1113,8 @@ void UploadMesh(Mesh *mesh, bool dynamic) } else { - // Default color vertex attribute set to WHITE + // Default vertex attribute: normal + // WARNING: Default value provided to shader if location available float value[3] = { 1.0f, 1.0f, 1.0f }; rlSetVertexAttributeDefault(2, value, SHADER_ATTRIB_VEC3, 3); rlDisableVertexAttribute(2); @@ -1125,8 +1129,9 @@ void UploadMesh(Mesh *mesh, bool dynamic) } else { - // Default color vertex attribute set to WHITE - float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + // Default vertex attribute: color + // WARNING: Default value provided to shader if location available + float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; // WHITE rlSetVertexAttributeDefault(3, value, SHADER_ATTRIB_VEC4, 4); rlDisableVertexAttribute(3); } @@ -1140,7 +1145,8 @@ void UploadMesh(Mesh *mesh, bool dynamic) } else { - // Default tangents vertex attribute + // Default vertex attribute: tangent + // WARNING: Default value provided to shader if location available float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; rlSetVertexAttributeDefault(4, value, SHADER_ATTRIB_VEC4, 4); rlDisableVertexAttribute(4); @@ -1155,7 +1161,8 @@ void UploadMesh(Mesh *mesh, bool dynamic) } else { - // Default texcoord2 vertex attribute + // Default vertex attribute: texcoord2 + // WARNING: Default value provided to shader if location available float value[2] = { 0.0f, 0.0f }; rlSetVertexAttributeDefault(5, value, SHADER_ATTRIB_VEC2, 2); rlDisableVertexAttribute(5); @@ -1293,8 +1300,10 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) } } - // Try binding vertex array objects (VAO) - // or use VBOs if not possible + // Try binding vertex array objects (VAO) or use VBOs if not possible + // WARNING: UploadMesh() enables all vertex attributes available in mesh and sets default attribute values + // for shader expected vertex attributes that are not provided by the mesh (i.e. colors) + // This could be a dangerous approach because different meshes with different shaders can enable/disable some attributes if (!rlEnableVertexArray(mesh.vaoId)) { // Bind mesh VBO data: vertex position (shader-location = 0) @@ -1326,8 +1335,8 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) } else { - // Set default value for unused attribute - // NOTE: Required when using default shader and no VAO support + // Set default value for defined vertex attribute in shader but not provided by mesh + // WARNING: It could result in GPU undefined behaviour float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; rlSetVertexAttributeDefault(material.shader.locs[SHADER_LOC_VERTEX_COLOR], value, SHADER_ATTRIB_VEC4, 4); rlDisableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]); @@ -1353,6 +1362,9 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]); } + // WARNING: Disable vertex attribute color input if mesh can not provide that data (despite location being enabled in shader) + if (mesh.vboId[3] == 0) rlDisableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]); + int eyeCount = 1; if (rlIsStereoRenderEnabled()) eyeCount = 2; @@ -1379,14 +1391,17 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) // Unbind all binded texture maps for (int i = 0; i < MAX_MATERIAL_MAPS; i++) { - // Select current shader texture slot - rlActiveTextureSlot(i); + if (material.maps[i].texture.id > 0) + { + // Select current shader texture slot + rlActiveTextureSlot(i); - // Disable texture for active slot - if ((i == MATERIAL_MAP_IRRADIANCE) || - (i == MATERIAL_MAP_PREFILTER) || - (i == MATERIAL_MAP_CUBEMAP)) rlDisableTextureCubemap(); - else rlDisableTexture(); + // Disable texture for active slot + if ((i == MATERIAL_MAP_IRRADIANCE) || + (i == MATERIAL_MAP_PREFILTER) || + (i == MATERIAL_MAP_CUBEMAP)) rlDisableTextureCubemap(); + else rlDisableTexture(); + } } // Disable all possible vertex array objects (or VBOs) @@ -1568,6 +1583,9 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]); } + // WARNING: Disable vertex attribute color input if mesh can not provide that data (despite location being enabled in shader) + if (mesh.vboId[3] == 0) rlDisableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]); + int eyeCount = 1; if (rlIsStereoRenderEnabled()) eyeCount = 2; @@ -1594,14 +1612,17 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i // Unbind all binded texture maps for (int i = 0; i < MAX_MATERIAL_MAPS; i++) { - // Select current shader texture slot - rlActiveTextureSlot(i); + if (material.maps[i].texture.id > 0) + { + // Select current shader texture slot + rlActiveTextureSlot(i); - // Disable texture for active slot - if ((i == MATERIAL_MAP_IRRADIANCE) || - (i == MATERIAL_MAP_PREFILTER) || - (i == MATERIAL_MAP_CUBEMAP)) rlDisableTextureCubemap(); - else rlDisableTexture(); + // Disable texture for active slot + if ((i == MATERIAL_MAP_IRRADIANCE) || + (i == MATERIAL_MAP_PREFILTER) || + (i == MATERIAL_MAP_CUBEMAP)) rlDisableTextureCubemap(); + else rlDisableTexture(); + } } // Disable all possible vertex array objects (or VBOs)