Улучшение качества УФ-линии геометрии триджа / шейдера - PullRequest
0 голосов
/ 03 января 2019

Я использую ультрафиолетовый выход тора Threejs, чтобы создать движущиеся линии поперек тора.Это работает, но не выглядит четким.

Как я могу улучшить качество линии?Я попытался сделать материал двусторонним и увеличить ширину линий, но качество не улучшилось.

Я не пытался полностью воспроизвести тор за пределами трех j, но это не такмоей зоны комфорта.

Я надеюсь, что есть способ изменить логику фрагментного шейдера, чтобы получить более четкие линии.Буду признателен за любые предложения.

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;
  });
}

1 Ответ

0 голосов
/ 03 января 2019

Я рекомендую определить количество линий для обоих направлений и рассчитать расстояние до линии в терминах 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;

Плавно интерполируйте между толщиной и половиной толщины линии (smoothstep), чтобы вычислить «насыщенность». Это приводит к тому, что линия всегда имеет полную «силу» в середине (конечно, вы можете поэкспериментировать с этим, например, sh*0.66, sh*0.33):

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);

См. Пример, где я применил предложенные изменения к вашему исходному коду:

/* 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>
...