我需要为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);
}
}
ps.s。不要看代码的优化程度-我目前只是在寻找正确的主意p.p.s.如果有人可以告诉我该示例如何进行简单的抗锯齿-这也将是非常受欢迎的。
一种可能的解决方案是通过视口的y轴将vertexPosition
的偏导数乘以dFdy
。dFdy
的偏导数的长度给出了模型空间中2个片段之间的距离。因此,可以定义一条线的最小厚度:
vertexPosition
请参见Three.js示例,该示例使用着色器:
vec3 dy = dFdy(vertexPosition);
float minWidth = length(dy);
if (abs(remainderX) <= max(lineWidth, minWidth))
{
fragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
else
{
fragColor = vec4(0.8, 0.8, 0.8, 1.0);
}
(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);
}
})();