How to achieve this material effect [gif image]?

materials
shaders

#1

It’s the scene ground of a commercial game.
I very like the grid lines effect.
I do not know how to describe it, the grid lines like a wave?
wave2


Fixed texture size
#2

Shader can achieve this effect


#3

As @Waverider says, you’ll probably need to write your own shader to achieve this effect. Have a look at the ShaderMaterial docs to get started, especially the code of the examples linked there.

Writing your own shaders is quite daunting at first, but start with some really basic ones (try writing a single color shader, or mapping a texture to a cube) and go from there.


#4

When I first looked at shaders, I found this interactive book.
https://thebookofshaders.com/ resp. https://thebookofshaders.com/01/
I really liked it. Different languages are available!

Then I made some examples for beginners. Maybe that can help. See http://threejs.hofk.de/ in the middle. Because the detailed comments for beginners are in German, I have checked to copy them into https://www.deepl.com/translator
To translate into English.
I think the result is useful. Give it a try.


#5

A very rough solution, based on this cool shader: http://madebyevan.com/shaders/grid/

jsfiddle example

Code of shaders:

  var vertexShader = `
    uniform float time;
    varying vec3 pos;
    void main()	{
      pos = position;
      vec3 p = position;
      p.y = sin(p.x * .1 - time) * cos(p.z * .1 - time) * 5.;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(p,1.0);
    }
  `;
  var fragmentShader = `
    /* based on http://madebyevan.com/shaders/grid/ */
  
    #extension GL_OES_standard_derivatives : enable

    varying vec3 pos;
    uniform float time;
    
    float line(float width, vec3 step){
      vec3 tempCoord = pos / step;
      
      vec2 coord = tempCoord.xz;

      vec2 grid = abs(fract(coord - 0.5) - 0.5) / fwidth(coord * width);
      float line = min(grid.x, grid.y);
      
      return 1. - min(line, 1.0);
    }
    
    void main() {
      float v = line(1., vec3(1.)) + line(1.5, vec3(10.));      
      vec3 c = v * vec3(0., 1., 1.) * (sin(time * 5. - pos.z * .25) * .5 + .5);
      c = mix(vec3(1), c, v);
      
      gl_FragColor = vec4(c, 1.0);
    }
  `;

#6

I forgot before:

There http://glslsandbox.com/ are many interesting examples.:smiley:


#7

@prisoner849 Thank you your awesome example!

vec3 c = v * vec3(0., 1., 1.) * (sin(time * 5. - pos.z * .25) * .5 + .5);

I know vec3(0., 1., 1.) control the highlight color,
time * 5 control the wave speed,
pos.z * .25 is the wave z axis width.

Is it possible has a lot of mesh tile with z axis and only show one wave at a time and keep a small wave z axis width.
https://jsfiddle.net/4ckvcd2t/

Math is my weak point, so I not sure I can learn to use shader.
Thanks other guy, I want to mention your name but I can’t, sorry!


#8

Don’t really understand
https://jsfiddle.net/realhunts/4ckvcd2t/1/


#9

I’m just curious, what’s the point to have many tiling planes instead of a big one?

PlaneWave

jsfiddle example

You can change the main() function of the fragment shader like so:

void main() {
  float v = line(1., vec3(5.)) + line(1.5, vec3(100.));
  
  float s = 500.; // step
  float mp = mod(pos.z - time * 100., s);
  float smooth = smoothstep(0., 5., mp) * (1. - smoothstep(s - 20.,s,mp));
  
  vec3 c = v * vec3(0., 1., 1.) * (1. - smooth);
  c = mix(vec3(1), c, v);
  
  gl_FragColor = vec4(c, 1.0);
}

I’m not sure, though, how correct such an approach is, as it was made from a scratch. :slight_smile:


#10

image
Two-dimensional schematic

The game is about the player move forward, so that is the ground chunk, may be one chunk has a random gear(like a laser or box let the player to slide shovel or jump) and I can reuse the ground chunk.
So the highlight wave of the chunk must can one by one light up, when get in the boss ground chunk, the highlight color may be change to red and speed up, I think this is very nice for the game atmosphere.


#11

example
So based on my idea for multi chunks and just can display one wave at a time for all chunks
I tried to change the step variable, for example like chunk1 step is 500, chunk2 step is 500*2 an so on, but failed.
Maybe the better way is by using the setInterval function of javascript to one by one light up the chunk?
But how to calculate the highlight lifetime of one chunk?


#12

You can add the position of a chunk in the vertex shader, call it, for example, basePos :slight_smile:

A very rough and simple jsfiddle example.

uniform float time;
uniform vec3 basePos;
varying vec3 pos;
void main()	{
  pos = position + basePos;
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}

#13

When used with box geometry had a problem, the vertical mesh will lost the grid line of x axis

https://jsfiddle.net/806vun3k/1/

I fixed it
https://jsfiddle.net/806vun3k/2/


#14

Yep, well done! :slight_smile:


#15

Use it with the 6 side tube had a problem, the grid line not divided equally each mesh.

My knowledge not enough to fix this problem :joy::joy::joy:

And how to setup the base color for grid line(default is black) ?

https://jsfiddle.net/yfh2e0qa/2/


#16

As an option, try to use uv coordinates of vertices in THREE.TubeBufferGeometry().


#17

I try

//vertexShader
//pos = vec3(uv, 0.);
//pos = vec3(uv, 1.);
//pos = vec3(uv, position.z);

all failed :joy:


#18

Do you know that you will owe me six pack :beer:, if you won’t start to think yourself? :smile:

https://jsfiddle.net/prisoner849/hg90shov/

You should pass uv to the fragment shader:

  var vertexShader = `
    uniform float time;
    uniform vec3 basePos;
    varying vec3 vPos;
    varying vec2 vUv;
    void main()	{
      vPos = position + basePos;
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
    }
  `;
  var fragmentShader = `
  
    #extension GL_OES_standard_derivatives : enable

    varying vec3 vPos;
    varying vec2 vUv;
    uniform float time;
    uniform vec3 color;
    
    float line(float width, vec2 step){
      
      vec2 coord = vUv / step;

      vec2 grid = abs(fract(coord - 0.5) - 0.5) / fwidth(coord * width);
      float line = min(grid.x, grid.y);
      
      return 1. - min(line, 1.0);
    }
    
    void main() {
      float v = line(1., vec2(1. / 30., 0.1));
      
      float s = 500.; // step
      float mp = mod(vPos.z - time * 100., s);
      float smooth = 1. - smoothstep(0., 5., mp) * (1. - smoothstep(s - 20.,s,mp));
      
      vec3 c = v * vec3(0., 1., 1.) * smooth;
      c = mix(color, c, v);
      
      gl_FragColor = vec4(c, 1.0);
    }
  `;

Just for reference, I’ve put it on Shadertoy: https://www.shadertoy.com/view/MlsBRX


#19

You can set the base colour of grid lines like this:

vec3 c = mix(vec3(0.125, 0., .125), vec3(0., 1., 1.), smooth); // mixing base colour of lines and colour of wave

instead of

vec3 c = v * vec3(0., 1., 1.) * smooth;

#20

Hello Paul. Please give me your mail, I want to talk to you about the project.