【问题标题】:planeGeometry turned into a sphereplaneGeometry 变成了一个球体
【发布时间】:2022-02-02 06:29:30
【问题描述】:

我觉得我的逻辑在这里并不太糟糕。我正在尝试将 planeGeometry 转换为使用其 UV 坐标作为纬度和经度的球体。本质上是这里的逻辑:

  1. 将uv坐标分别转换为纬度/经度
  2. 将纬度/经度更改为弧度
  3. 转换为 x,y,z catesian 坐标

这是我正在尝试的顶点着色器的代码:

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

感谢任何建议,我觉得我只是在逻辑上遗漏了一些小东西,但我相信大众。

编辑:

问题最终变得非常愚蠢,我只是为 planeGeometry 参数传递了错误的值。这里的所有解决方案都是有效的。

【问题讨论】:

  • 如果 x,y 在赤道的圆盘上,z 是垂直于圆盘的南北距离。 z = sin(lat), x = cos(lat) * cos(lon), y = cos(lat) * sin(lon)

标签: javascript c three.js glsl vertex-shader


【解决方案1】:

This is how THREE.js does it:

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

基于此,您的 z 线似乎已切换。试试:

float z = sin(latRad) * cos(lonRad);

我也不明白在声明你的位置向量4 时使用0.5 的意义。只需使用 1.0:vec4(x,y,z, 1.0);

最后,当乘以 *90 然后除以 /180 时,您会通过度数来复杂化事情,然后返回弧度。如果您已经有 [0, 1] 范围,只需相应地乘以 PI 和 PI * 2 即可转换为弧度。

【讨论】:

  • 感谢您的帮助。将事物完全更改为弧度并添加所有完整值来自尝试一切以使其工作的地方,我理解简化事情。我尝试了更新后的数学,但仍然没有得到预期的几何形状,这个结果只是一个 2D 圆。
【解决方案2】:

如果我想将平面变形为球体,我总是在着色器中使用来自 three.js 的球面坐标实现:

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>

【讨论】:

  • 伙计,我已经复制粘贴了这个解决方案,但我仍然只是得到一个拉长的平面。感谢您的帮助,但我现在真的无法弄清楚......
  • @investInSoup 然后提供一个 sn-p 或 jsfiddle,或 codepen,或 codesandbox(或其他任何东西),以及一个演示问题的最小工作示例:)
  • 感谢您一直以来的信任,我已经在一个公共仓库中获得了它,您可以在此处克隆:github.com/soupIsTheCurrencyOfTheFuture/sandbox/tree/shaders 它只是内置了与三光纤反应以与渲染器通信
  • 所有着色器和相关代码都在 app.js 中:github.com/soupIsTheCurrencyOfTheFuture/sandbox/blob/shaders/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多