[英]Improve UV line quality of threejs/shader geometry
我正在使用threejs圓環的uv輸出在圓環上創建移動線。 它有效,但看起來不清晰。
如何改善線路質量? 我嘗試將材料制作為雙面,並增加線的寬度,但是質量並沒有太大改善。
我還沒有嘗試在Threejs之外完全復制圓環,但這超出了我的舒適范圍。
我希望有辦法改變片段着色器的邏輯以產生更清晰的線條。 有任何建議,我將不勝感激。
/* 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;
});
}
我建議定義兩個方向的線數,並根據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.66
, sh*0.33
):
float sh = 0.005;
vec2 lineUV = smoothstep(sh, sh*0.5, abs(distUV));
alpha通道是兩個方向的最大“飽和度”值:
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>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.