Trails

Share your ZGE-development tips and techniques here!

Moderator: Moderators

Post Reply
User avatar
Kjell
Posts: 1985
Joined: Sat Feb 23, 2008 11:15 pm

Trails

Post by Kjell »

Hi guys,

Although I'm pretty sure I already posted a similar example before ( could have been wireframe only though ), let me put together a simple solid trail example .. give me a couple of minutes :) I did have this "Samurai" variant lying around though.

K
Attachments
Samurai.zip
(40.16 KiB) Downloaded 865 times
User avatar
Kjell
Posts: 1985
Joined: Sat Feb 23, 2008 11:15 pm

Post by Kjell »

Voila ( updated )
Attachments
Trail.zgeproj
(2.55 KiB) Downloaded 1007 times
User avatar
jph_wacheski
Posts: 1005
Joined: Sat Feb 16, 2008 8:10 pm
Location: Canada
Contact:

sweetness

Post by jph_wacheski »

Yeah,. that's the ticket!

This will be some fun to play around with,. the 'samurai' example is quite nice! Are you going to do a hack'n slash game?! :shock:
I am sure we can design loads of variants on this kind of poly ribbon type effect,. big huge thanks again for helping with another math/logic puzzle.

You roc Kjell!
iterationGAMES.com
User avatar
Kjell
Posts: 1985
Joined: Sat Feb 23, 2008 11:15 pm

Post by Kjell »

:?

I noticed that both examples don't run exactly as they should on every system. Might have to do with differences in framerate, or even video cards. If you want to take the safe route, instead of writing off the "new" value at the incremented index, push all array values down a cell so the newest value always resides at [0]. That way you don't have to do any trickery in the Render Component ( although it is a slightly slower approach ).

Here's what it should look like.

K
Attachments
Trail.jpg
Trail.jpg (74.38 KiB) Viewed 19009 times
User avatar
VilleK
Site Admin
Posts: 2416
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Post by VilleK »

Very nice effect Kjell!

I also noticed it looked strange sometimes. After lots of debugging I found the problem. There is a problem in 1.9.5b where comparing integer values do not behave correctly.

In your render-expression:

if(TrailIndex < 0) TrailIndex += Mouse.SizeDim1-1;

TrailIndex and 0 are integers so the "(TrailIndex < 0)" is the problem. It seems to work most times on Windows anyway, but when trying it on Linux it crashed. I will fix this as soon as I can.
User avatar
Ats
Posts: 933
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: Trails

Post by Ats »

Hello.
I intend to use something like this in my boat game, for the wind. But since your effect is made of pure openGL functions, I don't know if it is compatible with ES2/GL3. I tried a few things already, but the trail isn't showing up. Should I abandon the openGL functions and port that to a MeshExpression instead?
User avatar
Kjell
Posts: 1985
Joined: Sat Feb 23, 2008 11:15 pm

Re: Trails

Post by Kjell »

Hi Ats,
Ats wrote: Mon Jan 19, 2026 9:13 amBut since your effect is made of pure openGL functions, I don't know if it is compatible with ES2/GL3.
I just double-checked my example .. but it doesn't use any OpenGL calls? So i'm a little confused by your response :?

K
User avatar
Ats
Posts: 933
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: Trails

Post by Ats »

Whoops, sorry. I'm on a long bus trip... I thought it was the same trail example as another one that I have on my drive. I'm pretty sure it was also made by you :

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" CameraPosition="0 -14 0" CameraRotation="-0.25 -0.3832 0" FileVersion="2">
  <OnLoaded>
    <ZExternalLibrary ModuleName="opengl32">
      <BeforeInitExp>
<![CDATA[//

if(ANDROID)
{
  this.ModuleName = "libGLESv1_CM.so";
}
else if(LINUX)
{
  this.ModuleName = "libGL.so";
}
else
{
  this.ModuleName = "opengl32";
}]]>
      </BeforeInitExp>
      <Source>
<![CDATA[//

void glAlphaFunc(int func, float val){}
void glDisable(int cap){}
void glEnable(int cap){}

void glBegin(int mode){}
void glEnd(){}
void glTexCoord2f(float s, float t){}
void glVertex3f(float x, float y, float z){}
void glVertex3i(int x, int y, int z){}]]>
      </Source>
    </ZExternalLibrary>
    <ZExpression>
      <Expression>
<![CDATA[// Set alpha testing to greater-than 0

glAlphaFunc(0x0204, 0);

// Initialize trail

float t, x, y, z;

t = App.Time*8;

x = sin(t/7)*4;
y = cos(t/8)*2+2;
z = sin(t/9)*4;

for(int i=0; i<16; i++)
{
  Trail[i,0] = x;
  Trail[i,1] = y;
  Trail[i,2] = z;
}]]>
      </Expression>
    </ZExpression>
  </OnLoaded>
  <OnUpdate>
    <ZExpression>
      <Expression>
<![CDATA[// Camera rotation

App.CameraRotation.Y =   App.MousePosition.X/9*4;
App.CameraRotation.X = 0-App.MousePosition.Y/4;

// Camera position

float x, y;

x = App.CameraRotation.X*PI*2;
y = App.CameraRotation.Y*PI*2;

App.CameraPosition.X = 0-cos(x)*sin(y)*16;
App.CameraPosition.Y = 2+sin(x)       *16;
App.CameraPosition.Z =   cos(x)*cos(y)*16;]]>
      </Expression>
    </ZExpression>
    <ZExpression>
      <Expression>
<![CDATA[// Update timer ( 5fps ) & increment index

int i = TrailIndex;

TrailTimer += App.DeltaTime;

if(TrailTimer > 1/5)
{
  TrailTimer -= 1/5;
  i = TrailIndex = (TrailIndex + 1) & 15;
}

TrailTexture.TextureX = TrailTimer*5/16;

// Update active segment

float t = App.Time*8;

Trail[i,0] = sin(t/7)*4;
Trail[i,1] = cos(t/8)*2+2;
Trail[i,2] = sin(t/9)*4;]]>
      </Expression>
    </ZExpression>
  </OnUpdate>
  <OnRender>
    <UseMaterial Material="GridMaterial"/>
    <ZExpression>
      <Expression>
<![CDATA[// Quick & dirty grid rendering

glBegin(1);

for(int i=-4; i<=4; i++)
{
  glVertex3i(i, 0, -4); glVertex3i(i, 0, 4);
  glVertex3i(-4, 0, i); glVertex3i(4, 0, i);
}

glEnd();]]>
      </Expression>
    </ZExpression>
    <UseMaterial Material="TrailMaterial"/>
    <ZExpression>
      <Expression>
<![CDATA[// Quick & dirty trail rendering*

float x, y, z;

glEnable(0x0BC0);
glBegin(5);

for(int i=0; i<16; i++)
{
  int p = (TrailIndex-i) & 15;

  x = Trail[p,0];
  y = Trail[p,1];
  z = Trail[p,2];

  glTexCoord2f(i/16f,0); glVertex3f(x, y-0.5, z);
  glTexCoord2f(i/16f,1); glVertex3f(x, y+0.5, z);
}

glEnd();
glDisable(0x0BC0);

/*
 * You want to init & upload a texture buffer only once ( since it's always the same )
 * and only update the active trail node using glBufferSubData for the best performance.
 */]]>
      </Expression>
    </ZExpression>
  </OnRender>
  <Content>
    <Material Name="GridMaterial" Light="0"/>
    <Array Name="Trail" Dimensions="1" SizeDim1="16" SizeDim2="3">
      <Values>
<![CDATA[789C636018DA000000C00001]]>
      </Values>
    </Array>
    <Variable Name="TrailIndex" Type="1"/>
    <Variable Name="TrailTimer"/>
    <Bitmap Name="TrailBitmap" Width="256" Filter="1">
      <Producers>
        <BitmapExpression>
          <Expression>
<![CDATA[//

Pixel.R = 1;
Pixel.G = 1;
Pixel.B = 1;
Pixel.A = -0.5-(abs(Y-0.5)*2-(1-X))*8;]]>
          </Expression>
        </BitmapExpression>
      </Producers>
    </Bitmap>
    <Material Name="TrailMaterial" Shading="1" Color="1 0 0 0.5" Light="0" DrawBackFace="255">
      <Textures>
        <MaterialTexture Name="TrailTexture" Texture="TrailBitmap" TextureX="0.0521" TexCoords="1" Origin="0 0 0"/>
      </Textures>
    </Material>
  </Content>
</ZApplication>
Now I realize that the trail in this topic uses a RenderNet.
In my case, I'd like to display a few of those trails at the same time, at different coordinates, with different shapes and on ES2/GL3. I'm thinking of a clone model per trail.
Should I go with RenderNet or a MeshExpression?
User avatar
Kjell
Posts: 1985
Joined: Sat Feb 23, 2008 11:15 pm

Re: Trails

Post by Kjell »

Hi Ats,
Ats wrote: Mon Jan 19, 2026 12:29 pmShould I go with RenderNet or a MeshExpression?
Probably neither .. i suspect you're trying to do something like in Wind Waker?

Image

Just use a static mesh and animate the texture matrix. The only downside is that in ZGE you can't render a part of a mesh ( without using OpenGL calls ), but that shouldn't affect performance all that much.

+ Attached is the actual texture used in Wind Waker.

K
Attachments
Texture.png
Texture.png (3.24 KiB) Viewed 10890 times
User avatar
Ats
Posts: 933
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: Trails

Post by Ats »

You suspect right. But I want the wind to pass near the camera, so we can appreciate the direction of the wind. Not just breezes in a distance. Would the stretched bitmap work in that case?
It really looks like your polygon trail :
Screenshot_20260121-153034.png
Screenshot_20260121-153034.png (546.81 KiB) Viewed 10805 times
But the bitmap technique is interesting for the distance :D
User avatar
Kjell
Posts: 1985
Joined: Sat Feb 23, 2008 11:15 pm

Re: Trails

Post by Kjell »

Hi Ats,
Ats wrote: Wed Jan 21, 2026 2:33 pmNot just breezes in a distance. Would the stretched bitmap work in that case?
Just double-checked it .. and they use the exact same meshes & texture for up-close wind trails. The only reason it looks slightly different in the distance is because of the depth-of-field effect applied to pixels beyond a certain depth value.

Image

+ Added a video ( in an attempt ) to show that the meshes are completely static.

K
Attachments
Trails.zip
(2.97 MiB) Downloaded 161 times
User avatar
Ats
Posts: 933
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: Trails

Post by Ats »

Oh. All right :wink:
Thanks. I'll try that. I wonder how they manage to handle the looping, though. Maybe it's an animated texture?

Edit:
I found this very interesting article about this wind effect :D
https://medium.com/@gordonnl/wind-f4fc7a3b366a
User avatar
Kjell
Posts: 1985
Joined: Sat Feb 23, 2008 11:15 pm

Re: Trails

Post by Kjell »

Hi Ats,
Ats wrote: Thu Jan 22, 2026 9:11 amI wonder how they manage to handle the looping, though.
Here's a quick & dirty example of a looping ..

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" FileVersion="2">
  <OnLoaded>
    <SpawnModel Model="Trail"/>
  </OnLoaded>
  <Content>
    <Model Name="Trail">
      <OnUpdate>
        <ZExpression>
          <Expression>
<![CDATA[// Animate texture coordinates & material alpha

float t = frac(App.Time)*7;

if(t < 2)
{
  TrailMaterial.Color.A = t/2;
}
else if(t > 5)
{
  TrailMaterial.Color.A = (7-t)/2;
}
else
{
  TrailMaterial.Color.A = 1;
}

TrailTexture.TextureX = -t;]]>
          </Expression>
        </ZExpression>
      </OnUpdate>
      <OnRender>
        <UseMaterial Material="TrailMaterial"/>
        <RenderMesh Mesh="LoopMesh"/>
      </OnRender>
    </Model>
    <Mesh Name="LoopMesh">
      <Producers>
        <MeshBox Scale="64 1 1" XCount="63" Grid2DOnly="255"/>
        <MeshExpression Scale="0.2 0.2 0.2" AutoNormals="0">
          <Expression>
<![CDATA[//

V.X += 16;

if(V.X >= 0 && V.X <= 32)
{
  float t = V.X*PI/16;
  float a = 8-V.Y;

  V.X = sin(t)*a;
  V.Y = 8-cos(t)*a;
}
else if(V.X > 0)
{
  V.X -= 32;
}]]>
          </Expression>
        </MeshExpression>
      </Producers>
    </Mesh>
    <Bitmap Name="TrailBitmap" Width="16" Height="16">
      <Producers>
        <BitmapExpression>
          <Expression>
<![CDATA[//

float s = 0.5-X, t = 0.5-Y;
Pixel = vector4(1, 1, 1, 32-sqrt(s*s+t*t)*64);]]>
          </Expression>
        </BitmapExpression>
      </Producers>
    </Bitmap>
    <Material Name="TrailMaterial" Blend="1" ZBuffer="0">
      <Textures>
        <MaterialTexture Name="TrailTexture" Texture="TrailBitmap" TextureScale="8 1 1" TextureWrapMode="2" TexCoords="1" Origin="0 0.5 0"/>
      </Textures>
    </Material>
  </Content>
</ZApplication>
Ats wrote: Thu Jan 22, 2026 9:11 amI found this very interesting article about this wind effect :D
D'oh .. guess i should have googled :)

K
User avatar
VilleK
Site Admin
Posts: 2416
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: Trails

Post by VilleK »

This thread reminds me how much I enjoyed Wind Waker.

@Ats: Nice work on the sailboat project so far.
Post Reply