简体   繁体   English

提高Threejs /着色器几何图形的UV线质量

[英]Improve UV line quality of threejs/shader geometry

I'm using the uv output of threejs's torus to create moving lines across the torus. 我正在使用threejs圆环的uv输出在圆环上创建移动线。 It works, but doesn't look crisp. 它有效,但看起来不清晰。

How can I improve the line quality? 如何改善线路质量? I've tried making the material two-sided, and increasing the width of the lines, but the quality isn't improving much. 我尝试将材料制作为双面,并增加线的宽度,但是质量并没有太大改善。

I haven't tried completely reproducing the torus outside of threejs, but that's out of my comfort zone. 我还没有尝试在Threejs之外完全复制圆环,但这超出了我的舒适范围。

I'm hoping there's way to change the logic of the fragment shader to produce clearer lines. 我希望有办法改变片段着色器的逻辑以产生更清晰的线条。 I'd be greatful for any suggestions. 有任何建议,我将不胜感激。

Codepen Codepen

/* Scene Initialization */
var startTime = Date.now();
var scene = new THREE.Scene();
var width = window.innerWidth;
var height = window.innerHeight;
var canvas = document.getElementById('canvas');
var camera = new THREE.PerspectiveCamera(75, 1, 1, 1200);
// var camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, 1, 1200 );

camera.position.set(0, -420, 600);
camera.lookAt(new THREE.Vector3(0, 0, 0));

var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth * .2, window.innerWidth * .2);
renderer.setClearColor( 0xffffff, 1);
canvas.appendChild(renderer.domElement);

var geometry = new THREE.TorusGeometry(200, 200, 260, 260); 
material = new THREE.ShaderMaterial( {
        uniforms: {time: { type: "f", value: Date.now() - startTime}, },
        vertexShader: `attribute vec3 center;
            varying vec3 vCenter;
      varying vec2 vUv;
            void main() {
                vCenter = center;
        vUv = uv;
                gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
            }`,
        fragmentShader: `varying vec3 vCenter;
      varying vec2 vUv;
      uniform float time;
      uniform sampler2D tDiffuse;
            void main() {
        float sh = 0.005;
        float PI = 3.1415926535897932384626433832795;
        // float linesX = mod(time + vUv.x, 0.03);
        float linesX = sin((time + vUv.x) * PI * 30.)/30.;
        // float linesY = mod(time + vUv.y, 0.05);
        float linesY = sin((time + vUv.y) * PI * 20.)/20.;
        float smoothX =
        smoothstep( 0.0 - sh, 0.0, linesX) -
          smoothstep( 0.0, 0.0 + sh, linesX);
        float smoothY =
        smoothstep( 0.0 - sh, 0.0, linesY) -
          smoothstep( 0.0, 0.0 + sh, linesY);

        float uvOutput = smoothX + smoothY;
        gl_FragColor.rgb = vec3(1.0, 0, 0);
        gl_FragColor.a = uvOutput;
        // gl_FragColor = vec4(1.,0,0,1.)

            }`
      } );
//material.extensions.derivatives = true;

material.side = THREE.DoubleSide;

material.transparent = true;

//material.blending = THREE.Add;
material.depthTest = false;

var torus = new THREE.Mesh(geometry, material);
var geom = torus.geometry;
geometry.sortFacesByMaterialIndex();
torus.position.x = 0;

scene.add(torus);

/* Request Animation Frame */
function animation() {
  camera.lookAt(new THREE.Vector3(0, 0, 0));
  renderer.render(scene, camera);
  material.uniforms.time.value = (Date.now() - startTime)/20000;
  requestAnimationFrame(animation);
}

animation();
setupDraggableEvents();

function setupDraggableEvents() {
  var hammer = new Hammer(document.getElementsByTagName('canvas')[0]);
  hammer.on('pan', function(event) {
    torus.rotation.y += event.velocityX / 10;
    torus.rotation.x += event.velocityY / 10;
  });
}

I recommend to define the number of lines for both directions and to calculate the distance to a line in terms of UV coordinates: 我建议定义两个方向的线数,并根据UV坐标计算到线的距离:

float t = time;

vec2 noLines = vec2(30.0, 20.0);
vec2 floorUV = floor((t + vUv) * noLines);
vec2 distUV  = t + vUv - (floorUV+0.5) / noLines;

Smoothly interpolate between the thickness and the half thickness of a line ( smoothstep ), to calculate the "saturation". 在线条的粗细和一半粗细之间平滑地插值(“ smoothstep ),以计算“饱和度”。 This causes that the line always has the full "strength" in the middle (of course you can experiment with this eg sh*0.66 , sh*0.33 ): 这导致该行始终在中间始终具有完整的“强度”(当然,您可以尝试使用此sh*0.66 ,例如sh*0.66sh*0.33 ):

float sh = 0.005;
vec2 lineUV = smoothstep(sh, sh*0.5, abs(distUV));

The alpha channel is the maximum "saturation" value of both directions: alpha通道是两个方向的最大“饱和​​度”值:

float uvOutput = max(lineUV.x, lineUV.y);
gl_FragColor = vec4(1.0, 0.0, 0.0, uvOutput);

See the example, where I applied the suggested changes to your original code: 请参见示例,其中我将建议的更改应用于原始代码:

 /* Scene Initialization */ var startTime = Date.now(); var scene = new THREE.Scene(); var width = window.innerWidth; var height = window.innerHeight; var canvas = document.getElementById('canvas'); var camera = new THREE.PerspectiveCamera(75, 1, 1, 1200); camera.position.set(0, -420, 600); camera.lookAt(new THREE.Vector3(0, 0, 0)); orbitControls = new THREE.OrbitControls(camera); var renderer = new THREE.WebGLRenderer({antialias: true}); renderer.setSize(window.innerWidth * .2, window.innerWidth * .2); renderer.setClearColor( 0xffffff, 1); canvas.appendChild(renderer.domElement); var geometry = new THREE.TorusGeometry(200, 200, 260, 260); material = new THREE.ShaderMaterial( { uniforms: {time: { type: "f", value: Date.now() - startTime}, }, vertexShader: `attribute vec3 center; varying vec3 vCenter; varying vec2 vUv; void main() { vCenter = center; vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); }`, fragmentShader: `varying vec3 vCenter; varying vec2 vUv; uniform float time; uniform sampler2D tDiffuse; void main() { float t = time; vec2 noLines = vec2(30.0, 20.0); vec2 floorUV = floor((t + vUv) * noLines); vec2 distUV = t + vUv - (floorUV+0.5) / noLines; float sh = 0.005; vec2 lineUV = smoothstep(sh, sh*0.5, abs(distUV)); float uvOutput = max(lineUV.x, lineUV.y); gl_FragColor = vec4(1.0, 0.0, 0.0, uvOutput); }`, transparent: true } ); //material.extensions.derivatives = true; material.side = THREE.DoubleSide; material.transparent = true; //material.blending = THREE.Add; material.depthTest = false; var torus = new THREE.Mesh(geometry, material); var geom = torus.geometry; geometry.sortFacesByMaterialIndex(); torus.position.x = 0; scene.add(torus); /* Request Animation Frame */ function animation() { camera.lookAt(new THREE.Vector3(0, 0, 0)); renderer.render(scene, camera); material.uniforms.time.value = (Date.now() - startTime)/20000; requestAnimationFrame(animation); } resize(); window.onresize = resize; animation(); setupDraggableEvents(); function setupDraggableEvents() { var hammer = new Hammer(document.getElementsByTagName('canvas')[0]); hammer.on('pan', function(event) { torus.rotation.y += event.velocityX / 10; torus.rotation.x += event.velocityY / 10; }); } function resize() { var aspect = window.innerWidth / window.innerHeight; renderer.setSize(window.innerWidth, window.innerHeight); camera.aspect = aspect; camera.updateProjectionMatrix(); } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/100/three.min.js"></script> <script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script> <div id="canvas"></div> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM