Javascript webgl tilemap渲染不正确的UV计算
我正在尝试在单个四边形上渲染平铺贴图 我的方法使用一种“瓷砖贴图”纹理,其中每个像素在瓷砖集中存储瓷砖的X和Y索引 渲染片段时,其目的是:Javascript webgl tilemap渲染不正确的UV计算,javascript,webgl,Javascript,Webgl,我正在尝试在单个四边形上渲染平铺贴图 我的方法使用一种“瓷砖贴图”纹理,其中每个像素在瓷砖集中存储瓷砖的X和Y索引 渲染片段时,其目的是: 使用顶点纹理坐标对“平铺贴图”纹理进行采样 从纹理的R和G通道检索X和Y索引 计算选定瓷砖的UV 使用UV对纹理图集进行采样 我在工作上遇到了问题 以下是我试图用于渲染此对象的着色器代码: 顶点 #版本300 es 精密中泵浮子; 统一mat4视图; 均匀mat4反射; 统一mat3模型; vec2位置中的布局(位置=0); vec2 aTEXCOORD中的
#版本300 es
精密中泵浮子;
统一mat4视图;
均匀mat4反射;
统一mat3模型;
vec2位置中的布局(位置=0);
vec2 aTEXCOORD中的布局(位置=1);
出vec2 vTEXCOORD;
void main()
{
//翻转uv并将其传递给碎片着色器
vTEXCOORD=vec2(aTEXCOORD.x,1.0f-aTEXCOORD.y);
//变换顶点位置
vec3转化=uMODEL*vec3(位置,1.0);
gl_Position=uPROJECTION*uVIEW*vec4(transformed.xy,0.0,1.0);
}
碎片
#版本300 es
精密中泵浮子;
精密医疗泵usampler2D;
统一的usampler2D uMAP;
均匀采样;
均匀的vec2 uATLAS_尺寸;
在vec2 vTEXCOORD中;
RAG的vec4;
void main()
{
//“平铺贴图”纹理示例
vec4数据=vec4(纹理(uMAP,vTEXCOORD));
//计算紫外线
vec2 uv=(data.xy*32.0/uATLAS_尺寸)+(vTEXCOORD*32.0/uATLAS_尺寸);
//试一下瓷砖
oFRAG=纹理(uATLAS,uv);
}
我相信这就是罪魁祸首:
vec2 uv=(data.xy*32.0/uATLAS_尺寸)+(vTEXCOORD*32.0/uATLAS_尺寸);
这里的公式是uv=(平铺xy指数*平铺大小)+(texcoord*平铺大小)
,其中:
是顶点uv(标准[0,1]、[0,0]、[1,0]、[1,1])texcoord
是tile集合中tile的X,Y坐标tile\u xy\u索引
是tileset中一个tile的规格化大小tile\u size
texcoord=(0,0)
,tile\u xy\u index=(7,7)
,tile\u size=(32/1024,32/1024)
,那么这个片段的UV应该是(0.21875,0.21875)
,如果texcoord=(1,1)
,那么它应该是(0.25,0.25)
。这些值对我来说似乎是正确的,为什么它们会产生错误的结果,以及如何修复它?
以下是一些额外的上下文:
- 平铺贴图纹理(夸张的颜色):
- 预期结果(减去网格线):
- 实际结果:
代码将这两行中的3个内容合并在一起
// sample "tile map" texture
vec4 data = vec4(texture(uMAP, vTEXCOORD));
// calculate UV
vec2 uv = (data.xy * 32.0 / uATLAS_SIZE) + (vTEXCOORD * 32.0 / uATLAS_SIZE);
// sample the tileset
第一个,对于您正在绘制的整个四边形,将覆盖整个平铺贴图。那可能不是你想要的。通常,使用tilemap的应用程序希望显示它的一部分,而不是全部
第二个问题是第二行需要知道一个平铺将覆盖多少像素,而不是一个平铺是多少像素。换句话说,如果您有一个32x32平铺,并且您以4x4像素绘制它,那么您的纹理坐标需要在该平铺上以4像素(而不是32像素)从0.0变为1.0
第三个问题是除以32不会穿过32像素的平铺,除非纹理上有32个平铺。假设您有一个32x32像素的平铺,但平铺集中有8x4个平铺。您需要从0到1跨越1/8和1/4,而不是跨越1/32
它有效地使用了2个矩阵。绘制四边形可以旋转、缩放、3D投影等,但是对于平铺贴图来说,通常的做法是绘制一个覆盖画布的四边形
第二个是纹理矩阵(或瓷砖矩阵),其中每个单元为1块瓷砖。因此,给定一个0到1的四边形,计算一个矩阵,将该四边形展开并旋转到上面的四边形上
假设你不旋转,你仍然需要决定在四边形上画多少块瓷砖。如果要在四边形上放置4个平铺,向下放置3个平铺,则应将比例设置为x=4和y=3
这样,每个磁贴在其自己的空间中都会自动从0变为1。或者换一种说法,平铺2x7从U中的2.03.0和V中的7.08.0开始。然后,我们可以从地图平铺2,7中查找,并使用fract
在平铺在四元空间中占据的空间中覆盖该平铺
const vs=`#版本300 es
精密中泵浮子;
统一mat4视图;
均匀mat4反射;
统一mat4模型;
均匀mat4-uTEXMATRIX;
vec4位置中的布局(位置=0);
vec4 aTEXCOORD中的布局(位置=1);
出vec2 vTEXCOORD;
void main()
{
vTEXCOORD=(uTEXMATRIX*aTEXCOORD).xy;
gl_位置=拔出*视图*模型*位置;
}
`;
常数fs=`#版本300 es
精密中泵浮子;
精密医疗泵usampler2D;
统一的usampler2D uMAP;
均匀采样;
均匀vec2 uTILESET_大小;//瓷砖组上下有多少瓷砖
在vec2 vTEXCOORD中;
RAG的vec4;
void main()
{
//vTEXCOORD的整数部分是tilemap坐标
ivec2马库德=ivec2(vTEXCOORD);
uvec4数据=texelFetch(uMAP,mapCoord,0);
//vTEXCOORD的分数部分是瓷砖上的UV
vec2 texcoord=分形(vTEXCOORD);
vec2uv=(vec2(data.xy)+texcoord)/uTILESET_大小;
//试一下瓷砖
oFRAG=纹理(uATLAS,uv);
}
`;
常数tileWidth=32;
常数tileHeight=32;
常数tilesAcross=8;
常数tilesDown=4;
常数m4=twgl.m4;
const gl=document.querySelector('canvas').getContext('webgl2');
如果(!gl)警报('需要WebGL2');
//编译着色器、链接、查找位置
const programInfo=twgl.createProgramInfo(gl[vs,fs]);
//gl.createBuffer、bindBuffer、bufferData
const bufferInfo=twgl.createBufferInfoFromArrays(gl{
位置:{
NUM组件:2,