orangeduck / Corange

Pure C Game Engine
http://www.youtube.com/watch?v=482GxqTWXtA
Other
1.82k stars 199 forks source link

Parallax mapping problem (maybe offtop) #28

Closed blogdron closed 5 years ago

blogdron commented 5 years ago

Hi Daniel, can you help me? I do not understand if the problem is related to the engine or the fact that I am an idiot)) I try to make a parallax map, but I have a lot of distortions, if I do the calculations in the vertex shader, and if I do them in fragmentary shaders, then everything is correct only displayed on two sides of the cube. I added a video where everything is visible and the shader code

I have been suffering for a week, I do not understand how to fix it Maybe this is a feature of the data in the engine and I just do not notice?

Click in image to video video parallax broken

I create repo https://github.com/fedor-elizarov/parallax_data there is a collected work program (linux only)

vertex shader in assets_core/shaders/deffered/static.vs

#version 120

attribute vec3 vPosition;
attribute vec2 vTexcoord;
attribute vec3 vNormal;
attribute vec3 vTangent;
attribute vec3 vBinormal;

uniform vec3 camera_position;
uniform mat4 world;
uniform mat4 view;
uniform mat4 proj;

varying vec2 fTexcoord;
varying vec3 fColor;
varying vec3 fPosition;
varying mat4 fTBN;

varying vec3 fTanViewPos;
varying vec3 fTanFragPos;

void main( void ) {

  vec3 w_tangent  = mat3(world) * vTangent;
  vec3 w_binormal = mat3(world) * vBinormal;
  vec3 w_normal   = mat3(world) * vNormal;

  fTBN = mat4(
    w_tangent.x, w_binormal.x, w_normal.x, 0.0,
    w_tangent.y, w_binormal.y, w_normal.y, 0.0,
    w_tangent.z, w_binormal.z, w_normal.z, 0.0,
    0.0, 0.0, 0.0, 1.0 );

  vec4 world_position = world * vec4(vPosition, 1);

  fColor = vec3(1.0, 1.0, 1.0);

  fTexcoord = vTexcoord;
  fPosition = world_position.xyz / world_position.w;

  mat3 TBN= transpose(mat3(normalize (w_tangent),
                           normalize (w_binormal),
                           normalize (w_normal)));
  fTanFragPos = TBN * fPosition;
  fTanViewPos = TBN * camera_position;
  fTanViewPos = normalize(fTanViewPos - fTanFragPos);
  fTanViewPos.y = -fTanViewPos.y;

   gl_Position = proj * view * world_position;

} 

fragment shader in assets_core/shaders/deffered/static.fs

#version 120

uniform sampler2D diffuse_map;
uniform sampler2D normal_map;
uniform sampler2D specular_map;
uniform sampler2D parallax_map;

uniform vec3  camera_position;
uniform float glossiness_level;
uniform float bumpiness_level;
uniform float specular_level;
uniform float parallax_level;
uniform float alpha_test;
uniform int   material;

uniform float clip_near;
uniform float clip_far;

varying vec2 fTexcoord;
varying vec3 fColor;
varying vec3 fPosition;
varying mat4 fTBN;

varying vec3 fTanViewPos;
varying vec3 fTanFragPos;

vec3 to_gamma(vec3 color) {
  vec3 ret;
  ret.r = pow(color.r, 2.2);
  ret.g = pow(color.g, 2.2);
  ret.b = pow(color.b, 2.2);
    return ret;
}

vec3 from_gamma(vec3 color) {
  vec3 ret;
  ret.r = pow(color.r, 1.0/2.2);
  ret.g = pow(color.g, 1.0/2.2);
  ret.b = pow(color.b, 1.0/2.2);
    return ret;
}

vec3 swap_red_green_inv(vec3 color) {
  float temp = 1.0-color.r;
  color.r = 1.0-color.g;
  color.g = temp;
  return color;
}

float linear_depth(float depth, float near, float far){
  return (2.0 * near) / (far + near - depth * (far - near));
}

vec2 parallax_uv(vec2 uv, vec3 view_dir)
{

  float num_layers = 22;
  float layer_depth = 1.0 / num_layers;
  float cur_layer_depth = 0.0;
  vec2 delta_uv = view_dir.xy  * parallax_level / num_layers;
  vec2 cur_uv = uv;
  float depth_from_tex = texture2D(parallax_map, cur_uv).r;
  for (int i = 0; i < num_layers; i++) {
      cur_layer_depth += layer_depth;
      cur_uv -= delta_uv;
      depth_from_tex = texture2D(parallax_map, cur_uv).r;
      if (depth_from_tex < cur_layer_depth){
          break;
      }
  }
  /*
   //Step Parallax mapping
  return cur_uv;
  */

  // Parallax occlusion mapping
  vec2 prev_uv = cur_uv + delta_uv;
  float next = depth_from_tex - cur_layer_depth;
  float prev = texture2D(parallax_map, prev_uv).r - cur_layer_depth
               + layer_depth;
  float weight = next / (next - prev);
  return mix(cur_uv, prev_uv, weight);

  /*
  //Simple Parallax mapping
  float dep = texture2D(parallax_map,uv).z;
  vec2  uvn = view_dir.xy * (dep * parallax_level);
  return uv - uvn ;
  */
}

   void main( void ) {

    vec2 uvs = vec2(fTexcoord.x, -fTexcoord.y);
    if(parallax_level != 0.0)
    {
          mat3 TBN=transpose(mat3(normalize(fTBN[0]),
                                  normalize(fTBN[1]),
                                  normalize(fTBN[2])));
          vec3 position  = normalize(camera_position - fPosition);
          vec3 ViewPos   = TBN * position;
               ViewPos.y = -ViewPos.y;

          /*calculate from fragment shader*/
           //Variant 1 
            uvs=parallax_uv(uvs, ViewPos);         // correct 2 plane in box

          /*calculate from vertex shader*/
          //Variant 2 
          // uvs = parallax_uv(uvs,fTanViewPos); // all planes in box is broken

        if(uvs.x > 1.0 || uvs.y > 1.0 || uvs.x < 0.0 || uvs.y < 0.0)
        {
            // discard;
        };
    };
    vec4 diffuse = texture2D(diffuse_map, uvs);
    float spec = texture2D(specular_map, uvs).r * specular_level;
    vec4 normal = texture2D(normal_map, uvs);

    if (diffuse.a < alpha_test) { discard; }

    normal.rgb = swap_red_green_inv(normal.rgb);
    normal = mix(normal, vec4( 0.5, 0.5, 1.0, 1.0 ), bumpiness_level);
    normal = (normal * 2.0 - vec4(1.0,1.0,1.0,0.0)) * fTBN;

    gl_FragData[0].rgb = from_gamma(diffuse.rgb) * fColor;
    gl_FragData[0].a = spec;

    gl_FragData[1].rgb = normal.rgb;
    gl_FragData[1].a = float(material) + glossiness_level / 1000;

    gl_FragDepth = linear_depth(gl_FragCoord.z, clip_near, clip_far);

}

diff input data in shader in render.c (render_static())

+ shader_program_set_vec3(shader,  "camera_position",dr->camera->position);
+ shader_program_set_float(shader,   "parallax_level", material_entry_item(me, "parallax_level").as_float);
+ shader_program_set_texture(shader, "parallax_map", 3, material_entry_item(me, "parallax_map").as_asset);
blogdron commented 5 years ago

worked parallax -> https://github.com/fedor-elizarov/parallax_data/tree/master/version2 need calculate Tangent camera_position and Tangent fPosition in vertex shader and after replace camera x to y and y to x and inverse y to -y https://youtu.be/FUYzaYnRJWY . Im close issue