fix motion vectors going through gate
authorhgn <hgodden00@gmail.com>
Fri, 2 Dec 2022 20:52:52 +0000 (20:52 +0000)
committerhgn <hgodden00@gmail.com>
Fri, 2 Dec 2022 20:52:52 +0000 (20:52 +0000)
19 files changed:
models_src/rs_gate.mdl
player_physics.h
render.h
shaders/alphatest.h
shaders/gpos.h
shaders/menu.h
shaders/motion_vectors_common.glsl
shaders/motion_vectors_vs.glsl
shaders/route.h
shaders/scoretext.h
shaders/sky.h
shaders/standard.h
shaders/terrain.h
shaders/vblend.h
shaders/viewchar.h
shaders/water.h
shaders/water_fast.h
world_gate.h
world_gen.h

index c554abe87fb8f593c51155a682f58ea680b371f8..f3221b9c00c7e9016cba506a975d4d755849ad1a 100644 (file)
Binary files a/models_src/rs_gate.mdl and b/models_src/rs_gate.mdl differ
index f395953932e19003e93cac528d76c538cb99531e..b6283bf3c6353fa1c4f31000e201a6fc88371556 100644 (file)
@@ -1092,6 +1092,15 @@ VG_STATIC void player_do_motion(void)
          m3x3_mulv( gate->transport, phys->m, phys->m );
          m3x3_mulv( gate->transport, phys->bob, phys->bob );
 
+         /* Pre-emptively edit the camera matrices so that the motion vectors 
+          * are correct */
+         m4x3f transport_i;
+         m4x4f transport_4;
+         m4x3_invert_affine( gate->transport, transport_i );
+         m4x3_expand( transport_i, transport_4 );
+         m4x4_mul( main_camera.mtx.pv, transport_4, main_camera.mtx.pv );
+         m4x4_mul( main_camera.mtx.v, transport_4, main_camera.mtx.v );
+
          v4f transport_rotation;
          m3x3_q( gate->transport, transport_rotation );
          q_mul( transport_rotation, phys->rb.q, phys->rb.q );
index 0bb4c3330bd42a878940e26feae5f9fb5213422a..e3c7ee734b515c4bf0e01b31e341c36f56531272 100644 (file)
--- a/render.h
+++ b/render.h
@@ -139,13 +139,13 @@ framebuffers[] =
       /*
        * The primary draw target
        */
-      "Main", 
+      "main", 
       .link = &gpipeline.fb_main,
       .resolution_div = 1,
       .attachments = 
       {
          {
-            "Colour", k_framebuffer_attachment_type_colour,
+            "colour", k_framebuffer_attachment_type_colour,
 
             .internalformat = GL_RGB,
             .format         = GL_RGB,
@@ -153,7 +153,7 @@ framebuffers[] =
             .attachment     = GL_COLOR_ATTACHMENT0
          },
          {
-            "Motion Vectors", k_framebuffer_attachment_type_colour,
+            "motion", k_framebuffer_attachment_type_colour,
 
             .quality        = k_framebuffer_quality_high_only,
             .internalformat = GL_RG16F,
@@ -162,7 +162,7 @@ framebuffers[] =
             .attachment     = GL_COLOR_ATTACHMENT1
          },
          {
-            "Depth/Stencil", k_framebuffer_attachment_type_renderbuffer,
+            "depth_stencil", k_framebuffer_attachment_type_renderbuffer,
 
             .internalformat = GL_DEPTH24_STENCIL8,
             .attachment     = GL_DEPTH_STENCIL_ATTACHMENT
@@ -175,7 +175,7 @@ framebuffers[] =
        * Note: it does not have a render buffer attachement because it's
        *       intended to be drawn to in a MAX blending mode
        */
-      "Heightmap", 
+      "heightmap", 
       .link = &gpipeline.fb_heightmap,
       .fixed_w = 1024,
       .fixed_h = 1024,
@@ -183,7 +183,7 @@ framebuffers[] =
       .attachments =
       {
          {
-            "Depth", k_framebuffer_attachment_type_colour,
+            "depth", k_framebuffer_attachment_type_colour,
 
             .internalformat = GL_R32F,
             .format         = GL_RED,
@@ -196,20 +196,20 @@ framebuffers[] =
       /*
        * Second rendered view from the perspective of the water reflection
        */
-      "Water reflection",
+      "water_reflection",
       .link = &gpipeline.fb_water_reflection,
       .resolution_div = 3,
       .attachments = 
       {
          {
-            "Colour", k_framebuffer_attachment_type_colour,
+            "colour", k_framebuffer_attachment_type_colour,
             .internalformat = GL_RGB,
             .format         = GL_RGB,
             .type           = GL_UNSIGNED_BYTE,
             .attachment     = GL_COLOR_ATTACHMENT0
          },
          {
-            "Depth/Stencil", k_framebuffer_attachment_type_renderbuffer,
+            "depth_stencil", k_framebuffer_attachment_type_renderbuffer,
 
             .internalformat = GL_DEPTH24_STENCIL8,
             .attachment     = GL_DEPTH_STENCIL_ATTACHMENT
@@ -221,20 +221,20 @@ framebuffers[] =
        * Thid rendered view from the perspective of the camera, but just 
        * captures stuff thats under the water
        */
-      "Water Beneath",
+      "water_beneath",
       .link = &gpipeline.fb_water_beneath,
       .resolution_div = 4,
       .attachments = 
       {
          {
-            "Colour", k_framebuffer_attachment_type_colour,
+            "colour", k_framebuffer_attachment_type_colour,
             .internalformat = GL_RGBA,
             .format         = GL_RGBA,
             .type           = GL_UNSIGNED_BYTE,
             .attachment     = GL_COLOR_ATTACHMENT0
          },
          {
-            "Depth/Stencil", k_framebuffer_attachment_type_renderbuffer,
+            "depth_stencil", k_framebuffer_attachment_type_renderbuffer,
 
             .internalformat = GL_DEPTH24_STENCIL8,
             .attachment     = GL_DEPTH_STENCIL_ATTACHMENT
@@ -596,7 +596,7 @@ VG_STATIC void render_init_fs_quad(void)
                     0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
 
                     0.2f, 0.0f, 0.8f, 1.0f, 0.2f, 1.0f,
-                    0.2f, 0.0f, 0.8f, 0.0f, 0.8f, 1.0f};
+                    0.2f, 0.0f, 0.8f, 0.0f, 0.8f, 1.0f };
 
    glGenVertexArrays( 1, &gpipeline.fsquad.vao );
    glGenBuffers( 1, &gpipeline.fsquad.vbo );
@@ -605,7 +605,7 @@ VG_STATIC void render_init_fs_quad(void)
    glBufferData( GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW );
    glBindVertexArray( gpipeline.fsquad.vao );
    glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 
-         sizeof(float)*2, (void*)0 );
+                          sizeof(float)*2, (void*)0 );
    glEnableVertexAttribArray( 0 );
 
    VG_CHECK_GL_ERR();
index 8b06893f0b88a6fefae287b57e22af32c36d26cc..25e58795ec18da791c1124970eaca74933978860 100644 (file)
@@ -17,7 +17,7 @@ static struct vg_shader _shader_alphatest = {
 "\n"
 "#line      2        0 \n"
 "#line       1        2 \n"
-"const float k_motion_lerp_amount = 0.05;\n"
+"const float k_motion_lerp_amount = 0.01;\n"
 "\n"
 "#line      2        0 \n"
 "\n"
@@ -26,6 +26,8 @@ static struct vg_shader _shader_alphatest = {
 "\n"
 "void vs_motion_out( vec4 vproj0, vec4 vproj1 )\n"
 "{\n"
+"   // This magically solves some artifacting errors!\n"
+"   //\n"
 "   vproj1 = vproj0*(1.0-k_motion_lerp_amount) + vproj1*k_motion_lerp_amount;\n"
 "\n"
 "   aMotionVec0 = vec3( vproj0.xy, vproj0.w );\n"
@@ -182,7 +184,7 @@ static struct vg_shader _shader_alphatest = {
 "\n"
 "#line     13        0 \n"
 "#line       1        2 \n"
-"const float k_motion_lerp_amount = 0.05;\n"
+"const float k_motion_lerp_amount = 0.01;\n"
 "\n"
 "#line      2        0 \n"
 "\n"
index a41a7f7c56d76155c81f8722de59c697842a1737..2f4440db78c899b68542ce010f21595c7c5394fc 100644 (file)
@@ -17,7 +17,7 @@ static struct vg_shader _shader_gpos = {
 "\n"
 "#line      2        0 \n"
 "#line       1        2 \n"
-"const float k_motion_lerp_amount = 0.05;\n"
+"const float k_motion_lerp_amount = 0.01;\n"
 "\n"
 "#line      2        0 \n"
 "\n"
@@ -26,6 +26,8 @@ static struct vg_shader _shader_gpos = {
 "\n"
 "void vs_motion_out( vec4 vproj0, vec4 vproj1 )\n"
 "{\n"
+"   // This magically solves some artifacting errors!\n"
+"   //\n"
 "   vproj1 = vproj0*(1.0-k_motion_lerp_amount) + vproj1*k_motion_lerp_amount;\n"
 "\n"
 "   aMotionVec0 = vec3( vproj0.xy, vproj0.w );\n"
index a0baa701ad00b221093b503b3671710f10885e3a..3bf0d1ff357744da0de0cea795e0aba7d7a0fe80 100644 (file)
@@ -17,7 +17,7 @@ static struct vg_shader _shader_menu = {
 "\n"
 "#line      2        0 \n"
 "#line       1        2 \n"
-"const float k_motion_lerp_amount = 0.05;\n"
+"const float k_motion_lerp_amount = 0.01;\n"
 "\n"
 "#line      2        0 \n"
 "\n"
@@ -26,6 +26,8 @@ static struct vg_shader _shader_menu = {
 "\n"
 "void vs_motion_out( vec4 vproj0, vec4 vproj1 )\n"
 "{\n"
+"   // This magically solves some artifacting errors!\n"
+"   //\n"
 "   vproj1 = vproj0*(1.0-k_motion_lerp_amount) + vproj1*k_motion_lerp_amount;\n"
 "\n"
 "   aMotionVec0 = vec3( vproj0.xy, vproj0.w );\n"
index 1d6ed9794dd6768a6a6a495cd243896cb315d6bd..7e6c114679e113dfd6c4685e16608f15d9e73b87 100644 (file)
@@ -1 +1 @@
-const float k_motion_lerp_amount = 0.05;
+const float k_motion_lerp_amount = 0.01;
index 63a17dbdb8f06b22f39e676347292168912a107a..492f7a4814218fdcf3d08546e48a4bcf777b75a9 100644 (file)
@@ -5,6 +5,8 @@ out vec3 aMotionVec1;
 
 void vs_motion_out( vec4 vproj0, vec4 vproj1 )
 {
+   // This magically solves some artifacting errors!
+   //
    vproj1 = vproj0*(1.0-k_motion_lerp_amount) + vproj1*k_motion_lerp_amount;
 
    aMotionVec0 = vec3( vproj0.xy, vproj0.w );
index b003858c513f284ee2ec4f9f1544319516045e79..60b5c5cd2676570f5ad3e0d07b9e0f72cdbeb291 100644 (file)
@@ -17,7 +17,7 @@ static struct vg_shader _shader_route = {
 "\n"
 "#line      2        0 \n"
 "#line       1        2 \n"
-"const float k_motion_lerp_amount = 0.05;\n"
+"const float k_motion_lerp_amount = 0.01;\n"
 "\n"
 "#line      2        0 \n"
 "\n"
@@ -26,6 +26,8 @@ static struct vg_shader _shader_route = {
 "\n"
 "void vs_motion_out( vec4 vproj0, vec4 vproj1 )\n"
 "{\n"
+"   // This magically solves some artifacting errors!\n"
+"   //\n"
 "   vproj1 = vproj0*(1.0-k_motion_lerp_amount) + vproj1*k_motion_lerp_amount;\n"
 "\n"
 "   aMotionVec0 = vec3( vproj0.xy, vproj0.w );\n"
@@ -182,7 +184,7 @@ static struct vg_shader _shader_route = {
 "\n"
 "#line     13        0 \n"
 "#line       1        2 \n"
-"const float k_motion_lerp_amount = 0.05;\n"
+"const float k_motion_lerp_amount = 0.01;\n"
 "\n"
 "#line      2        0 \n"
 "\n"
index 06fa71996660b13081b1a1276ada26be4addd9c9..fea61cc0a68631d47539ae05e13432949c47c263 100644 (file)
@@ -17,7 +17,7 @@ static struct vg_shader _shader_scoretext = {
 "\n"
 "#line      2        0 \n"
 "#line       1        2 \n"
-"const float k_motion_lerp_amount = 0.05;\n"
+"const float k_motion_lerp_amount = 0.01;\n"
 "\n"
 "#line      2        0 \n"
 "\n"
@@ -26,6 +26,8 @@ static struct vg_shader _shader_scoretext = {
 "\n"
 "void vs_motion_out( vec4 vproj0, vec4 vproj1 )\n"
 "{\n"
+"   // This magically solves some artifacting errors!\n"
+"   //\n"
 "   vproj1 = vproj0*(1.0-k_motion_lerp_amount) + vproj1*k_motion_lerp_amount;\n"
 "\n"
 "   aMotionVec0 = vec3( vproj0.xy, vproj0.w );\n"
@@ -203,7 +205,7 @@ static struct vg_shader _shader_scoretext = {
 "\n"
 "#line     12        0 \n"
 "#line       1        2 \n"
-"const float k_motion_lerp_amount = 0.05;\n"
+"const float k_motion_lerp_amount = 0.01;\n"
 "\n"
 "#line      2        0 \n"
 "\n"
index 931dec18490f47538d400d67ed870117e1eea94e..b7b26ef487bf178941623af151b4796be2a203a4 100644 (file)
@@ -17,7 +17,7 @@ static struct vg_shader _shader_sky = {
 "\n"
 "#line      2        0 \n"
 "#line       1        2 \n"
-"const float k_motion_lerp_amount = 0.05;\n"
+"const float k_motion_lerp_amount = 0.01;\n"
 "\n"
 "#line      2        0 \n"
 "\n"
@@ -26,6 +26,8 @@ static struct vg_shader _shader_sky = {
 "\n"
 "void vs_motion_out( vec4 vproj0, vec4 vproj1 )\n"
 "{\n"
+"   // This magically solves some artifacting errors!\n"
+"   //\n"
 "   vproj1 = vproj0*(1.0-k_motion_lerp_amount) + vproj1*k_motion_lerp_amount;\n"
 "\n"
 "   aMotionVec0 = vec3( vproj0.xy, vproj0.w );\n"
@@ -75,7 +77,7 @@ static struct vg_shader _shader_sky = {
 "in vec3 aCo;\n"
 "\n"
 "#line       1        1 \n"
-"const float k_motion_lerp_amount = 0.05;\n"
+"const float k_motion_lerp_amount = 0.01;\n"
 "\n"
 "#line      2        0 \n"
 "\n"
index 319e6be91bf5a4f181d49ec9c1402a1beef5ad34..cf61d03be700cc16df6532698314bcba747c1c2d 100644 (file)
@@ -17,7 +17,7 @@ static struct vg_shader _shader_standard = {
 "\n"
 "#line      2        0 \n"
 "#line       1        2 \n"
-"const float k_motion_lerp_amount = 0.05;\n"
+"const float k_motion_lerp_amount = 0.01;\n"
 "\n"
 "#line      2        0 \n"
 "\n"
@@ -26,6 +26,8 @@ static struct vg_shader _shader_standard = {
 "\n"
 "void vs_motion_out( vec4 vproj0, vec4 vproj1 )\n"
 "{\n"
+"   // This magically solves some artifacting errors!\n"
+"   //\n"
 "   vproj1 = vproj0*(1.0-k_motion_lerp_amount) + vproj1*k_motion_lerp_amount;\n"
 "\n"
 "   aMotionVec0 = vec3( vproj0.xy, vproj0.w );\n"
@@ -182,7 +184,7 @@ static struct vg_shader _shader_standard = {
 "\n"
 "#line     13        0 \n"
 "#line       1        2 \n"
-"const float k_motion_lerp_amount = 0.05;\n"
+"const float k_motion_lerp_amount = 0.01;\n"
 "\n"
 "#line      2        0 \n"
 "\n"
index cf32d5ea5c5bc49bc2c103ca19e8154c2531474e..b2730fba9ebc4ab69ed67f166affcba6aefada36 100644 (file)
@@ -17,7 +17,7 @@ static struct vg_shader _shader_terrain = {
 "\n"
 "#line      2        0 \n"
 "#line       1        2 \n"
-"const float k_motion_lerp_amount = 0.05;\n"
+"const float k_motion_lerp_amount = 0.01;\n"
 "\n"
 "#line      2        0 \n"
 "\n"
@@ -26,6 +26,8 @@ static struct vg_shader _shader_terrain = {
 "\n"
 "void vs_motion_out( vec4 vproj0, vec4 vproj1 )\n"
 "{\n"
+"   // This magically solves some artifacting errors!\n"
+"   //\n"
 "   vproj1 = vproj0*(1.0-k_motion_lerp_amount) + vproj1*k_motion_lerp_amount;\n"
 "\n"
 "   aMotionVec0 = vec3( vproj0.xy, vproj0.w );\n"
@@ -183,7 +185,7 @@ static struct vg_shader _shader_terrain = {
 "\n"
 "#line     14        0 \n"
 "#line       1        2 \n"
-"const float k_motion_lerp_amount = 0.05;\n"
+"const float k_motion_lerp_amount = 0.01;\n"
 "\n"
 "#line      2        0 \n"
 "\n"
index ad3f82b1236790ce119a231266379ce831b2d157..fd558ef8acdd3798829f4ce5d9173a982ec98158 100644 (file)
@@ -17,7 +17,7 @@ static struct vg_shader _shader_vblend = {
 "\n"
 "#line      2        0 \n"
 "#line       1        2 \n"
-"const float k_motion_lerp_amount = 0.05;\n"
+"const float k_motion_lerp_amount = 0.01;\n"
 "\n"
 "#line      2        0 \n"
 "\n"
@@ -26,6 +26,8 @@ static struct vg_shader _shader_vblend = {
 "\n"
 "void vs_motion_out( vec4 vproj0, vec4 vproj1 )\n"
 "{\n"
+"   // This magically solves some artifacting errors!\n"
+"   //\n"
 "   vproj1 = vproj0*(1.0-k_motion_lerp_amount) + vproj1*k_motion_lerp_amount;\n"
 "\n"
 "   aMotionVec0 = vec3( vproj0.xy, vproj0.w );\n"
@@ -181,7 +183,7 @@ static struct vg_shader _shader_vblend = {
 "\n"
 "#line     12        0 \n"
 "#line       1        2 \n"
-"const float k_motion_lerp_amount = 0.05;\n"
+"const float k_motion_lerp_amount = 0.01;\n"
 "\n"
 "#line      2        0 \n"
 "\n"
index e8d6fe741c482c6ffc553e64cd4439bfabaf0587..604cae2534ba85af4b973e54d2d565de9b5e614e 100644 (file)
@@ -17,7 +17,7 @@ static struct vg_shader _shader_viewchar = {
 "\n"
 "#line      2        0 \n"
 "#line       1        2 \n"
-"const float k_motion_lerp_amount = 0.05;\n"
+"const float k_motion_lerp_amount = 0.01;\n"
 "\n"
 "#line      2        0 \n"
 "\n"
@@ -26,6 +26,8 @@ static struct vg_shader _shader_viewchar = {
 "\n"
 "void vs_motion_out( vec4 vproj0, vec4 vproj1 )\n"
 "{\n"
+"   // This magically solves some artifacting errors!\n"
+"   //\n"
 "   vproj1 = vproj0*(1.0-k_motion_lerp_amount) + vproj1*k_motion_lerp_amount;\n"
 "\n"
 "   aMotionVec0 = vec3( vproj0.xy, vproj0.w );\n"
@@ -191,7 +193,7 @@ static struct vg_shader _shader_viewchar = {
 "\n"
 "#line     11        0 \n"
 "#line       1        2 \n"
-"const float k_motion_lerp_amount = 0.05;\n"
+"const float k_motion_lerp_amount = 0.01;\n"
 "\n"
 "#line      2        0 \n"
 "\n"
index 710d5c1fe0546f6fe5cf503b51b4945b8f134ec8..93dcba858e07048a0ecdba1a9247ffd05cceb3c3 100644 (file)
@@ -17,7 +17,7 @@ static struct vg_shader _shader_water = {
 "\n"
 "#line      2        0 \n"
 "#line       1        2 \n"
-"const float k_motion_lerp_amount = 0.05;\n"
+"const float k_motion_lerp_amount = 0.01;\n"
 "\n"
 "#line      2        0 \n"
 "\n"
@@ -26,6 +26,8 @@ static struct vg_shader _shader_water = {
 "\n"
 "void vs_motion_out( vec4 vproj0, vec4 vproj1 )\n"
 "{\n"
+"   // This magically solves some artifacting errors!\n"
+"   //\n"
 "   vproj1 = vproj0*(1.0-k_motion_lerp_amount) + vproj1*k_motion_lerp_amount;\n"
 "\n"
 "   aMotionVec0 = vec3( vproj0.xy, vproj0.w );\n"
@@ -189,7 +191,7 @@ static struct vg_shader _shader_water = {
 "\n"
 "#line     20        0 \n"
 "#line       1        2 \n"
-"const float k_motion_lerp_amount = 0.05;\n"
+"const float k_motion_lerp_amount = 0.01;\n"
 "\n"
 "#line      2        0 \n"
 "\n"
index 756f308cb3c4d01b8d50ad8e5fb73e04570f6f9d..196c71ee738a0adea3e3f5860dccde17da6fab71 100644 (file)
@@ -17,7 +17,7 @@ static struct vg_shader _shader_water_fast = {
 "\n"
 "#line      2        0 \n"
 "#line       1        2 \n"
-"const float k_motion_lerp_amount = 0.05;\n"
+"const float k_motion_lerp_amount = 0.01;\n"
 "\n"
 "#line      2        0 \n"
 "\n"
@@ -26,6 +26,8 @@ static struct vg_shader _shader_water_fast = {
 "\n"
 "void vs_motion_out( vec4 vproj0, vec4 vproj1 )\n"
 "{\n"
+"   // This magically solves some artifacting errors!\n"
+"   //\n"
 "   vproj1 = vproj0*(1.0-k_motion_lerp_amount) + vproj1*k_motion_lerp_amount;\n"
 "\n"
 "   aMotionVec0 = vec3( vproj0.xy, vproj0.w );\n"
@@ -186,7 +188,7 @@ static struct vg_shader _shader_water_fast = {
 "\n"
 "#line     17        0 \n"
 "#line       1        2 \n"
-"const float k_motion_lerp_amount = 0.05;\n"
+"const float k_motion_lerp_amount = 0.01;\n"
 "\n"
 "#line      2        0 \n"
 "\n"
index 3e35081e2b1c72639bfa510a9196eb4da04fc706..9d1287711782d7570fb0c26505647beb2b9c5978 100644 (file)
@@ -52,7 +52,11 @@ VG_STATIC int render_gate( teleport_gate *gate, camera *cam )
 
    v3f v0;
    v3_sub( cam->pos, gate->co[0], v0 );
-   if( v3_dot(v0, gatedir) >= 0.0f )
+
+   float dist = v3_dot(v0, gatedir);
+
+   /* Hard cutoff */
+   if( dist > 3.0f )
       return 0;
 
    if( v3_dist( cam->pos, gate->co[0] ) > 100.0f )
@@ -80,7 +84,7 @@ VG_STATIC int render_gate( teleport_gate *gate, camera *cam )
    static camera gate_view;
    gate_view.fov = cam->fov;
    gate_view.nearz = 0.1f;
-   gate_view.farz  = 900.0f;
+   gate_view.farz  = 2000.0f;
 
    m4x3_mul( gate->transport, cam->transform, gate_view.transform );
    camera_update_view( &gate_view );
@@ -93,7 +97,9 @@ VG_STATIC int render_gate( teleport_gate *gate, camera *cam )
    
    m4x3_mulp( gate_view.transform_inverse, surface, surface );
    surface[3] = -fabsf(surface[3]);
-   m4x4_clip_projection( gate_view.mtx.p, surface );
+
+   if( dist < -0.5f )
+      m4x4_clip_projection( gate_view.mtx.p, surface );
 
    /* Ready to draw with new camrea */
    camera_finalize( &gate_view );
index 1648bdf490370113e0b954f1a2d26b8b1c6b7c53..47ed5ee9c9b64624c20bf060c90921f3bb7d8037 100644 (file)
@@ -54,6 +54,8 @@ VG_STATIC void world_apply_procedural_foliage( struct world_material *mat )
    mdl_node *mblob = mdl_node_from_name( mfoliage, "blob" );
    mdl_submesh *sm_blob = mdl_node_submesh( mfoliage, mblob, 0 );
 
+   int count = 0;
+
    for( int i=0;i<100000;i++ )
    {
       v3f pos;
@@ -64,7 +66,7 @@ VG_STATIC void world_apply_procedural_foliage( struct world_material *mat )
       ray_hit hit;
       hit.dist = INFINITY;
 
-      if( ray_world( pos, (v3f){0.0f,-1.0f,0.0f}, &hit ))
+      if( ray_world( pos, (v3f){0.0001f,-1.0f,0.0001f}, &hit ))
       {
          struct world_material *m1 = ray_hit_material( &hit );
          if((hit.normal[1] > 0.8f) && (m1 == mat) && (hit.pos[1] > 0.0f+10.0f))
@@ -83,9 +85,13 @@ VG_STATIC void world_apply_procedural_foliage( struct world_material *mat )
             v3_copy( hit.pos, transform[3] );
             scene_add_submesh( world.scene_no_collide, mfoliage, 
                                sm_blob, transform);
+
+            count ++;
          }
       }
    }
+
+   vg_info( "%d foliage models added\n", count );
 }
 
 VG_STATIC void world_ents_allocate(void)