gpt4 book ai didi

three.js - 将极坐标映射到 webgl 着色器 uv

转载 作者:行者123 更新时间:2023-12-01 13:42:14 24 4
gpt4 key购买 nike

在我的 WebGL 着色器中,我想根据范围为 [0,2*PI) 的函数 (atan) 的输出来映射纹理的 U 值。但是 U 的范围(正如 texture2D 所预期的那样)是 [0,1]。所以我试图将开区间映射到闭区间。

这说明了问题: enter image description here水平红色渐变是 U 轴,当我的 atan 从 0 变为 2*PI 时,它从 Red=1 变为 Red=0。但是 atan 将 2*PI 视为零,因此在渐变变黑后右侧有一条红色带。 (顶部和底部也有红色带,但这是与 V 值有关的类似问题,出于这个问题的目的,我忽略了它)。

使用 three.js 显示顶点的能力查看此图像: enter image description here

您可以看到最右边的顶点 (U=1) 是如何再次对应 atan=0 而不是 2*PI 的红色。

关于如何实现这一点有什么建议吗?我不能强制 atan 返回 2*PI。我不想平铺纹理。我能以某种方式将 U 值映射到开区间吗?

我一直认为一定有一个简单的解决方案,但我已经尝试了所有我能想到的修复方法。

这是我的顶点着色器:

void main()
{

vec4 mvPosition = modelViewMatrix * vec4(position, 1.0 );
gl_Position = projectionMatrix * mvPosition;

// convert from uv to polar coords
vec2 tempuv = uv;
theta = (1.0-tempuv[1]) * PI;
phi = PI * 2.0 * tempuv[0];

// convert polar to cartesian. Theta is polar, phi is azimuth.
x = sin(theta)*cos(phi);
y = sin(theta)*sin(phi);
z = cos(theta);

// and convert back again to demonstrate problem.
// problem: the phi above is [0,2*PI]. this phi is [0,2*PI)
phi = atan2(y, x);
if (phi < 0.0) {
phi = phi + PI*2.0;
}
if (phi > (2.0 * PI)) { // allow 2PI since we gen uv over [0,1]
phi = phi - 2.0 * PI;
}
theta = acos(z);

// now get uv in new chart.
float newv = 1.0 - theta/PI;
float newu = phi/(2.0 * PI);
vec2 newuv = vec2(newu, newv);
vUv = newuv;
}

这是我的片段着色器:

void main() {
vec2 uv = vUv;
gl_FragColor = vec4(1.0- uv[0],0.,0.,1.);
}

最佳答案

如您所提到的,看待问题的一种方式是,边缘处 1 变为 0。但另一种看待它的方式是,如果你将 uv 改为从 0 到 2 而不是 0 到 1,然后你使用 fract(uv) 你会多次遇到同样的问题,因为你'有效地采样一个函数,每个点只能选择一种颜色,而要正确映射它,你需要一些如何让每个点神奇地为顶点选择 2 种颜色,这些顶点需要一种颜色用于向左插值,另一种用于插值向右。

示例 fract(uv * 2.)

var vs = `
#define PI radians(180.)

attribute vec4 position;
attribute vec2 texcoord;

varying vec2 vUv;

void main() {
gl_Position = position;

// convert from uv to polar coords
vec2 tempuv = fract(texcoord * 2.);

float theta = (1.0-tempuv[1]) * PI;
float phi = PI * 2.0 * tempuv[0];

// convert polar to cartesian. Theta is polar, phi is azimuth.
float x = sin(theta)*cos(phi);
float y = sin(theta)*sin(phi);
float z = cos(theta);

// and convert back again to demonstrate problem.
// problem: the phi above is [0,2*PI]. this phi is [0,2*PI)
phi = atan(y, x);
if (phi < 0.0) {
phi = phi + PI * 2.0;
}
if (phi > (2.0 * PI)) { // allow 2PI since we gen uv over [0,1]
phi = phi - 2.0 * PI;
}
theta = acos(z);

// now get uv in new chart.
float newv = 1.0 - theta/PI;
float newu = phi/(2.0 * PI);
vec2 newuv = vec2(newu, newv);
vUv = newuv;
}
`;

var fs = `
precision mediump float;
varying vec2 vUv;
void main() {
vec2 uv = vUv;
gl_FragColor = vec4(1.0- uv[0],0.,0.,1.);
}
`;

var gl = document.querySelector("canvas").getContext("webgl");
var m4 = twgl.m4;
var programInfo = twgl.createProgramInfo(gl, [vs, fs]);
var bufferInfo = twgl.primitives.createPlaneBufferInfo(
gl, 2, 2, 20, 20, m4.rotationX(Math.PI * .5));

twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.drawBufferInfo(gl, bufferInfo);
body { margin: 0 }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://twgljs.org/dist/2.x/twgl-full.min.js"></script>
<canvas></canvas>

将代码移动到片段着色器有效地解决了它。

将代码移至片段着色器的示例

var vs = `
attribute vec4 position;
attribute vec2 texcoord;

varying vec2 vUv;

void main() {
gl_Position = position;
vUv = texcoord;
}
`;

var fs = `
precision mediump float;
varying vec2 vUv;

#define PI radians(180.)

void main() {

// convert from uv to polar coords
vec2 tempuv = vUv;

float theta = (1.0-tempuv[1]) * PI;
float phi = PI * 2.0 * tempuv[0];

// convert polar to cartesian. Theta is polar, phi is azimuth.
float x = sin(theta)*cos(phi);
float y = sin(theta)*sin(phi);
float z = cos(theta);

// and convert back again to demonstrate problem.
// problem: the phi above is [0,2*PI]. this phi is [0,2*PI)
phi = atan(y, x);
if (phi < 0.0) {
phi = phi + PI * 2.0;
}
if (phi > (2.0 * PI)) { // allow 2PI since we gen uv over [0,1]
phi = phi - 2.0 * PI;
}
theta = acos(z);

// now get uv in new chart.
float newv = 1.0 - theta/PI;
float newu = phi/(2.0 * PI);
vec2 newuv = vec2(newu, newv);
gl_FragColor = vec4(1.0- newuv[0],0.,0.,1.);
}
`;

var gl = document.querySelector("canvas").getContext("webgl");
var m4 = twgl.m4;
var programInfo = twgl.createProgramInfo(gl, [vs, fs]);
var bufferInfo = twgl.primitives.createPlaneBufferInfo(
gl, 2, 2, 20, 20, m4.rotationX(Math.PI * .5));

twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.drawBufferInfo(gl, bufferInfo);
body { margin: 0 }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://twgljs.org/dist/2.x/twgl-full.min.js"></script>
<canvas></canvas>

将其保留为顶点着色器的一种解决方案就是捏造数字,使其介于 0.00005 和 0.99995 之间。

var vs = `
#define PI radians(180.)

attribute vec4 position;
attribute vec2 texcoord;

varying vec2 vUv;

void main() {
gl_Position = position;

// convert from uv to polar coords
vec2 tempuv = texcoord * 0.9999 + 0.00005;

float theta = (1.0-tempuv[1]) * PI;
float phi = PI * 2.0 * tempuv[0];

// convert polar to cartesian. Theta is polar, phi is azimuth.
float x = sin(theta)*cos(phi);
float y = sin(theta)*sin(phi);
float z = cos(theta);

// and convert back again to demonstrate problem.
// problem: the phi above is [0,2*PI]. this phi is [0,2*PI)
phi = atan(y, x);
if (phi < 0.0) {
phi = phi + PI * 2.0;
}
if (phi > (2.0 * PI)) { // allow 2PI since we gen uv over [0,1]
phi = phi - 2.0 * PI;
}
theta = acos(z);

// now get uv in new chart.
float newv = 1.0 - theta/PI;
float newu = phi/(2.0 * PI);
vec2 newuv = vec2(newu, newv);
vUv = newuv;
}
`;

var fs = `
precision mediump float;
varying vec2 vUv;
void main() {
vec2 uv = vUv;
gl_FragColor = vec4(1.0- uv[0],0.,0.,1.);
}
`;

var gl = document.querySelector("canvas").getContext("webgl");
var m4 = twgl.m4;
var programInfo = twgl.createProgramInfo(gl, [vs, fs]);
var bufferInfo = twgl.primitives.createPlaneBufferInfo(
gl, 2, 2, 20, 20, m4.rotationX(Math.PI * .5));

twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.drawBufferInfo(gl, bufferInfo);
body { margin: 0 }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://twgljs.org/dist/2.x/twgl-full.min.js"></script>
<canvas></canvas>

这只有效,因为纹理坐标从 0 变为 1。如果它们从 0 变为 > 1(或小于 0),您会遇到与上述相同的问题,即某些顶点需要超过 1 种颜色。您基本上需要使用片段着色器解决方案

关于three.js - 将极坐标映射到 webgl 着色器 uv,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39059323/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com