Glsl 鱼眼天空盒着色器

Glsl 鱼眼天空盒着色器,glsl,webgl,Glsl,Webgl,我想写一个panaorama查看器。这主要涉及将图像映射到四边形以模拟天空盒 对于立方体贴图图像来说,这是相当繁琐的。或者制作一个这样做的着色器 对于像理光θ那样的等矩形图像 你可以用这个数学 // convert from direction (n) to texcoord (uv) float latitude = acos(n.y); float longitude = atan(n.z, n.x); vec2 sphereCoords =

我想写一个panaorama查看器。这主要涉及将图像映射到四边形以模拟天空盒

对于立方体贴图图像来说,这是相当繁琐的。或者制作一个这样做的着色器

对于像理光θ那样的等矩形图像

你可以用这个数学

      // convert from direction (n) to texcoord (uv)
      float latitude = acos(n.y);
      float longitude = atan(n.z, n.x);
      vec2 sphereCoords = vec2(longitude, latitude) * vec2(0.5 / PI, 1.0 / PI);
      vec2 uv = fract(vec2(0.5,1.0) - sphereCoords);
const m4=twgl.m4;
const gl=document.querySelector('canvas').getContext('webgl');
常数vs=`
属性向量4位置;
可变vec4 v_位置;
void main(){
v_位置=位置;
gl_位置=位置;
gl_位置z=1.0;
}
`;
常数fs=`
高精度浮点;
统一采样器2D u_skybox;
均匀mat4 u_视图方向投影反转;
可变vec4 v_位置;
#定义圆周率弧度(180.0)
void main(){
vec4 t=u_视图方向投影反转*v_位置;
vec3 n=标准化(t.xyz/t.w);
//从方向(n)转换为texcoord(uv)
浮动纬度=acos(n.y);
浮动经度=atan(n.z,n.x);
vec2-sphereCoords=vec2(经度、纬度)*vec2(0.5/PI,1.0/PI);
vec2紫外=分形(vec2(0.5,1.0)-sphereCoords);
//将u乘以2,因为我们只有180度的视野
gl_FragColor=纹理2D(u_skybox,uv*vec2(-2,1));
}
`;
const programInfo=twgl.createProgramInfo(gl[vs,fs]);
常量tex=twgl.createTexture(gl{
src:'https://i.imgur.com/ChIfXM0.jpg',
弗利皮:是的,
});
const bufferInfo=twgl.primitives.createXYQuadBufferInfo(gl,2);
函数渲染(时间){
时间*=0.001;
twgl.resizeCanvasToDisplaySize(总图画布);
总图视口(0,0,总图画布宽度,总图画布高度);
const aspect=gl.canvas.clientWidth/gl.canvas.clientHeight;
constprojectionmatrix=m4.perspective(45*Math.PI/180,aspect,1,20);
常数cameraMatrix=m4.旋转Y(时间*0.1);
m4.rotateX(cameraMatrix,数学sin(时间*0.3)*0.5,cameraMatrix);
常量viewMatrix=m4.逆(cameraMatrix);
viewMatrix[12]=0;
viewMatrix[13]=0;
viewMatrix[14]=0;
常量viewDirectionProjectionMatrix=m4.multiply(projectionMatrix,viewMatrix);
常量viewDirectionProjectionInverseMatrix=m4.逆(viewDirectionProjectionMatrix);
总账使用程序(programInfo.program);
twgl.setBuffersAndAttributes(总帐、程序信息、缓冲信息);
twgl.设置制服(程序信息{
u_viewDirectionProjectionInverse:viewDirectionProjectionInverseMatrix,
u_skyBox:tex,
});
twgl.drawBufferInfo(总账,bufferInfo);
请求动画帧(渲染);
}
请求动画帧(渲染)
body{margin:0;}
画布{宽度:100vw;高度:100vh;显示:块;}

我认为错误在于以下逻辑:

// multiply u by 2 because we only have a 180degree view
gl_FragColor = texture2D(u_skybox, uv * vec2(-2, 1));
虽然这在等矩形情况下有效,因为数学计算结果表明z分量只影响经度,但在鱼眼情况下它不再有效,因为
n.z
影响两个轴

通过取
n.z
的绝对值,并在z为负值时翻转
n.x
,可以计算公式中的负z分量:

  // convert from direction (n) to texcoord (uv)
  float r = 2.0 * atan(length(n.xy), abs(n.z)) / PI;
  float theta = atan(n.y, n.x * sign(n.z));
  vec2 uv = vec2(cos(theta), sin(theta)) * r * 0.5 + vec2(0.5);
这就是它的作用:

const m4=twgl.m4;
const gl=document.querySelector('canvas').getContext('webgl');
常数vs=`
属性向量4位置;
可变vec4 v_位置;
void main(){
v_位置=位置;
gl_位置=位置;
gl_位置z=1.0;
}
`;
常数fs=`
高精度浮点;
统一采样器2D u_skybox;
均匀mat4 u_视图方向投影反转;
可变vec4 v_位置;
#定义圆周率弧度(180.0)
void main(){
vec4 t=u_视图方向投影反转*v_位置;
vec3 n=标准化(t.xyz/t.w);
//从方向(n)转换为texcoord(uv)
浮点数r=2.0*atan(长度n.xy,绝对值n.z))/PI;
浮点θ=atan(n.y,n.x*符号(n.z));
vec2uv=vec2(cos(θ),sin(θ))*r*0.5+vec2(0.5);
gl_FragColor=纹理2D(u_skybox,uv*vec2(-1.0,1.0));
}
`;
const programInfo=twgl.createProgramInfo(gl[vs,fs]);
常量tex=twgl.createTexture(gl{
src:'https://i.imgur.com/dzXCQwM.jpg',
弗利皮:是的,
});
const bufferInfo=twgl.primitives.createXYQuadBufferInfo(gl,2);
函数渲染(时间){
时间*=0.001;
twgl.resizeCanvasToDisplaySize(总图画布);
总图视口(0,0,总图画布宽度,总图画布高度);
const aspect=gl.canvas.clientWidth/gl.canvas.clientHeight;
constprojectionmatrix=m4.perspective(45*Math.PI/180,aspect,1,20);
常数cameraMatrix=m4.旋转Y(时间*0.1);
m4.rotateX(cameraMatrix,0.7+数学sin(time*0.3)*.7,cameraMatrix);
常量viewMatrix=m4.逆(cameraMatrix);
viewMatrix[12]=0;
viewMatrix[13]=0;
viewMatrix[14]=0;
常量viewDirectionProjectionMatrix=m4.multiply(projectionMatrix,viewMatrix);
常量viewDirectionProjectionInverseMatrix=m4.逆(viewDirectionProjectionMatrix);
总账使用程序(programInfo.program);
twgl.setBuffersAndAttributes(总帐、程序信息、缓冲信息);
twgl.设置制服(程序信息{
u_viewDirectionProjectionInverse:viewDirectionProjectionInverseMatrix,
u_skyBox:tex,
});
twgl.drawBufferInfo(总账,bufferInfo);
请求动画帧(渲染);
}
请求动画帧(渲染)
body{margin:0;}
画布{宽度:100vw;高度:100vh;显示:块;}