From e1a85f898e0781c9dd69ced6cd6ccb4e304a7bd1 Mon Sep 17 00:00:00 2001 From: jussi Date: Fri, 9 Dec 2022 16:02:28 +0200 Subject: Draw Mesh Instanced Example. --- API.md | 12 ++- changelog | 2 + examples/bunnymark/main.lua | 11 +- examples/instancing/main.lua | 112 +++++++++++++++++++++ examples/resources/lib/gui.lua | 2 +- examples/resources/shaders/glsl330/lighting.fs | 82 +++++++++++++++ .../shaders/glsl330/lighting_instancing.vs | 36 +++++++ include/models.h | 1 + src/lua_core.c | 1 + src/models.c | 37 ++++++- src/rmath.c | 2 +- 11 files changed, 282 insertions(+), 16 deletions(-) create mode 100644 examples/instancing/main.lua create mode 100644 examples/resources/shaders/glsl330/lighting.fs create mode 100644 examples/resources/shaders/glsl330/lighting_instancing.vs diff --git a/API.md b/API.md index e625af1..f5d1473 100644 --- a/API.md +++ b/API.md @@ -4070,7 +4070,6 @@ Draw a 3d mesh with material and transform > success = RL_DrawMeshInstanced( Mesh mesh, Material material, Matrix{} transforms, int instances ) Draw multiple mesh instances with material and different transforms -Note! Untested. - Failure return false - Success return true @@ -4171,6 +4170,15 @@ Set value for a material map type --- +> success = RL_SetMaterialShader( Material material, Shader shader ) + +Set shader for material + +- Failure return false +- Success return true + +--- + ## Models - Model --- @@ -5363,7 +5371,7 @@ Invert provided matrix --- -> result = MatrixIdentity() +> result = RL_MatrixIdentity() Get identity matrix diff --git a/changelog b/changelog index e630e73..2877f0f 100644 --- a/changelog +++ b/changelog @@ -10,6 +10,7 @@ KEY CHANGES: - ADDED: Flag option (-s) for doc_parser.lua for exporting module APIs to separate files. - ADDED: ReiLuaGui. - ADDED: ReiLuaGui Examples. + - ADDED: Draw Mesh Instanced Example. Detailed changes: ADDED: Help argument. @@ -21,3 +22,4 @@ FIXED: RL_DrawLineBezierQuad was called RL_DrawLineBezier in API. ADDED: Color lib. FIXED: RL_DrawEllipse and RL_DrawEllipseLines expecting wrong arguments. ADDED: RL_IsPathFile. +ADDED: RL_SetMaterialShader. diff --git a/examples/bunnymark/main.lua b/examples/bunnymark/main.lua index 8672887..8bdc9b9 100644 --- a/examples/bunnymark/main.lua +++ b/examples/bunnymark/main.lua @@ -1,3 +1,6 @@ +-- Forked from raylib-lua example by TSnake41 +-- https://github.com/TSnake41/raylib-lua/blob/master/examples/textures_bunnymark.lua + local MAX_BUNNIES = 100000 -- This is the maximum amount of elements (quads) per batch @@ -39,8 +42,6 @@ function Bunny:update() end end --- Init - function init() RL_SetWindowState( FLAG_VSYNC_HINT ) RL_SetWindowSize( { screenWidth, screenHeight } ) @@ -50,8 +51,6 @@ function init() texSize = RL_GetTextureSize( texBunny ) end --- Update - function process( delta ) if RL_IsMouseButtonDown( 0 ) then -- Create more bunnies @@ -59,7 +58,7 @@ function process( delta ) if #bunnies < MAX_BUNNIES then local speed = { math.random( -250, 250 ) / 60, math.random( -250, 250 ) / 60 } local color = { math.random( 50, 240 ), math.random( 80, 240 ), math.random( 100, 240 ), 255 } - table.insert( bunnies, Bunny:new( RL_GetMousePosition(), speed, color) ) + table.insert( bunnies, Bunny:new( RL_GetMousePosition(), speed, color ) ) end end end @@ -69,8 +68,6 @@ function process( delta ) end end - -- Draw - function draw() RL_ClearBackground( RAYWHITE ) diff --git a/examples/instancing/main.lua b/examples/instancing/main.lua new file mode 100644 index 0000000..bcd9575 --- /dev/null +++ b/examples/instancing/main.lua @@ -0,0 +1,112 @@ +--[[ + This example is translated from "raylib [shaders] example - Mesh instancing" + -- https://github.com/raysan5/raylib/blob/master/examples/shaders/shaders_mesh_instancing.c + + Contributed by @seanpringle + Reviewed by Max (@moliad) and Ramon Santamaria (@raysan5) + + Modified by Jussi Viitala (@nullstare) for ReiLua style. +]] + +local MAX_INSTANCES = 10000 + +local cube +local transforms = {} +local camera + +local shader +local matInstances +local matDefault + +function init() + local monitor = 0 + local mPos = RL_GetMonitorPosition( monitor ) + local mSize = RL_GetMonitorSize( monitor ) + local winSize = RL_GetWindowSize() + -- local winSize = { 1920, 1080 } + + RL_SetWindowState( FLAG_WINDOW_RESIZABLE ) + RL_SetWindowSize( winSize ) + RL_SetWindowPosition( { mPos[1] + mSize[1] / 2 - winSize[1] / 2, mPos[2] + mSize[2] / 2 - winSize[2] / 2 } ) + RL_SetWindowTitle( "Instancing" ) + RL_SetWindowState( FLAG_VSYNC_HINT ) + + -- Define the camera to look into our 3d world + camera = RL_CreateCamera3D() + RL_SetCamera3DPosition( camera, { -125.0, 125.0, -125.0 } ) + RL_SetCamera3DTarget( camera, { 0, 0, 0 } ) + RL_SetCamera3DUp( camera, { 0, 1, 0 } ) + RL_SetCamera3DFovy( camera, 45 ) + RL_SetCameraMode( camera, CAMERA_ORBITAL ) + + -- Define mesh to be instanced + cube = RL_GenMeshCube( { 1, 1, 1 } ) + + -- Translate and rotate cubes randomly + for i = 1, MAX_INSTANCES do + local translation = RL_MatrixTranslate( { math.random( -50, 50 ), math.random( -50, 50 ), math.random( -50, 50 ) } ) + local axis = RL_Vector3Normalize( { math.random( 0, 360 ), math.random( 0, 360 ), math.random( 0, 360 ) } ) + local angle = math.rad( math.random( 0, 10 ) ) + local rotation = RL_MatrixRotate( axis, angle ) + + table.insert( transforms, RL_MatrixMultiply( rotation, translation ) ) + end + + -- Load lighting shader + shader = RL_LoadShader( RL_GetBasePath().."../resources/shaders/glsl330/lighting_instancing.vs", + RL_GetBasePath().."../resources/shaders/glsl330/lighting.fs" ) + + -- Get shader locations + local mvpLoc = RL_GetShaderLocation( shader, "mvp" ) + local viewPosLoc = RL_GetShaderLocation( shader, "viewPos" ) + local instanceTransformLoc = RL_GetShaderLocationAttrib( shader, "instanceTransform" ) + RL_SetShaderLocationIndex( shader, SHADER_LOC_MATRIX_MVP, mvpLoc ) + RL_SetShaderLocationIndex( shader, SHADER_LOC_VECTOR_VIEW, viewPosLoc ) + RL_SetShaderLocationIndex( shader, SHADER_LOC_MATRIX_MODEL, instanceTransformLoc ) + + -- Set shader value: ambient light level + local ambientLoc = RL_GetShaderLocation( shader, "ambient" ) + RL_SetShaderValue( shader, ambientLoc, { 0.2, 0.2, 0.2, 0.1 }, SHADER_UNIFORM_VEC4 ) + + -- Create one light + RL_CreateLight( LIGHT_DIRECTIONAL, { 50.0, 50.0, 0.0 }, RL_Vector3Zero(), WHITE, shader ) + + -- NOTE: We are assigning the intancing shader to material.shader + -- to be used on mesh drawing with DrawMeshInstanced() + matInstances = RL_LoadMaterialDefault() + RL_SetMaterialShader( matInstances, shader ) + RL_SetMaterialColor( matInstances, MATERIAL_MAP_DIFFUSE, RED ) + + -- 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 + matDefault = RL_LoadMaterialDefault() + RL_SetMaterialColor( matDefault, MATERIAL_MAP_DIFFUSE, BLUE ) +end + +function process( delta ) + RL_UpdateCamera3D( camera ) + + -- Update the light shader with the camera view position + local loc = RL_GetShaderLocationIndex( shader, SHADER_LOC_VECTOR_VIEW ) + RL_SetShaderValue( shader, loc, RL_GetCamera3DPosition( camera ), SHADER_UNIFORM_VEC3 ) +end + +function draw() + RL_ClearBackground( DARKBLUE ) + + RL_BeginMode3D( camera ) + -- Draw cube mesh with default material (BLUE) + RL_DrawMesh( cube, matDefault, RL_MatrixTranslate( { -10.0, 0.0, 0.0 } ) ) + + -- Draw meshes instanced using material containing instancing shader (RED + lighting), + -- transforms[] for the instances should be provided, they are dynamically + -- updated in GPU every frame, so we can animate the different mesh instances + RL_DrawMeshInstanced( cube, matInstances, transforms, MAX_INSTANCES ) + + -- Draw cube mesh with default material (BLUE) + RL_DrawMesh( cube, matDefault, RL_MatrixTranslate( { 10.0, 0.0, 0.0 } ) ) + RL_EndMode3D() + + RL_DrawFPS( { 10, 10 } ) +end diff --git a/examples/resources/lib/gui.lua b/examples/resources/lib/gui.lua index 4e4ee7e..da46744 100644 --- a/examples/resources/lib/gui.lua +++ b/examples/resources/lib/gui.lua @@ -45,7 +45,7 @@ Gui = { padding = 2, spacing = 4, scrollbarWidth = 8, - scrollAmount = 10, + scrollAmount = 20, heldCallback = nil, diff --git a/examples/resources/shaders/glsl330/lighting.fs b/examples/resources/shaders/glsl330/lighting.fs new file mode 100644 index 0000000..58845c8 --- /dev/null +++ b/examples/resources/shaders/glsl330/lighting.fs @@ -0,0 +1,82 @@ +#version 330 + +// Input vertex attributes (from vertex shader) +in vec3 fragPosition; +in vec2 fragTexCoord; +//in vec4 fragColor; +in vec3 fragNormal; + +// Input uniform values +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +// Output fragment color +out vec4 finalColor; + +// NOTE: Add here your custom variables + +#define MAX_LIGHTS 4 +#define LIGHT_DIRECTIONAL 0 +#define LIGHT_POINT 1 + +struct MaterialProperty { + vec3 color; + int useSampler; + sampler2D sampler; +}; + +struct Light { + int enabled; + int type; + vec3 position; + vec3 target; + vec4 color; +}; + +// Input lighting values +uniform Light lights[MAX_LIGHTS]; +uniform vec4 ambient; +uniform vec3 viewPos; + +void main() +{ + // Texel color fetching from texture sampler + vec4 texelColor = texture(texture0, fragTexCoord); + vec3 lightDot = vec3(0.0); + vec3 normal = normalize(fragNormal); + vec3 viewD = normalize(viewPos - fragPosition); + vec3 specular = vec3(0.0); + + // NOTE: Implement here your fragment shader code + + for (int i = 0; i < MAX_LIGHTS; i++) + { + if (lights[i].enabled == 1) + { + vec3 light = vec3(0.0); + + if (lights[i].type == LIGHT_DIRECTIONAL) + { + light = -normalize(lights[i].target - lights[i].position); + } + + if (lights[i].type == LIGHT_POINT) + { + light = normalize(lights[i].position - fragPosition); + } + + float NdotL = max(dot(normal, light), 0.0); + lightDot += lights[i].color.rgb*NdotL; + + float specCo = 0.0; + if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16.0); // 16 refers to shine + specular += specCo; + } + } + + finalColor = (texelColor*((colDiffuse + vec4(specular, 1.0))*vec4(lightDot, 1.0))); + finalColor += texelColor*(ambient/10.0)*colDiffuse; + + // Gamma correction + finalColor = pow(finalColor, vec4(1.0/2.2)); +} diff --git a/examples/resources/shaders/glsl330/lighting_instancing.vs b/examples/resources/shaders/glsl330/lighting_instancing.vs new file mode 100644 index 0000000..6775a2e --- /dev/null +++ b/examples/resources/shaders/glsl330/lighting_instancing.vs @@ -0,0 +1,36 @@ +#version 330 + +// Input vertex attributes +in vec3 vertexPosition; +in vec2 vertexTexCoord; +in vec3 vertexNormal; +//in vec4 vertexColor; // Not required + +in mat4 instanceTransform; + +// Input uniform values +uniform mat4 mvp; +uniform mat4 matNormal; + +// Output vertex attributes (to fragment shader) +out vec3 fragPosition; +out vec2 fragTexCoord; +out vec4 fragColor; +out vec3 fragNormal; + +// NOTE: Add here your custom variables + +void main() +{ + // Compute MVP for current instance + mat4 mvpi = mvp*instanceTransform; + + // Send vertex attributes to fragment shader + fragPosition = vec3(mvpi*vec4(vertexPosition, 1.0)); + fragTexCoord = vertexTexCoord; + //fragColor = vertexColor; + fragNormal = normalize(vec3(matNormal*vec4(vertexNormal, 1.0))); + + // Calculate final vertex position + gl_Position = mvpi*vec4(vertexPosition, 1.0); +} diff --git a/include/models.h b/include/models.h index 0113b62..606e003 100644 --- a/include/models.h +++ b/include/models.h @@ -45,6 +45,7 @@ int lmodelsUnloadMaterial( lua_State *L ); int lmodelsSetMaterialTexture( lua_State *L ); int lmodelsSetMaterialColor( lua_State *L ); int lmodelsSetMaterialValue( lua_State *L ); +int lmodelsSetMaterialShader( lua_State *L ); /* Model. */ int lmodelsLoadModel( lua_State *L ); int lmodelsLoadModelFromMesh( lua_State *L ); diff --git a/src/lua_core.c b/src/lua_core.c index 2a07a90..acf4843 100644 --- a/src/lua_core.c +++ b/src/lua_core.c @@ -1028,6 +1028,7 @@ void luaRegister() { lua_register( L, "RL_SetMaterialTexture", lmodelsSetMaterialTexture ); lua_register( L, "RL_SetMaterialColor", lmodelsSetMaterialColor ); lua_register( L, "RL_SetMaterialValue", lmodelsSetMaterialValue ); + lua_register( L, "RL_SetMaterialShader", lmodelsSetMaterialShader ); /* Model. */ lua_register( L, "RL_LoadModel", lmodelsLoadModel ); lua_register( L, "RL_LoadModelFromMesh", lmodelsLoadModelFromMesh ); diff --git a/src/models.c b/src/models.c index bc84f6c..f2f7f2e 100644 --- a/src/models.c +++ b/src/models.c @@ -1287,12 +1287,10 @@ int lmodelsDrawMesh( lua_State *L ) { return 1; } -/* TODO Untested. */ /* > success = RL_DrawMeshInstanced( Mesh mesh, Material material, Matrix{} transforms, int instances ) Draw multiple mesh instances with material and different transforms -Note! Untested. - Failure return false - Success return true @@ -1305,14 +1303,14 @@ int lmodelsDrawMeshInstanced( lua_State *L ) { } int instances = lua_tointeger( L, -1 ); lua_pop( L, 1 ); - Matrix matrises[ instances ]; + Matrix transforms[ instances ]; int t = lua_gettop( L ), i = 0; lua_pushnil( L ); while ( lua_next( L, t ) != 0 ) { if ( lua_istable( L, -1 ) ) { - matrises[i] = uluaGetMatrix( L ); + transforms[i] = uluaGetMatrix( L ); } i++; lua_pop( L, 1 ); @@ -1326,7 +1324,7 @@ int lmodelsDrawMeshInstanced( lua_State *L ) { lua_pushboolean( L, false ); return 1; } - DrawMeshInstanced( *state->meshes[ meshId ], *state->materials[ materialId ], matrises, instances ); + DrawMeshInstanced( *state->meshes[ meshId ], *state->materials[ materialId ], transforms, instances ); lua_pushboolean( L, true ); return 1; @@ -1699,6 +1697,35 @@ int lmodelsSetMaterialValue( lua_State *L ) { return 1; } +/* +> success = RL_SetMaterialShader( Material material, Shader shader ) + +Set shader for material + +- Failure return false +- Success return true +*/ +int lmodelsSetMaterialShader( lua_State *L ) { + if ( !lua_isnumber( L, -2 ) || !lua_isnumber( L, -1 ) ) { + TraceLog( LOG_WARNING, "%s", "Bad call of function. RL_SetMaterialShader( Material material, Shader shader )" ); + lua_pushboolean( L, false ); + return 1; + } + size_t shaderId = lua_tointeger( L, -1 ); + lua_pop( L, 1 ); + size_t materialId = lua_tointeger( L, -1 ); + + if ( !validMaterial( materialId || !validShader( shaderId ) ) ) { + lua_pushboolean( L, false ); + return 1; + } + + state->materials[ materialId ]->shader = *state->shaders[ shaderId ]; + lua_pushboolean( L, true ); + + return 1; +} + /* ## Models - Model */ diff --git a/src/rmath.c b/src/rmath.c index 141f8d5..a83eac4 100644 --- a/src/rmath.c +++ b/src/rmath.c @@ -1607,7 +1607,7 @@ int lmathMatrixInvert( lua_State *L ) { } /* -> result = MatrixIdentity() +> result = RL_MatrixIdentity() Get identity matrix -- cgit v1.2.3