planeGeometry 变成了一个球体
planeGeometry turned into a sphere
我觉得我的逻辑在这里并不太糟糕。我正在尝试使用其 UV 坐标作为纬度和经度将 planeGeometry 转换为球体。本质上这是逻辑:
- 将uv坐标分别转换为lat/long
- 将 lat/long 改为弧度
- 转换为 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 参数传递了错误的值。这里所有的解决方案都是有效的。
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);
我也不明白在声明位置向量时使用 0.5
的意义4。只需使用 1.0:vec4(x,y,z, 1.0);
最后,您通过度数使事情复杂化,然后在乘以 *90 再除以 /180 时又回到弧度。如果您已经有了 [0, 1] 范围,只需乘以 PI 和 PI * 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>
我觉得我的逻辑在这里并不太糟糕。我正在尝试使用其 UV 坐标作为纬度和经度将 planeGeometry 转换为球体。本质上这是逻辑:
- 将uv坐标分别转换为lat/long
- 将 lat/long 改为弧度
- 转换为 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 参数传递了错误的值。这里所有的解决方案都是有效的。
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);
我也不明白在声明位置向量时使用 0.5
的意义4。只需使用 1.0:vec4(x,y,z, 1.0);
最后,您通过度数使事情复杂化,然后在乘以 *90 再除以 /180 时又回到弧度。如果您已经有了 [0, 1] 范围,只需乘以 PI 和 PI * 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>