【问题标题】:Shader testgrid - lines jagged and breaking着色器测试网格 - 线条锯齿状和断裂
【发布时间】:2020-04-12 15:39:09
【问题描述】:

我需要为 testgrid 地表编写一个简单的着色器。我想基本上在着色器代码中绘制平行线。

问题:随着线条与相机的距离越来越远,它们开始断裂,并且出现间隙。我理解为什么我的代码会发生这种情况 - 因为 OpenGL 将片段的位置近似为离我计算的点太远,所以它将它标记为不属于一条线。

我将平面表面矢量的实际世界位置传递给我的着色器 - 这就是我可以计算它的方法。

我已经玩了一个小时的算法,但似乎无法获得好的结果。

我尝试过的最佳想法是包含一个小系数,该系数随着线条离相机越远而增长 - 但结果并不令人印象深刻。我线性地计算了系数,但我想我需要一些更聪明的公式才能走这条路,因为屏幕上线条变细的速度不是线性的。到目前为止,我无法弄清楚这一点。目前,它要么使近距离的线条太粗,这是不受欢迎的,要么对于远距离的线条仍然存在同样的问题。

为了简化,我目前只画 X 轴线

我包含一段着色器代码和问题的屏幕截图。

#version 300 es

precision highp float;
precision highp int;

in highp vec3 vertexPosition;

out mediump vec4 fragColor;

void main()
{
    highp float lineWidth = 0.2;
    highp float squareSize = 5.0f;

    highp int roundX = int(vertexPosition.x / squareSize);
    highp int roundY = int(vertexPosition.z / squareSize);
    highp float remainderX = vertexPosition.x - float(roundX)*squareSize;
    highp float remainderY = vertexPosition.x - float(roundY)*squareSize;

    // this is the small coefficient I was trying to add to linewidth
    highp float test = abs(0.08 * float(roundX));

    if (abs(remainderX) <= (lineWidth))
    {
        fragColor = vec4(1,0,0, 1);
    }
    else
    {
        fragColor = vec4(0.8,0.8,0.8, 1);
    }
}

第一个答案解决了换行的主要问题,但引入了一个视觉错误。要去尝试找出原因。不管怎样,这已经是个好主意了!但正如你所看到的,线条越靠近末端越宽。

编辑:找到了。在执行dFdy 之前,刚刚从vertexPosition 中删除了Z 坐标。现在我只需要一种使线条更平滑而不像楼梯的方法。

附言不要看代码的优化程度——我目前只是在寻找正确的想法 pps如果有人能告诉我如何为这个例子做简单的抗锯齿 - 这也是最受欢迎的。

【问题讨论】:

    标签: java opengl-es glsl fragment-shader


    【解决方案1】:

    重要的是 roundX 被四舍五入 (round) 到最接近的整数,而不是截断:

    highp int roundX = int(round(vertexPosition.x / squareSize));
    

    highp int roundX = int(vertexPosition.x / squareSize + 0.5 * sign(vertexPosition.x));
    

    一种可能的解决方案是通过dFdy 沿视口的y 轴获得vertexPosition.xy 的偏导数。
    vertexPosition.xy 的偏导数的长度给出了模型空间中 2 个片段之间的距离。因此可以定义线的最小粗细:

    vec2 dy = dFdy(vertexPosition.xy);
    float minWidth = length(dy);
    
    float w = step(max(lineWidth, minWidth), abs(remainderX));
    fragColor = mix(vec4(1.0, 0.0, 0.0, 1.0), vec4(0.8, 0.8, 0.8, 1.0), w);
    

    对于更平滑的线条,您必须插入线条颜色和底色。如果abs(remainderX) 介于min(lineWidth, minWidth)max(lineWidth, minWidth) 之间,则进行插值。使用smoothstep 进行插值。例如:

    highp int roundX = int(round(vertexPosition.x / squareSize));
    highp float remainderX = vertexPosition.x - float(roundX)*squareSize;
    
    vec2 dy = dFdy(vertexPosition.xy);
    float minWidth = length(dy);
    
    float w = smoothstep(min(lineWidth, minWidth), max(lineWidth, minWidth), abs(remainderX));
    fragColor = mix(vec4(1.0, 0.0, 0.0, 1.0), vec4(0.8, 0.8, 0.8, 1.0), w);
    

    参见 Three.js 示例,它使用了着色器:

    (function onLoad() {
      var camera, scene, renderer, orbitControls;
      
      init();
      animate();
    
      function init() {
        
        renderer = new THREE.WebGLRenderer({
          antialias: true,
          alpha: true
        });
    
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMap.enabled = true;
        document.body.appendChild(renderer.domElement);
    
        camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 300);
        camera.position.set(10, 15, -60);
    
        loader = new THREE.TextureLoader();
        loader.setCrossOrigin("");
    
        scene = new THREE.Scene();
        scene.background = new THREE.Color(0xffffff);
        scene.add(camera);
        window.onresize = resize;
        
        orbitControls = new THREE.OrbitControls(camera, renderer.domElement);
        
        var helper = new THREE.GridHelper(400, 10);
        helper.material.opacity = 0.25;
        helper.material.transparent = true;
        scene.add(helper);
    
        var axis = new THREE.AxesHelper(1000);
        scene.add(axis);
        
        var material = new THREE.ShaderMaterial({  
              vertexShader: document.getElementById('vertex-shader').textContent,
              fragmentShader: document.getElementById('fragment-shader').textContent,
        });
        material.extensions = {
          derivatives: true
        }
    
        var geometry = new THREE.BoxGeometry( 100, 0.1, 100 );
        var mesh = new THREE.Mesh(geometry, material);
        scene.add(mesh);
      }
    
      function resize() { 
        var aspect = window.innerWidth / window.innerHeight;
        renderer.setSize(window.innerWidth, window.innerHeight);
        camera.aspect = aspect;
        camera.updateProjectionMatrix();
      }
    
      function animate() {
        requestAnimationFrame(animate);
        orbitControls.update();
        render();
      }
    
      function render() {
        renderer.render(scene, camera);
      }
    })();
    <script type='x-shader/x-vertex' id='vertex-shader'>
    varying vec3 vertexPosition;
    void main() {
        vertexPosition = position.zyx;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
    </script>
    
    <script type='x-shader/x-fragment' id='fragment-shader'>
    precision highp float;
    
    varying vec3 vertexPosition;
    
    int round(float x)
    {
      return int(x + 0.5 * sign(x));
    }
    
    void main(){
        vec4 fragColor;
    
        highp float lineWidth = 0.2;
        highp float squareSize = 5.0;
    
        highp int roundX = round(vertexPosition.x / squareSize);
        highp float remainderX = vertexPosition.x - float(roundX)*squareSize;
        
        vec2 dy = dFdy(vertexPosition.xy);
        float minWidth = length(dy);
    
        float w = smoothstep(min(lineWidth, minWidth), max(lineWidth, minWidth), abs(remainderX));
        //float w = step(max(lineWidth, minWidth), abs(remainderX));
        fragColor = mix(vec4(1.0, 0.0, 0.0, 1.0), vec4(0.8, 0.8, 0.8, 1.0), w);
    
        gl_FragColor = fragColor;
    }
    </script>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js"></script>
    <script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

    【讨论】:

    • 谢谢!答案似乎可以完成这项工作,但它也引入了一个视觉错误。截图见帖子更新。
    • 编辑:找到了。在执行 dFdy 之前,刚刚从 vertexPosition 中删除了 Z 坐标。现在我只需要一种让线条更平滑而不像楼梯的方法。
    猜你喜欢
    • 2019-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-01
    • 1970-01-01
    • 2016-10-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多