在带纹理的球体上给定 4 个点,提取 2d 平面及其投影纹理
given 4 points on a textured sphere extract a 2d plane and it's projected texture
布景
我正在研究 scenekit 中的一个功能,我在球体的中心有一个摄像头。球体周围环绕着纹理。假设这是在房间内拍摄的 360 度图像。
到目前为止
我已经确定了球体上与地板角对应的位置。我可以提取并创建一个新的二维平面,该平面从相机的角度来看与地板的尺寸相匹配。例如。如果房间有长方形地板,我会创建一个梯形平面。
问题
但我希望新的 2d 平面具有地板的纹理,而不仅仅是形状。鉴于我要提取的不是原始纹理图像,而是它投影到球体上的结果,我该怎么做?
仅供参考,我对 scenekit 和 3d 图形还很陌生,对 opengl 更陌生
我假设您的图像结构允许您直接选择给定任意方向的像素。例如。如果方向的方位角映射到图像的 x 坐标,方向的高度映射到图像的 y 坐标,您可以将方向转换为这些参数并在这些坐标处选择颜色。如果不是这种情况,则必须找到相应光线(从相机开始)与球体的交点,并在该交点处找到纹理坐标。然后您可以使用此纹理坐标选择颜色。
现在,您基本上有两种选择。第一个选项是为平面生成一个新纹理。第二个选项是从着色器中采样球形图像。
选项 1 - 生成新纹理
您知道平面的范围,因此可以生成尺寸与平面的范围成比例的新纹理。您可以使用任意分辨率。然后您需要做的就是填充该纹理的像素。为此,您只需为给定像素生成光线并在球形图像中找到相应的颜色,如下所示:
input: d1, d2, d3, d3 (the four direction vectors of the plane corners)
// d3 +------+ d4
// d1 +------+ d2
for x from 0 to texture width
for y from 0 to texture height
//Find the direction vector for this pixel through bilinear interpolation
a = x / (width - 1) //horizontal interpolation parameter
b = y / (height - 1) //vertical interpolation parameter
d = (1 - a) * ((1 - b) * d1 + b * d3) + a * ((1 - b) * d2 + b * d4)
normalize d
//Sample the spherical image at d
color = sample(d)
//write the color to the new planar texture
texture(x, y) = color
next
next
然后,您就有了可以应用于平面的新纹理。如果将平面表示为两个三角形,则重心插值可能更合适。但是只要平面是矩形的,结果都是一样的。
请注意,sample()
方法取决于您的图像结构,需要适当实施。
选项 2 - 在着色器中采样
在选项 2 中,您执行与选项 1 中相同的操作。但是您是在片段着色器中执行的。您使用平面的顶点及其各自的方向(这可能只是顶点位置)并让 GPU 对它们进行插值。这直接给你方向d
,你可以使用。这是一些伪着色器代码:
in vec3 direction;
out vec4 color;
void main()
{
color = sample(normalize(direction));
}
如果您的图像是立方体贴图,您甚至可以让 GPU 进行采样。
布景 我正在研究 scenekit 中的一个功能,我在球体的中心有一个摄像头。球体周围环绕着纹理。假设这是在房间内拍摄的 360 度图像。
到目前为止 我已经确定了球体上与地板角对应的位置。我可以提取并创建一个新的二维平面,该平面从相机的角度来看与地板的尺寸相匹配。例如。如果房间有长方形地板,我会创建一个梯形平面。
问题 但我希望新的 2d 平面具有地板的纹理,而不仅仅是形状。鉴于我要提取的不是原始纹理图像,而是它投影到球体上的结果,我该怎么做?
仅供参考,我对 scenekit 和 3d 图形还很陌生,对 opengl 更陌生
我假设您的图像结构允许您直接选择给定任意方向的像素。例如。如果方向的方位角映射到图像的 x 坐标,方向的高度映射到图像的 y 坐标,您可以将方向转换为这些参数并在这些坐标处选择颜色。如果不是这种情况,则必须找到相应光线(从相机开始)与球体的交点,并在该交点处找到纹理坐标。然后您可以使用此纹理坐标选择颜色。
现在,您基本上有两种选择。第一个选项是为平面生成一个新纹理。第二个选项是从着色器中采样球形图像。
选项 1 - 生成新纹理
您知道平面的范围,因此可以生成尺寸与平面的范围成比例的新纹理。您可以使用任意分辨率。然后您需要做的就是填充该纹理的像素。为此,您只需为给定像素生成光线并在球形图像中找到相应的颜色,如下所示:
input: d1, d2, d3, d3 (the four direction vectors of the plane corners)
// d3 +------+ d4
// d1 +------+ d2
for x from 0 to texture width
for y from 0 to texture height
//Find the direction vector for this pixel through bilinear interpolation
a = x / (width - 1) //horizontal interpolation parameter
b = y / (height - 1) //vertical interpolation parameter
d = (1 - a) * ((1 - b) * d1 + b * d3) + a * ((1 - b) * d2 + b * d4)
normalize d
//Sample the spherical image at d
color = sample(d)
//write the color to the new planar texture
texture(x, y) = color
next
next
然后,您就有了可以应用于平面的新纹理。如果将平面表示为两个三角形,则重心插值可能更合适。但是只要平面是矩形的,结果都是一样的。
请注意,sample()
方法取决于您的图像结构,需要适当实施。
选项 2 - 在着色器中采样
在选项 2 中,您执行与选项 1 中相同的操作。但是您是在片段着色器中执行的。您使用平面的顶点及其各自的方向(这可能只是顶点位置)并让 GPU 对它们进行插值。这直接给你方向d
,你可以使用。这是一些伪着色器代码:
in vec3 direction;
out vec4 color;
void main()
{
color = sample(normalize(direction));
}
如果您的图像是立方体贴图,您甚至可以让 GPU 进行采样。