Webgl 用于纹理立方投影的GLSL着色器

Webgl 用于纹理立方投影的GLSL着色器,webgl,projection,fragment-shader,glsles,Webgl,Projection,Fragment Shader,Glsles,我正在尝试在WebGL着色器中实现纹理立方体投影,如下图所示: 到目前为止,我尝试的是: 我通过对象的包围盒(图片中间的框)如下: uniform vec3 u_bbmin; uniform vec3 u_bbmax; 。。。我的投影框的八个顶点是: vec3 v1 = vec3(u_bbmin.x, u_bbmin.y, u_bbmin.z); vec3 v2 = vec3(u_bbmax.x, u_bbmin.y, u_bbmin.z); vec3 v3 = vec3(u_bbmin.x

我正在尝试在WebGL着色器中实现纹理立方体投影,如下图所示:

到目前为止,我尝试的是:

我通过对象的包围盒(图片中间的框)如下:

uniform vec3 u_bbmin;
uniform vec3 u_bbmax;
。。。我的投影框的八个顶点是:

vec3 v1 = vec3(u_bbmin.x, u_bbmin.y, u_bbmin.z);
vec3 v2 = vec3(u_bbmax.x, u_bbmin.y, u_bbmin.z);
vec3 v3 = vec3(u_bbmin.x, u_bbmax.y, u_bbmin.z);
...other combinations
vec3 v8 = vec3(u_bbmax.x, u_bbmax.y, u_bbmax.z);
最后,要从我的纹理中采样,我需要以下形式的贴图:

varying vec3 v_modelPos;
...
uniform sampler2D s_texture;
vec2 tCoords = vec2(0.0);

tCoords.s = s(x,y,z)
tCoords.t = t(y,y,z)

vec4 color = texture2D(s_texture, tCoords);
我能够实现球形和圆柱形投影,但我现在陷入了如何获得这种立方体贴图的困境,纹理将延伸到整个边界框,纵横比无关紧要


也许我遗漏了一些要点,我需要一些提示。立方体投影的数学应该是什么样的?

我真的不知道这是否正确,但是

查看多维数据集映射的工作原理,OpenGL ES 2.0规范中有一个表

表3.21:基于纹理坐标长轴方向的立方体地图图像选择

我用它写了这个函数

#define RX 0
#define RY 1
#define RZ 2
#define S 0
#define T 1

void majorAxisDirection(vec3 normal, inout mat4 uvmat) {
   vec3 absnorm = abs(normal);
   if (absnorm.x > absnorm.y && absnorm.x > absnorm.z) {
     // x major
     if (normal.x >= 0.0) {
       uvmat[RZ][S] = -1.;
       uvmat[RY][T] = -1.;
     } else {
       uvmat[RZ][S] =  1.;
       uvmat[RY][T] = -1.;
     }
   } else if (absnorm.y > absnorm.z) {
     // y major
     if (normal.y >= 0.0) {
       uvmat[RX][S] =  1.;
       uvmat[RZ][T] =  1.;
     } else {
       uvmat[RX][S] =  1.;
       uvmat[RZ][T] = -1.;
     }
   } else {
     // z major
     if (normal.z >= 0.0) {
       uvmat[RX][S] =  1.;
       uvmat[RY][T] = -1.;
     } else {
       uvmat[RX][S] = -1.;
       uvmat[RY][T] = -1.;
     }
   }
}
传入一个矩阵,它将其设置为将正确的X、Y或Z移动到X和Y列(以转换为s和t)。换言之,你通过正常,它返回s和t

这将有效地使单位立方体投影在原点的正侧。加入另一个矩阵,我们可以移动和缩放立方体

如果希望它精确地适合立方体,则需要设置比例、平移和方向以匹配立方体

“严格使用”;
/*全局文档,twgl,requestAnimationFrame*/
常数vs=`
统一mat4-u_模型;
均匀mat4 u_视图投影;
属性向量4位置;
属性向量3正常;
属性向量2 texcoord;
可变矢量2 v_texCoord;
可变vec3 v_正常;
可变vec3 v_位置;
void main(){
v_texCoord=texCoord;
vec4位置=u_模型*位置;
gl_位置=u_视图投影*位置;
v_位置=位置xyz;
v_normal=(u_模型*vec4(normal,0)).xyz;
}
`;
常数fs=`
精密中泵浮子;
可变vec3 v_位置;
可变矢量2 v_texCoord;
可变vec3 v_正常;
均匀mat4 u_立方投影;
均匀二维u_扩散;
#定义RX 0
#定义RY 1
#定义rz2
#定义s0
#定义t1
#if-BOX\u投影
空洞主轴线方向(vec3法线,inout mat4 uvmat){
vec3 absnorm=abs(正常);
if(absnorm.x>absnorm.y&&absnorm.x>absnorm.z){
//大调
如果(正常.x>=0.0){
uvmat[RZ][S]=-1。;
uvmat[RY][T]=-1。;
}否则{
uvmat[RZ][S]=1。;
uvmat[RY][T]=-1。;
}
}else if(absnorm.y>absnorm.z){
//y大调
如果(正常.y>=0.0){
uvmat[RX][S]=1。;
uvmat[RZ][T]=1。;
}否则{
uvmat[RX][S]=1。;
uvmat[RZ][T]=-1。;
}
}否则{
//z大调
如果(正常.z>=0.0){
uvmat[RX][S]=1。;
uvmat[RY][T]=-1。;
}否则{
uvmat[RX][S]=-1。;
uvmat[RY][T]=-1。;
}
}
}
#else//立方体投影
空洞主轴线方向(vec3法线,inout mat4 uvmat){
vec3 absnorm=abs(正常);
if(absnorm.x>absnorm.y&&absnorm.x>absnorm.z){
//大调
uvmat[RZ][S]=1。;
uvmat[RY][T]=-1。;
}else if(absnorm.y>absnorm.z){
uvmat[RX][S]=1。;
uvmat[RZ][T]=1。;
}否则{
uvmat[RX][S]=1。;
uvmat[RY][T]=-1。;
}
}
#恩迪夫
void main(){
vec3正常=正常化(v_正常);
mat4 uvmat=mat4(
vec4(0,0,0,0),
vec4(0,0,0,0),
vec4(0,0,0,0),
vec4(0,0,0,1));
主轴方向(正常,uvmat);
uvmat=mat4(
abs(uvmat[0]),
abs(uvmat[1]),
abs(uvmat[2]),
abs(uvmat[3]);
vec2 uv=(uvmat*u_立方投影*vec4(v_位置,1)).xy;
gl_FragColor=纹理2D(u_漫反射,uv);
}
`;
常数m4=twgl.m4;
const gl=twgl.getWebGLContext(document.getElementById(“c”);
//编译着色器,查找位置
const cubeprojectinfo=twgl.createProgramInfo(gl,
[vs'#定义框_投影0\n'+fs]);
const-boxprograminfo=twgl.createProgramInfo(gl,
[vs'#定义框#投影1\n'+fs]);
设progNdx=1;
常量程序信息=[
CubeProjectInfo,
boxProjProgramInfo,
];
//创建缓冲区
const cubeBufferInfo=twgl.primitives.createCubeBufferInfo(gl,2);
const sphereBufferInfo=twgl.primitives.createSphereBufferInfo(gl,1,60,40);
const ctx=document.createElement(“画布”).getContext(“2d”);
ctx.canvas.width=256;
ctx.canvas.height=256;
ctx.fillStyle=`hsl(${360},0%,30%)`;
ctx.fillRect(0,0,256,256);
对于(设y=0;y<4;++y){
对于(设x=0;x<4;x+=2){
ctx.fillStyle=`hsl(${(x+y)/16*360},100%,75%)`;
ctx.fillRect((x+(y&1))*64,y*64,64,64);
}
}
ctx.线宽=10;
ctx.strokeRect(0,0,256,256);
ctx.font=“240px无衬线”;
ctx.textAlign=“中心”;
ctx.textb基线=“中间”;
ctx.fillStyle='红色';
ctx.fillText(“F”,128,128);
常量纹理=twgl.createTexture(gl{
src:ctx.canvas,
包裹:总包夹至边缘,
最小值:gl.LINEAR,//无mips
});
函数加法器(父级,类型){
const elem=document.createElement(类型);
父、子(elem);
返回元素;
}
函数makeRange(父对象、对象、属性、最小值、最大值、名称){
const divElem=addElem(父级,“div”);
常量inputElem=addElem(divElem,'输入');
对象。分配(inputElem{
键入:“范围”,
分:0,,
最高:1000,
值:(obj[prop]-min)/(max-min)*1000,
});
常量valuelem=addElem(divElem,'span');
valuelem.textContent=obj[prop].toFixed(2);
常量labelem=addElem(divElem,'label');
labelElem.textContent=名称;
函数更新(){
inputElem.value=(对象[prop]-min)/(最大-最小)*1000,
valuelem.textContent=obj[prop].toFixed(2);
}
inputElem.addEventListener('input',(e)=>{
obj[prop]=(e.target.value/1000*(最大-最小)+min);
更新();
});
返回更新;
}
常数模型=[
cubeBufferInfo,
sphereBufferInfo,
cubeBufferInfo,
];
常量旋转种子=[
1.
#define RX 0
#define RY 1
#define RZ 2
#define S 0
#define T 1

void majorAxisDirection(vec3 normal, inout mat4 uvmat) {
   vec3 absnorm = abs(normal);
   if (absnorm.x > absnorm.y && absnorm.x > absnorm.z) {
     // x major
     if (normal.x >= 0.0) {
       uvmat[RZ][S] = -1.;
       uvmat[RY][T] = -1.;
     } else {
       uvmat[RZ][S] =  1.;
       uvmat[RY][T] = -1.;
     }
   } else if (absnorm.y > absnorm.z) {
     // y major
     if (normal.y >= 0.0) {
       uvmat[RX][S] =  1.;
       uvmat[RZ][T] =  1.;
     } else {
       uvmat[RX][S] =  1.;
       uvmat[RZ][T] = -1.;
     }
   } else {
     // z major
     if (normal.z >= 0.0) {
       uvmat[RX][S] =  1.;
       uvmat[RY][T] = -1.;
     } else {
       uvmat[RX][S] = -1.;
       uvmat[RY][T] = -1.;
     }
   }
}
float sX = u_bbmax.x - u_bbmin.x;
float sY = u_bbmax.y - u_bbmin.y;
float sZ = u_bbmax.z - u_bbmin.z;

/* --- BOX PROJECTION - THREE SIDES --- */
if( (abs(modelNormal.x) > abs(modelNormal.y)) && (abs(modelNormal.x) > abs(modelNormal.z)) ) {
  uvCoords = modelPos.yz / vec2(sY, -sZ); // X axis
} else if( (abs(modelNormal.z) > abs(modelNormal.x)) && (abs(modelNormal.z) > abs(modelNormal.y)) ) {
  uvCoords = modelPos.xy / vec2(sX, -sY); // Z axis
} else {
  uvCoords = modelPos.xz / vec2(sX, -sZ); // Y axis
}
uvCoords += vec2(0.5);