2015-12-30 73 views
5

我已經設置了這個最小的測試用例,您可以很容易地看到使用自定義片段着色器(jsfiddle)對欠振動紅色進行欠採樣所產生的莫阿條紋。刪除由GLSL着色器產生的莫爾條紋

什麼是使用GLSL消除這種模式的一般技術?我認爲它涉及衍生產品擴展,但我從來沒有完全理解如何實現它。基本上我必須做反走樣,我想呢?

var canvas = document.getElementById('canvas'); 
 
var scene = new THREE.Scene(); 
 
var renderer = new THREE.WebGLRenderer({canvas: canvas, antialias: true}); 
 
var camera = new THREE.PerspectiveCamera(75, canvas.clientWidth/canvas.clientWidth, 1, 1000); 
 

 
var geometry = new THREE.SphereGeometry(50, 50, 50); 
 
var material = new THREE.ShaderMaterial({ 
 
    vertexShader: document.getElementById('vertex-shader').textContent, 
 
    fragmentShader: document.getElementById('fragment-shader').textContent 
 
}); 
 
var sphere = new THREE.Mesh(geometry, material); 
 

 
scene.add(sphere); 
 

 
camera.position.z = 100; 
 

 
var period = 30; 
 
var clock = new THREE.Clock(); 
 
render(); 
 

 
function render() { 
 
    requestAnimationFrame(render); 
 
    
 
    if (canvas.width !== canvas.clientWidth || canvas.height !== canvas.clientHeight) { 
 
    renderer.setSize(canvas.clientWidth, canvas.clientHeight, false); 
 
    camera.aspect = canvas.clientWidth/canvas.clientHeight; 
 
    camera.updateProjectionMatrix(); 
 
    } 
 
    
 
    sphere.rotation.y -= clock.getDelta() * 2 * Math.PI/period; 
 
    renderer.render(scene, camera); 
 
}
html, body, #canvas { 
 
    margin: 0; 
 
    padding: 0; 
 
    width: 100%; 
 
    height: 100%; 
 
    overflow: hidden; 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r73/three.min.js"></script> 
 
<canvas id="canvas"></canvas> 
 
<script id="vertex-shader" type="x-shader/x-vertex"> 
 
    varying vec2 vUv; 
 

 
    void main() { 
 
    vUv = uv; 
 
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 
 
    } 
 
</script> 
 
<script id="fragment-shader" type="x-shader/x-fragment"> 
 
    #define M_TAU 6.2831853071795864769252867665590 
 

 
    varying vec2 vUv; 
 

 
    void main() { 
 
    float w = sin(500.0 * M_TAU * vUv.x)/2.0 + 0.5; 
 
    vec3 color = vec3(w, 0.0, 0.0); 
 
    gl_FragColor = vec4(color, 1.0); 
 
    } 
 
</script>

更新:我試圖執行super-sampling,不知道我是否已經正確地實現它,但它似乎並沒有幫助太多。

+0

@WacławJasper使用UV座標只是一個簡單的方法來獲得這種效果。接縫本身不會產生問題,否則你只會看到接縫本身的問題。 –

回答

6

不幸的是,這裏的莫阿條紋是高對比度線接近Nyquist Frequency的結果。換句話說,沒有好的辦法讓1或2像素寬的高對比度線平滑地轉移到下一個像素,而不會引入這些僞影,或者使線條模糊不清。

你提到了衍生物擴展,事實上這個擴展可以用來確定你的UV在屏幕空間中的變化有多快,因此,弄清楚需要多少模糊才能在地毯下掃描這個問題。在下面你自己的例子的修改版本中,我試圖使用fwidth將球體變成紅色,噪聲變壞。嘗試玩一些在這裏定義爲常數的浮點數,看看你能找到什麼。

var canvas = document.getElementById('canvas'); 
 
var scene = new THREE.Scene(); 
 
var renderer = new THREE.WebGLRenderer({canvas: canvas, antialias: true}); 
 
var camera = new THREE.PerspectiveCamera(75, canvas.clientWidth/canvas.clientWidth, 1, 1000); 
 

 
var geometry = new THREE.SphereGeometry(50, 50, 50); 
 
var material = new THREE.ShaderMaterial({ 
 
    vertexShader: document.getElementById('vertex-shader').textContent, 
 
    fragmentShader: document.getElementById('fragment-shader').textContent 
 
}); 
 
var sphere = new THREE.Mesh(geometry, material); 
 

 
scene.add(sphere); 
 

 
camera.position.z = 100; 
 

 
var period = 30; 
 
var clock = new THREE.Clock(); 
 
render(); 
 

 
function render() { 
 
    requestAnimationFrame(render); 
 
    
 
    if (canvas.width !== canvas.clientWidth || canvas.height !== canvas.clientHeight) { 
 
    renderer.setSize(canvas.clientWidth, canvas.clientHeight, false); 
 
    camera.aspect = canvas.clientWidth/canvas.clientHeight; 
 
    camera.updateProjectionMatrix(); 
 
    } 
 
    
 
    sphere.rotation.y -= clock.getDelta() * 2 * Math.PI/period; 
 
    renderer.render(scene, camera); 
 
}
html, body, #canvas { 
 
    margin: 0; 
 
    padding: 0; 
 
    width: 100%; 
 
    height: 100%; 
 
    overflow: hidden; 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r73/three.min.js"></script> 
 
<canvas id="canvas"></canvas> 
 
<script id="vertex-shader" type="x-shader/x-vertex"> 
 
    varying vec2 vUv; 
 

 
    void main() { 
 
    vUv = uv; 
 
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 
 
    } 
 
</script> 
 
<script id="fragment-shader" type="x-shader/x-fragment"> 
 
    #extension GL_OES_standard_derivatives : enable 
 

 
    #define M_TAU 6.2831853071795864769252867665590 
 

 
    varying vec2 vUv; 
 

 
    void main() { 
 
    float linecount = 200.0; 
 
    float thickness = 0.0; 
 
    float blendregion = 2.8; 
 
    
 
    // Loosely based on https://github.com/AnalyticalGraphicsInc/cesium/blob/1.16/Source/Shaders/Materials/GridMaterial.glsl#L17-L34 
 
    float scaledWidth = fract(linecount * vUv.s); 
 
    scaledWidth = abs(scaledWidth - floor(scaledWidth + 0.5)); 
 
    vec2 dF = fwidth(vUv) * linecount; 
 
    float value = 1.0 - smoothstep(dF.s * thickness, dF.s * (thickness + blendregion), scaledWidth); 
 
    gl_FragColor = vec4(value, 0.0, 0.0, 1.0); 
 
    } 
 
</script>

+0

感謝您的回答!我能要求的唯一可能是關於這種類型的東西的各種技術的進一步信息或文檔?他們都基本上只是模糊高頻的東西? –

+1

據我所知這是唯一的解決方案:基於像素的顯示器根本無法顯示高於像素密度的頻率。在上面的代碼中,由於'fwidth',在屏幕空間像素中指定'thickness'和'blendregion',這意味着線條開始重疊,因爲它們的間距小於3像素。小於這一點,你只有1個像素的線和1個像素的間隙,並且當線條不粘在像素網格上時,事情會變得雜亂無章。 – emackey

+1

順便說一下,這個代碼的基礎邏輯在Cozzi和Ring的書「虛擬地球的三維引擎設計」一書中有更詳細的描述,代碼清單4.13。 – emackey