Nasıl bir doku her zaman kamera karşısında ..?


10

Güncelleme 5

Bekleneni göstermek için başka bir keman yarattı. Görünmez bir skydome ve bir cubecamera eklenir ve çevre haritası kullanılır; benim durumumda, bu tekniğin hiçbiri daha önce belirtilen nedenlerle kullanılmamalıdır.


Güncelleme 4

Önemli: Hedef ağın arkasında, dokunun ağ yüzeyine doğru bir şekilde bağlanıp bağlanmadığını gözlemlemek için yansıtıcı bir düzlem olduğunu lütfen unutmayın, çözmeye çalıştığım şeyle ilgisi yoktur.


Güncelleme 3

Beklenen davranışın DEĞİL olduğunu göstermek için yeni bir keman oluşturdu

  • kod

Belki sorumu yeniden ifade etmeliyim, ama çözmeye çalıştığım şey hakkında doğru bir şekilde tanımlayabilecek bilgiye sahip değilim, lütfen yardım edin .. olabilir .. ?)


Güncelleme 2

(Kod pasajı uygulandığı için kullanımdan kaldırıldı.)


Güncelleme

Tamam .. 3 yöntem ekledim:

  • TransformUvbir geometriyi ve uv-dönüşümünü işleyen bir transformatör yöntemini kabul eder. Geri arama bir UVS her bir yüz için bir dizi ve karşılık gelen kabul Face3ait geometry.faces[]parametreleri olarak.

  • MatcapTransformer matcap dönüşümünü yapmak için uv-transform işleyici geri aramasıdır.

    ve

  • fixTextureWhenRotateAroundZAxis isminde gibi çalışır.

Şimdiye kadar fixTexture..yöntemlerin hiçbiri tamamen işe yaramaz, ayrıca çözülmez fixTextureWhenRotateAroundXAxis. Sorun hala çözülmemiş, keşke yeni eklenenler bana yardım etmenize yardımcı olabilir.


Bir örgünün dokusunu, göreceli pozisyonlar ne olursa olsun, her zaman aktif bir perspektif kamerayla yüzleştirmeye çalışıyorum.

Sahnemin gerçek bir örneğini oluşturmak için ve etkileşim oldukça karmaşık olurdu, niyetimi göstermek için minimal bir örnek oluşturdum.

  • kod
    var MatcapTransformer=function(uvs, face) {
    	for(var i=uvs.length; i-->0;) {
    		uvs[i].x=face.vertexNormals[i].x*0.5+0.5;
    		uvs[i].y=face.vertexNormals[i].y*0.5+0.5;
    	}
    };
    
    var TransformUv=function(geometry, xformer) {
    	// The first argument is also used as an array in the recursive calls 
    	// as there's no method overloading in javascript; and so is the callback. 
    	var a=arguments[0], callback=arguments[1];
    
    	var faceIterator=function(uvFaces, index) {
    		xformer(uvFaces[index], geometry.faces[index]);
    	};
    
    	var layerIterator=function(uvLayers, index) {
    		TransformUv(uvLayers[index], faceIterator);
    	};
    
    	for(var i=a.length; i-->0;) {
    		callback(a, i);
    	}
    
    	if(!(i<0)) {
    		TransformUv(geometry.faceVertexUvs, layerIterator);
    	}
    };
    
    var SetResizeHandler=function(renderer, camera) {
    	var callback=function() {
    		renderer.setSize(window.innerWidth, window.innerHeight);
    		camera.aspect=window.innerWidth/window.innerHeight;
    		camera.updateProjectionMatrix();
    	};
    
    	// bind the resize event
    	window.addEventListener('resize', callback, false);
    
    	// return .stop() the function to stop watching window resize
    	return {
    		stop: function() {
    			window.removeEventListener('resize', callback);
    		}
    	};
    };
    
    (function() {
    	var fov=45;
    	var aspect=window.innerWidth/window.innerHeight;
    	var loader=new THREE.TextureLoader();
    
    	var texture=loader.load('https://i.postimg.cc/mTsN30vx/canyon-s.jpg');
    	texture.wrapS=THREE.RepeatWrapping;
    	texture.wrapT=THREE.RepeatWrapping;
    	texture.center.set(1/2, 1/2);
    
    	var geometry=new THREE.SphereGeometry(1, 16, 16);
    	var material=new THREE.MeshBasicMaterial({ 'map': texture });
    	var mesh=new THREE.Mesh(geometry, material);
    
    	var geoWireframe=new THREE.WireframeGeometry(geometry);
    	var matWireframe=new THREE.LineBasicMaterial({ 'color': 'red', 'linewidth': 2 });
    	mesh.add(new THREE.LineSegments(geoWireframe, matWireframe));
    
    	var camera=new THREE.PerspectiveCamera(fov, aspect);
    	camera.position.setZ(20);
    
    	var scene=new THREE.Scene();
    	scene.add(mesh);
      
    	{
    		var mirror=new THREE.CubeCamera(.1, 2000, 4096);
    		var geoPlane=new THREE.PlaneGeometry(16, 16);
    		var matPlane=new THREE.MeshBasicMaterial({
    			'envMap': mirror.renderTarget.texture
    		});
    
    		var plane=new THREE.Mesh(geoPlane, matPlane);
    		plane.add(mirror);
    		plane.position.setZ(-4);
    		plane.lookAt(mesh.position);
    		scene.add(plane);
    	}
    
    	var renderer=new THREE.WebGLRenderer();
    
    	var container=document.getElementById('container1');
    	container.appendChild(renderer.domElement);
    
    	SetResizeHandler(renderer, camera);
    	renderer.setSize(window.innerWidth, window.innerHeight);
    
    	var fixTextureWhenRotateAroundYAxis=function() {
    		mesh.rotation.y+=0.01;
    		texture.offset.set(mesh.rotation.y/(2*Math.PI), 0);
    	};
    
    	var fixTextureWhenRotateAroundZAxis=function() {
    		mesh.rotation.z+=0.01;
    		texture.rotation=-mesh.rotation.z
    		TransformUv(geometry, MatcapTransformer);
    	};
    
    	// This is wrong
    	var fixTextureWhenRotateAroundAllAxis=function() {
    		mesh.rotation.y+=0.01;
    		mesh.rotation.x+=0.01;
    		mesh.rotation.z+=0.01;
    
    		// Dun know how to do it correctly .. 
    		texture.offset.set(mesh.rotation.y/(2*Math.PI), 0);
    	};
      
    	var controls=new THREE.TrackballControls(camera, container);
    
    	renderer.setAnimationLoop(function() {
    		fixTextureWhenRotateAroundYAxis();
    
    		// Uncomment the following line and comment out `fixTextureWhenRotateAroundYAxis` to see the demo
    		// fixTextureWhenRotateAroundZAxis();
    
    		// fixTextureWhenRotateAroundAllAxis();
        
    		// controls.update();
    		plane.visible=false;
    		mirror.update(renderer, scene);
    		plane.visible=true; 
    		renderer.render(scene, camera);
    	});
    })();
    body {
    	background-color: #000;
    	margin: 0px;
    	overflow: hidden;
    }
    <script src="https://threejs.org/build/three.min.js"></script>
    <script src="https://threejs.org/examples/js/controls/TrackballControls.js"></script>
    
    <div id='container1'></div>

Bu gösteride örgünün kendisinin dönmesine rağmen, asıl amacım kameranın örgünün etrafında dönen gibi hareket etmesini sağlamak olduğunu lütfen unutmayın.

Hareketi daha net hale getirmek için tel kafes ekledim. Gördüğünüz fixTextureWhenRotateAroundYAxisgibi doğru yapmak için kullanıyorum , ama bu sadece y ekseni için. mesh.rotation.yBenim gerçek kodda gibi bir şey hesaplanır

var ve=camera.position.clone();
ve.sub(mesh.position);
var rotY=Math.atan2(ve.x, ve.z);
var offsetX=rotY/(2*Math.PI);

Ancak, fixTextureWhenRotateAroundAllAxisdoğru bir şekilde nasıl yapılacağına dair bilgim yok . Bunu çözmenin bazı kısıtlamaları vardır:

  • İstemci makinelerde performans sorunları olabileceğinden CubeCamera / CubeMap kullanılamaz

  • lookAtFotoğraf makinesini sadece küreler değil, her türlü geometriye sahip oldukları için sadece kamerayı örmeyin; gibi bir çerçeve içinde lookAtve geri hileler .quaterniontamam olurdu.

Tescilli kodu ifşa etme hakkım olmadığı için ya da minimal bir örnek oluşturmak için çaba harcamak zorunda kalmayacağım için bir XY sorunu sorduğumu lütfen yanlış anlamayın :)


GLSL gölgelendirici dilini biliyor musunuz? Bu efekti elde etmenin tek yolu, UV koordinatlarının varsayılan davranışını geçersiz kılan özel bir gölgelendirici yazmaktır.
Marquizzo

@Marquizzo GLSL'de uzman değilim, ancak WebGLRenderTargetCube gibi three.js kaynak kodunu kazdım; ShaderMaterial ile sarılmış GLSL bulabilirim. Söylediğim gibi, bu konuda bilgi sahibi değilim ve şu anda içmek çok fazla olurdu. Three.js'nin GLSL'yi yeterince iyi ve aynı zamanda kütüphaneyi kullanarak GLSL ile uğraşmadan bu tür şeyleri başarabileceğimizi düşündüğüm kadar hafif olduğuna inanıyorum.
Ken Kin

2
Maalesef, bunu yapmayı düşünebilmemin tek yolu GLSL'den geçiyor, çünkü dokular her zaman gölgelendiricide çiziliyor ve doku konumunun hesaplanma şeklini değiştirmeye çalışıyorsunuz. Daha iyi şanslar de sorulara "nasıl" bu tür soran olabilir discourse.threejs.org
Marquizzo

Yanıtlar:


7

Kameraya bakacak olursak:

resim açıklamasını buraya girin

Ya da, daha iyi, bu soruda olduğu gibi, ters düzeltmenin istendiği:

resim açıklamasını buraya girin

Bunu başarmak için, basit bir parça gölgelendirici kurmanız gerekir (OP'nin yanlışlıkla yaptığı gibi):

Köşe gölgelendirici

void main() {
  gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

Parça gölgelendirici

uniform vec2 size;
uniform sampler2D texture;

void main() {
  gl_FragColor = texture2D(texture, gl_FragCoord.xy / size.xy);
}

Three.js ile gölgelendiricinin çalışan bir alay konusu

function main() {
  // Uniform texture setting
  const uniforms = {
    texture1: { type: "t", value: new THREE.TextureLoader().load( "https://threejsfundamentals.org/threejs/resources/images/wall.jpg" ) }
  };
  // Material by shader
   const myMaterial = new THREE.ShaderMaterial({
        uniforms: uniforms,
        vertexShader: document.getElementById('vertexShader').textContent,
        fragmentShader: document.getElementById('fragmentShader').textContent
      });
  const canvas = document.querySelector('#c');
  const renderer = new THREE.WebGLRenderer({canvas});

  const fov = 75;
  const aspect = 2;  // the canvas default
  const near = 0.1;
  const far = 5;
  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.position.z = 2;

  const scene = new THREE.Scene();

  const boxWidth = 1;
  const boxHeight = 1;
  const boxDepth = 1;
  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);

  const cubes = [];  // just an array we can use to rotate the cubes
  
  const cube = new THREE.Mesh(geometry, myMaterial);
  scene.add(cube);
  cubes.push(cube);  // add to our list of cubes to rotate

  function resizeRendererToDisplaySize(renderer) {
    const canvas = renderer.domElement;
    const width = canvas.clientWidth;
    const height = canvas.clientHeight;
    const needResize = canvas.width !== width || canvas.height !== height;
    if (needResize) {
      renderer.setSize(width, height, false);
    }
    return needResize;
  }

  function render(time) {
    time *= 0.001;
    
    if (resizeRendererToDisplaySize(renderer)) {
      const canvas = renderer.domElement;
      camera.aspect = canvas.clientWidth / canvas.clientHeight;
      camera.updateProjectionMatrix();
    }

    cubes.forEach((cube, ndx) => {
      const speed = .2 + ndx * .1;
      const rot = time * speed;
      
      
      cube.rotation.x = rot;
      cube.rotation.y = rot;      
    });
   

    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }

  requestAnimationFrame(render);
}

main();
body {
  margin: 0;
}
#c {
  width: 100vw;
  height: 100vh;
  display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/109/three.min.js"></script>
<script id="vertexShader" type="x-shader/x-vertex">
  void main() {
    gl_Position =   projectionMatrix * 
                    modelViewMatrix * 
                    vec4(position,1.0);
  }
</script>

<script id="fragmentShader" type="x-shader/x-fragment">
  uniform sampler2D texture1;
  const vec2  size = vec2(1024, 512);
  
  void main() {
    gl_FragColor = texture2D(texture1,gl_FragCoord.xy/size.xy); 
  }
</script>
<canvas id="c"></canvas>
  

Geçerli bir alternatif: Küp Haritalama

Burada küp haritalama hakkında bir jsfiddle değiştirdim , belki de ne arıyorsun:

https://jsfiddle.net/v8efxdo7/

Küp, yüz dokusunu alttaki nesneye yansıtır ve kameraya bakar.

Not: Işık ve iç nesne sabit konumda olduğu için ışıklar dönüşle değişir, kamera ve projeksiyon küpü de sahnenin merkezi etrafında döner.

Örneğe dikkatlice bakarsanız, bu teknik mükemmel değildir, ancak aradığınız şey (bir kutuya uygulanır) aldatıcıdır, çünkü bir küpün dokusunun UV sargısı çapraz şekillidir, UV'nin kendisi döndürülmez projeksiyon nesnesi şekli ve projeksiyon konusu şekli önemli olduğundan projeksiyon tekniklerini kullanmanın dezavantajları vardır.

Sadece daha iyi anlamak için: gerçek dünyada, kutulardaki 3B alanda bu etkiyi nerede görüyorsunuz? Aklıma gelen tek örnek, 3D bir yüzey üzerinde bir 2D projeksiyon (görsel tasarımda projeksiyon eşlemesi gibi).


1
Daha öncekinden daha fazlası. Bunu yapmak için lütfen üç.js kullanır mısınız? GLSL'ye aşina değilim. Ve ilk animasyondaki küpün her eksen etrafında aynı anda dönmesi durumunda ne olacağını merak ediyorum? Uygulamanızı three.js kullanarak sağladıktan sonra, sorumun çözülüp çözülmeyeceğini göreceğim. Umut verici görünüyor :)
Ken Kin

1
Merhaba dostum, ihtiyacınız olan gölgelendiriciyi çoğaltan basit bir demo ile bir kod ekledim.
Mosè Raguzzini

Davam için işe yarayıp yaramadığını kontrol etmek için biraz zamana ihtiyacım var.
Ken Kin

1
Doku her zaman kamerayla yüzleşirse , env'in ışığı yoksa veya malzeme gölgelenmezse , etki her zaman düz bir doku olacaktır. Konum gibi öznitelikler ve üniformalar Geometry ve BufferGeometry tarafından sağlanır, böylece bunları başka yerlerde geri almak zorunda kalmazsınız. Three.js belgelerinin bu konuda güzel bir bölümü var: threejs.org/docs/#api/en/renderers/webgl/WebGLProgram
Mosè Raguzzini

1
Lütfen gözden geçirilmiş olanın jsfiddle.net/7k9so2fr adresine bakın . Doku bağlamanın bu davranışının elde etmeye çalıştığım şey olmadığını söyleyebilirim :( ..
Ken Kin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.