Improve UV line quality of threejs/shader geometry





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







2















I'm using the uv output of threejs's torus to create moving lines across the torus. 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.



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



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









share|improve this question

























  • Adding the following line after your create your renderer will increase the effective resolution on many devices. renderer.setPixelRatio( window.devicePixelRatio );. The lines of your torus definitely looks sharper on my iMac.

    – Mugen87
    Jan 3 at 10:07


















2















I'm using the uv output of threejs's torus to create moving lines across the torus. 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.



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



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









share|improve this question

























  • Adding the following line after your create your renderer will increase the effective resolution on many devices. renderer.setPixelRatio( window.devicePixelRatio );. The lines of your torus definitely looks sharper on my iMac.

    – Mugen87
    Jan 3 at 10:07














2












2








2








I'm using the uv output of threejs's torus to create moving lines across the torus. 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.



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



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









share|improve this question
















I'm using the uv output of threejs's torus to create moving lines across the torus. 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.



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



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






javascript three.js glsl shader






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 3 at 10:11









Rabbid76

43.8k123354




43.8k123354










asked Jan 3 at 2:35









Eva PengEva Peng

132




132













  • Adding the following line after your create your renderer will increase the effective resolution on many devices. renderer.setPixelRatio( window.devicePixelRatio );. The lines of your torus definitely looks sharper on my iMac.

    – Mugen87
    Jan 3 at 10:07



















  • Adding the following line after your create your renderer will increase the effective resolution on many devices. renderer.setPixelRatio( window.devicePixelRatio );. The lines of your torus definitely looks sharper on my iMac.

    – Mugen87
    Jan 3 at 10:07

















Adding the following line after your create your renderer will increase the effective resolution on many devices. renderer.setPixelRatio( window.devicePixelRatio );. The lines of your torus definitely looks sharper on my iMac.

– Mugen87
Jan 3 at 10:07





Adding the following line after your create your renderer will increase the effective resolution on many devices. renderer.setPixelRatio( window.devicePixelRatio );. The lines of your torus definitely looks sharper on my iMac.

– Mugen87
Jan 3 at 10:07












1 Answer
1






active

oldest

votes


















0














I recommend to define the number of lines for both directions and to calculate the distance to a line in terms of UV coordinates:



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". This causes that the line always has the full "strength" in the middle (of course you can experiment with this e.g. sh*0.66, sh*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:



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>








share|improve this answer
























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54015617%2fimprove-uv-line-quality-of-threejs-shader-geometry%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    0














    I recommend to define the number of lines for both directions and to calculate the distance to a line in terms of UV coordinates:



    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". This causes that the line always has the full "strength" in the middle (of course you can experiment with this e.g. sh*0.66, sh*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:



    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>








    share|improve this answer




























      0














      I recommend to define the number of lines for both directions and to calculate the distance to a line in terms of UV coordinates:



      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". This causes that the line always has the full "strength" in the middle (of course you can experiment with this e.g. sh*0.66, sh*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:



      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>








      share|improve this answer


























        0












        0








        0







        I recommend to define the number of lines for both directions and to calculate the distance to a line in terms of UV coordinates:



        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". This causes that the line always has the full "strength" in the middle (of course you can experiment with this e.g. sh*0.66, sh*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:



        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>








        share|improve this answer













        I recommend to define the number of lines for both directions and to calculate the distance to a line in terms of UV coordinates:



        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". This causes that the line always has the full "strength" in the middle (of course you can experiment with this e.g. sh*0.66, sh*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:



        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>








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





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






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Jan 3 at 10:07









        Rabbid76Rabbid76

        43.8k123354




        43.8k123354
































            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54015617%2fimprove-uv-line-quality-of-threejs-shader-geometry%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Can a sorcerer learn a 5th-level spell early by creating spell slots using the Font of Magic feature?

            ts Property 'filter' does not exist on type '{}'

            mat-slide-toggle shouldn't change it's state when I click cancel in confirmation window