【问题标题】:Lost fragments in my shader我的着色器中丢失的片段
【发布时间】:2016-08-12 22:31:31
【问题描述】:

我正在尝试在 Threejs 中创建一个瓦片系统:绿色为地面/蓝色为水。

我在 PlaneBufferGeometry 上使用着色器。

这是我目前所拥有的:

相关代码:

  • JS:变量chunk和函数DoPlaneStuff()(都是开头)
  • HTML:顶点和片段着色器

var chunk = {
  // number of width and height segments for PlaneBuffer
  segments: 32,
  // Heightmap: 0 = water, 1 = ground
  heightmap: [
    [1, 0, 0],
    [1, 1, 0],
    [1, 0, 1],
  ],
  // size of the plane
  size: 40
};

function DoPlaneStuff() {
  var uniforms = {
    heightmap: {
      type: "iv1",
      // transform the 2d Array to a simple array
      value: chunk.heightmap.reduce((p, c) => p.concat(c), [])
    },
    hmsize: {
      type: "f",
      value: chunk.heightmap[0].length
    },
    coord: {
      type: "v2",
      value: new THREE.Vector2(-chunk.size / 2, -chunk.size / 2)
    },
    size: {
      type: "f",
      value: chunk.size
    }
  };
  console.info("UNIFORMS GIVEN :", uniforms);
  var shaderMaterial = new THREE.ShaderMaterial({
    uniforms: uniforms,
    vertexShader: document.getElementById("v_shader").textContent,
    fragmentShader: document.getElementById("f_shader").textContent
  });
  var plane = new THREE.Mesh(
    new THREE.PlaneBufferGeometry(chunk.size, chunk.size, chunk.segments, chunk.segments),
    shaderMaterial
  );
  plane.rotation.x = -Math.PI / 2;
  scene.add(plane);
}


// --------------------- END OF RELEVANT CODE


window.addEventListener("load", Init);

function Init() {
  Init3dSpace();
  DoPlaneStuff();
  Render();
}

var camera_config = {
  dist: 50,
  angle: (5 / 8) * (Math.PI / 2)
}
var scene, renderer, camera;
function Init3dSpace() {
  scene = new THREE.Scene();
  renderer = new THREE.WebGLRenderer({
    antialias: true,
    logarithmicDepthBuffer: true
  });
  camera = new THREE.PerspectiveCamera(
    50,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );
  this.camera.position.y = camera_config.dist * Math.sin(camera_config.angle);
  this.camera.position.x = 0;
  this.camera.position.z = 0 + camera_config.dist * Math.cos(camera_config.angle);
  this.camera.rotation.x = -camera_config.angle;
  var light = new THREE.HemisphereLight(0xffffff, 10);
  light.position.set(0, 50, 0);
  scene.add(light);
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);
}

function Render() {
  renderer.render(scene, camera);
}
body {
  overflow: hidden;
  margin: 0;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/three.js/r70/three.min.js"></script>
<!-- VERTEX SHADER -->
<script id="v_shader" type="x-shader/x-vertex">
  // size of the plane 
  uniform float size; 
  // coordinates of the geometry 
  uniform vec2 coord; 
  // heightmap size (=width and height of the heightmap)
  uniform float hmsize; 
  uniform int heightmap[9]; 
  varying float colorValue; 
  
  void main() { 
    int xIndex = int(floor( 
      (position.x - coord.x) / (size / hmsize)
    ));
    int yIndex = int(floor(
      (-1.0 * position.y - coord.y) / (size / hmsize)
    ));
    // Get the index of the corresponding tile in the array
    int index = xIndex + int(hmsize) * yIndex;
    // get the value of the tile
    colorValue = float(heightmap[index]);
  
    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
  }
</script>
<!-- FRAGMENT SHADER -->
<script id="f_shader" type="x-shader/x-fragment">
  varying float colorValue; 
  
  void main() {
    // default color is something is not expected: RED
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    // IF WATER
    if (colorValue == 0.0) { 
      // BLUE
      gl_FragColor = vec4( 0.0, 0.0, 1.0, 1.0 );
    }
    // IF GROUND
    if (colorValue == 1.0) {
      // GREEN 
      gl_FragColor = vec4( 0.1, 0.6, 0.0, 1.0 );
    }
  }
</script>

正如您所见,它几乎可以工作了,但我有这些红线将绿色和蓝色区域分开,我不知道为什么。 我将这些红色碎片称为“丢失的碎片”,因为它们没有映射到任何图块,我不明白为什么。

我只能注意到chunk.segments 的值越大(这是几何体的高度和宽度段的数量),我的红线就越细。

我想知道如何在绿色和蓝色区域而不是红色区域之间进行渐变填充。

【问题讨论】:

    标签: three.js shader fragment-shader


    【解决方案1】:

    红线由三角形组成,其中一些顶点位于地砖中,而其他顶点位于水砖中。然后,GPU 沿三角形对colorValue 进行插值,产生从 0 到 1 的平滑渐变,而不是您可能期望的急剧变化。

    对此有多种解决方案。您可以更改着色器中的条件以根据中点选择颜色:如果colorValue flat 插值限定符添加到colorValue,但更难控制三角形最终使用的顶点属性。

    ...我刚刚注意到您确实需要渐变而不是陡峭的台阶。这更容易。您需要将颜色选择代码从片段着色器移动到顶点着色器,然后在片段着色器中返回生成的插值颜色。

    【讨论】:

    • 感谢您的回答。 “GPU然后沿三角形插入colorValue”这就是为什么我不能有一个可变的int!但是,我不确定你的“更好的解决方案”是什么意思,你有一些资源让我看看吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-21
    • 1970-01-01
    • 2019-01-24
    • 2014-08-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多