Siento que mi lógica no es demasiado horrible aquí. Estoy tratando de convertir un planeGeometry en una esfera usando sus coordenadas UV como latitud y longitud. Esencialmente aquí está la lógica:
aquí está el código para el vertex shader que estoy probando:
varying vec2 vUv; #define PI 3.14159265359 void main() { vUv = uv; float lat = (uv.x - 0.5) * 90.0; float lon = abs((uv.y - 0.5) * 180.0); float latRad = lat * (PI / 180.0); float lonRad = lon * (PI / 180.0); float x = sin(latRad) * sin(lonRad); float y = cos(latRad); float z = cos(latRad) * sin(lonRad); gl_Position = projectionMatrix * modelViewMatrix * vec4(x,y,z, 0.5); }Se agradece cualquier consejo, siento que me falta algo pequeño con la lógica, pero creo en las masas.
Editar:
El problema terminó siendo bastante estúpido, solo estaba pasando los valores incorrectos para los argumentos de planeGeometry. Todas las soluciones aquí son válidas.
setFromSphericalCoords( radius, phi, theta ) { const sinPhiRadius = Math.sin( phi ) * radius; this.x = sinPhiRadius * Math.sin( theta ); this.y = Math.cos( phi ) * radius; this.z = sinPhiRadius * Math.cos( theta ); return this; }Basado en esto, parece que su línea z está cambiada. Probar:
float z = sin(latRad) * cos(lonRad); Tampoco entiendo el punto de usar 0.5 al declarar su posición vector4. Solo usa 1.0: vec4(x,y,z, 1.0);
Finalmente, está complicando las cosas yendo a grados, luego de vuelta a radianes al multiplicar *90 y luego dividir /180. Si ya tiene el rango [0, 1], simplemente multiplique por PI y PI * 2 en consecuencia para convertir a radianes.
Siempre uso esa implementación de coordenadas esféricas de three.js en shaders, si quiero cambiar de plano a esfera:
body{ overflow: hidden; margin: 0; } <script type="module"> import * as THREE from "https://cdn.skypack.dev/three@0.136.0"; import { OrbitControls } from "https://cdn.skypack.dev/three@0.136.0/examples/jsm/controls/OrbitControls.js"; import { GUI } from "https://cdn.skypack.dev/three@0.136.0/examples/jsm/libs/lil-gui.module.min.js"; let scene = new THREE.Scene(); let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000); camera.position.set(0, 0, 1).setLength(6); let renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(innerWidth, innerHeight); renderer.setClearColor(0x404040); document.body.appendChild(renderer.domElement); let controls = new OrbitControls(camera, renderer.domElement); controls.autoRotate = true; controls.update(); console.log(controls.getAzimuthalAngle()) let light = new THREE.DirectionalLight(0xffffff, 1); light.position.set(0.25, 0.5, 1); scene.add(light, new THREE.AmbientLight(0xffffff, 0.5)); let u = { mixVal: {value: 0} } let g = new THREE.PlaneGeometry(2 * Math.PI, Math.PI, 100, 100); let m = new THREE.MeshBasicMaterial({ map: new THREE.TextureLoader().load("https://threejs.org/examples/textures/uv_grid_opengl.jpg"), onBeforeCompile: shader => { shader.uniforms.mixVal = u.mixVal; shader.vertexShader = ` uniform float mixVal; vec3 fromSpherical(float radius, float phi, float theta){ float sinPhiRadius = sin( phi ) * radius; float x = sinPhiRadius * sin( theta ); float y = cos( phi ) * radius; float z = sinPhiRadius * cos( theta ); return vec3(x, y, z); } ${shader.vertexShader} `.replace( `#include <begin_vertex>`, `#include <begin_vertex> float phi = (1. - uv.y) * PI; float theta = uv.x * PI * 2. + PI; float r = 1.; transformed = mix(position, fromSpherical(r, phi, theta), mixVal); ` ); //console.log(shader.vertexShader); } }); let box = new THREE.Mesh(g, m); scene.add(box); let gui = new GUI(); gui.add(u.mixVal, "value", 0, 1).name("mixVal"); window.addEventListener("resize", onWindowResize); renderer.setAnimationLoop(() => { renderer.render(scene, camera); }) function onWindowResize() { camera.aspect = innerWidth / innerHeight; camera.updateProjectionMatrix(); renderer.setSize(innerWidth, innerHeight); } </script>