如何扭曲着色器矩阵以匹配 3d 场景中的等距透视图?
How can I warp a shader matrix to match isometric perspective in a 3d scene?
我正在将着色器作为纹理应用到等距场景中的平面。该平面以 x、z 维度平放。我无法让着色器模式与场景中的等距透视相匹配。
这是一个示例,其中着色器通过将方向作为统一传递来随平面(如常规纹理)旋转。
这是着色器纹理的“2d”(正交)投影:
var TWO_PI = Math.PI * 2;
var PI = Math.PI;
var width = window.innerHeight - 50;
var height = window.innerHeight - 50;
var aspect = width / height;
var planeSize = width * 0.75;
var clock = new THREE.Clock();
var camera, scene, renderer;
var plane, geom_plane, mat_plane;
function init() {
// ---------- scene
scene = new THREE.Scene();
// ---------- plane
var plane_w = planeSize;
var plane_h = planeSize;
var geom_plane = new THREE.PlaneGeometry(plane_w,
plane_h,
0);
var mat_plane = new THREE.MeshBasicMaterial({
color: 0xffff00,
side: THREE.DoubleSide
});
var shaderMaterial_plane = new THREE.ShaderMaterial({
uniforms: {
u_resolution: {
value: new THREE.Vector2(planeSize, planeSize)
},
u_rotation_x: {
value: performance.now() * 0.001
},
u_rotation_y: {
value: performance.now() * 0.001
}
},
vertexShader: document.getElementById('vertexshader').textContent,
fragmentShader: document.getElementById('fragmentshader').textContent,
blending: THREE.NormalBlending,
depthTest: true,
transparent: true
});
plane = new THREE.Mesh(geom_plane, shaderMaterial_plane);
scene.add(plane);
// ---------- cam
camera = new THREE.OrthographicCamera(width / -2, width / 2, height / 2, height / -2, 1, 5000);
camera.position.set(0, 0, planeSize);
camera.lookAt(scene.position);
// ---------- renderer
renderer = new THREE.WebGLRenderer({
antialias: false,
alpha: true
});
renderer.setSize(width, height);
renderer.setClearColor(0x000000);
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
var time = performance.now() * 0.001;
plane.material.uniforms.u_rotation_x.value = Math.sin(time * 0.2);
plane.material.uniforms.u_rotation_y.value = Math.cos(time * 0.2);
var delta = clock.getDelta();
render();
}
function render() {
renderer.render(scene, camera);
}
init();
animate();
<script type="x-shader/x-vertex" id="vertexshader">
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
</script>
<script type="x-shader/x-fragment" id="fragmentshader">
uniform vec2 u_resolution; // Canvas size (width,height)
uniform float u_rotation_x;
uniform float u_rotation_y;
mat2 rotate2d(vec2 _angles){
return mat2(_angles.x,
-_angles.x,
_angles.y,
_angles.y);
}
float map(float value, float min1, float max1, float min2, float max2) {
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
vec3 color = vec3(1.0,1.0,1.0);
float gradientLength = 0.2;
float t = 18.;
// move matrix in order to set rotation pivot point to center
st -= vec2(0.5);
// rotate
vec2 u_rotation = vec2(u_rotation_x, u_rotation_y);
st = rotate2d(u_rotation) * st;
// move matrix back
st += vec2(0.5);
// apply gradient pattern
vec2 p = vec2(floor(gl_FragCoord.x), floor(gl_FragCoord.y));
float pp = clamp(gl_FragCoord.y,-0.5,st.y);
float val = mod((pp + t), gradientLength);
float alpha = map(val, 0.0, gradientLength, 1.0, 0.0);
gl_FragColor = vec4(color,alpha);
}
</script>
<div id="threejs_canvas"></div>
<script src="https://threejs.org/build/three.min.js"></script>
这里是在等距平面上 space(旋转相同):
var TWO_PI = Math.PI * 2;
var PI = Math.PI;
var width = window.innerHeight - 50;
var height = window.innerHeight - 50;
var aspect = width / height;
var canvasCubeSize = width;
var clock = new THREE.Clock();
var camera, scene, renderer;
var wire_cube;
var plane, geom_plane, mat_plane;
function init() {
// ---------- scene
scene = new THREE.Scene();
// ---------- wire cube
var wire_geometry = new THREE.BoxGeometry(canvasCubeSize / 2, canvasCubeSize / 2, canvasCubeSize / 2);
var wire_material = new THREE.MeshBasicMaterial({
wireframe: true,
color: 0xff0000
});
wire_cube = new THREE.Mesh(wire_geometry, wire_material);
scene.add(wire_cube);
// ---------- plane
var plane_w = canvasCubeSize / 2;
var plane_h = plane_w;
var geom_plane = new THREE.PlaneGeometry(plane_w,
plane_h,
0);
var mat_plane = new THREE.MeshBasicMaterial({
color: 0xffff00,
side: THREE.DoubleSide
});
var shaderMaterial_plane = new THREE.ShaderMaterial({
uniforms: {
u_time: {
value: 1.0
},
u_resolution: {
value: new THREE.Vector2(canvasCubeSize, canvasCubeSize)
},
u_rotation_x: {
value: wire_cube.rotation.y
},
u_rotation_y: {
value: wire_cube.rotation.y
}
},
vertexShader: document.getElementById('vertexshader').textContent,
fragmentShader: document.getElementById('fragmentshader').textContent,
blending: THREE.NormalBlending,
depthTest: true,
transparent: true
});
plane = new THREE.Mesh(geom_plane, shaderMaterial_plane);
plane.rotation.x = -PI / 2;
wire_cube.add(plane);
// ---------- cam
camera = new THREE.OrthographicCamera(width / -2, width / 2, height / 2, height / -2, 1, 5000);
camera.position.set(canvasCubeSize, canvasCubeSize, canvasCubeSize);
camera.lookAt(scene.position);
// ---------- renderer
renderer = new THREE.WebGLRenderer({
antialias: false,
alpha: true
});
renderer.setSize(width, height);
renderer.setClearColor(0x000000);
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
var time = performance.now() * 0.001;
wire_cube.rotation.y = time * 0.2;
if (wire_cube.rotation.y >= TWO_PI) {
wire_cube.rotation.y -= TWO_PI;
}
plane.material.uniforms.u_time.value = time * 0.005;
plane.material.uniforms.u_rotation_x.value = Math.sin(wire_cube.rotation.y);
plane.material.uniforms.u_rotation_y.value = Math.cos(wire_cube.rotation.y);
var delta = clock.getDelta();
render();
}
function render() {
renderer.render(scene, camera);
}
init();
animate();
<script type="x-shader/x-vertex" id="vertexshader">
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
</script>
<script type="x-shader/x-fragment" id="fragmentshader">
uniform vec2 u_resolution; // Canvas size (width,height)
uniform float u_rotation_x;
uniform float u_rotation_y;
mat2 rotate2d(vec2 _angles){
return mat2(_angles.x,
-_angles.x,
_angles.y,
_angles.y);
}
float map(float value, float min1, float max1, float min2, float max2) {
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
vec3 color = vec3(1.0,1.0,1.0);
float gradientLength = 0.2;
float t = 18.;
// move matrix in order to set rotation pivot point to center
st -= vec2(0.5);
// rotate
vec2 u_rotation = vec2(u_rotation_x, u_rotation_y);
st = rotate2d(u_rotation) * st;
// move matrix back
st += vec2(0.5);
// apply gradient pattern
vec2 p = vec2(floor(gl_FragCoord.x), floor(gl_FragCoord.y));
float pp = clamp(gl_FragCoord.y,-0.5,st.y);
float val = mod((pp + t), gradientLength);
float alpha = map(val, 0.0, gradientLength, 1.0, 0.0);
gl_FragColor = vec4(color,alpha);
}
</script>
<div id="threejs_canvas">
</div>
<script src="https://threejs.org/build/three.min.js"></script>
if snippet output is too small see here
旋转说明了着色器如何不模仿等轴测透视。请注意着色器图案如何在旋转时相对于平面的角不保持固定。
这是片段着色器:
uniform vec2 u_resolution; // canvas size (width,height)
uniform float u_rotation_x;
uniform float u_rotation_y;
mat2 rotate2d(vec2 _angles){
return mat2(_angles.x,
-_angles.x,
_angles.y,
_angles.y);
}
float map(float value, float min1, float max1, float min2, float max2) {
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
vec3 color = vec3(1.0,1.0,1.0);
float gradientLength = 0.2;
float t = 18.;
// move matrix in order to set rotation pivot point to center
st -= vec2(0.5);
// rotate
vec2 u_rotation = vec2(u_rotation_x, u_rotation_y);
st = rotate2d(u_rotation) * st;
// move matrix back
st += vec2(0.5);
// apply gradient pattern
vec2 p = vec2(floor(gl_FragCoord.x), floor(gl_FragCoord.y));
float pp = clamp(gl_FragCoord.y,-0.5,st.y);
float val = mod((pp + t), gradientLength);
float alpha = map(val, 0.0, gradientLength, 1.0, 0.0);
gl_FragColor = vec4(color,alpha);
}
有人可以帮助我了解如何 "warp" 着色器中的矩阵,以便在旋转时模拟等距平面的旋转 space 吗?
编辑:我想知道变形矩阵和应用精确旋转是否应该分成两个独立的问题?我正在尝试根据 0 将旋转速度更改为 TWO_PI 方向,但也许这是针对此示例的特定解决方案...
非常有趣的问题(+1)。如何将单位圆转换为椭圆并使用其内接的 90 度偏移基向量?
此处忽略矩阵数学 GL/GLSL/C++ 示例:
CPU 边画:
// GLSL Isometric view
float pan[2]={0.5,0.5};
float u[2]={1.0,0.0};
float v[2]={0.5,0.5};
const float deg=M_PI/180.0;
const float da=1.0*deg;;
static float a=0.0;
u[0]=1.0*cos(a);
u[1]=0.5*sin(a);
v[0]=1.0*cos(a+90.0*deg);
v[1]=0.5*sin(a+90.0*deg);
a+=da; if (a>=2.0*M_PI) a-=2.0*M_PI;
glUseProgram(prog_id);
id=glGetUniformLocation(prog_id,"zoom"); glUniform1f(id,0.5);
id=glGetUniformLocation(prog_id,"pan"); glUniform2fv(id,1,pan);
id=glGetUniformLocation(prog_id,"u"); glUniform2fv(id,1,u);
id=glGetUniformLocation(prog_id,"v"); glUniform2fv(id,1,v);
glBegin(GL_QUADS);
glColor3f(1,1,1);
float x=0.0,y=0.0;
glVertex2f(x+0.0,y+0.0);
glVertex2f(x+0.0,y+1.0);
glVertex2f(x+1.0,y+1.0);
glVertex2f(x+1.0,y+0.0);
glEnd();
glUseProgram(0);
顶点:
#version 120
// Vertex
uniform vec2 pan=vec2(0.5,0.5); // origin [grid cells]
uniform float zoom=0.5; // scale
uniform vec2 u=vec2(1.0,0.0); // basis vectors
uniform vec2 v=vec2(0.5,0.5);
varying vec2 pos; // position [grid cells]
void main()
{
pos=gl_Vertex.xy;
vec2 a=zoom*(gl_Vertex.xy-pan);
gl_Position=vec4((u*a.x)+(v*a.y),0.0,1.0);
}
片段:
#version 120
// Fragment
varying vec2 pos; // texture coordinate
void main()
{
float a;
a=2.0*(pos.x+pos.y);
a-=floor(a);
gl_FragColor=vec4(a,a,a,1.0);
}
最后预览:
重要的东西在顶点着色器中。因此,只需使用 u,v
基向量即可通过公式从 world 2D 转换为 Isometric 2D 位置:
isometric = world.x*u + world.y*v
剩下的就是 pan
和 zoom
...
事实证明解决方案非常简单。我发现我的问题是 dupe,原始问题包含一个说明解决方案的示例(也在下面解释)。
在我的原始代码中,我使用 vec2 st = gl_FragCoord.xy/u_resolution.xy;
获取像素 xy 位置,这是全局 window 位置。在frag shader中获取相对uv位置需要将uv表面的宽高传入vertex shader才能使用threejs得到归一化的像素位置predefined vec3 position
:
uniform float width;
uniform float height;
varying float x;
varying float y;
void main() {
// Get normalized position
x = position.x / width;
y = position.y / height;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
然后它们就可以在片段着色器中使用了:
varying float x; // -0.5 to 0.5
varying float y; // -0.5 to 0.5
void main() {
gl_FragColor = vec4(x, y, 0.0, 1.0);
}
我正在将着色器作为纹理应用到等距场景中的平面。该平面以 x、z 维度平放。我无法让着色器模式与场景中的等距透视相匹配。
这是一个示例,其中着色器通过将方向作为统一传递来随平面(如常规纹理)旋转。
这是着色器纹理的“2d”(正交)投影:
var TWO_PI = Math.PI * 2;
var PI = Math.PI;
var width = window.innerHeight - 50;
var height = window.innerHeight - 50;
var aspect = width / height;
var planeSize = width * 0.75;
var clock = new THREE.Clock();
var camera, scene, renderer;
var plane, geom_plane, mat_plane;
function init() {
// ---------- scene
scene = new THREE.Scene();
// ---------- plane
var plane_w = planeSize;
var plane_h = planeSize;
var geom_plane = new THREE.PlaneGeometry(plane_w,
plane_h,
0);
var mat_plane = new THREE.MeshBasicMaterial({
color: 0xffff00,
side: THREE.DoubleSide
});
var shaderMaterial_plane = new THREE.ShaderMaterial({
uniforms: {
u_resolution: {
value: new THREE.Vector2(planeSize, planeSize)
},
u_rotation_x: {
value: performance.now() * 0.001
},
u_rotation_y: {
value: performance.now() * 0.001
}
},
vertexShader: document.getElementById('vertexshader').textContent,
fragmentShader: document.getElementById('fragmentshader').textContent,
blending: THREE.NormalBlending,
depthTest: true,
transparent: true
});
plane = new THREE.Mesh(geom_plane, shaderMaterial_plane);
scene.add(plane);
// ---------- cam
camera = new THREE.OrthographicCamera(width / -2, width / 2, height / 2, height / -2, 1, 5000);
camera.position.set(0, 0, planeSize);
camera.lookAt(scene.position);
// ---------- renderer
renderer = new THREE.WebGLRenderer({
antialias: false,
alpha: true
});
renderer.setSize(width, height);
renderer.setClearColor(0x000000);
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
var time = performance.now() * 0.001;
plane.material.uniforms.u_rotation_x.value = Math.sin(time * 0.2);
plane.material.uniforms.u_rotation_y.value = Math.cos(time * 0.2);
var delta = clock.getDelta();
render();
}
function render() {
renderer.render(scene, camera);
}
init();
animate();
<script type="x-shader/x-vertex" id="vertexshader">
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
</script>
<script type="x-shader/x-fragment" id="fragmentshader">
uniform vec2 u_resolution; // Canvas size (width,height)
uniform float u_rotation_x;
uniform float u_rotation_y;
mat2 rotate2d(vec2 _angles){
return mat2(_angles.x,
-_angles.x,
_angles.y,
_angles.y);
}
float map(float value, float min1, float max1, float min2, float max2) {
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
vec3 color = vec3(1.0,1.0,1.0);
float gradientLength = 0.2;
float t = 18.;
// move matrix in order to set rotation pivot point to center
st -= vec2(0.5);
// rotate
vec2 u_rotation = vec2(u_rotation_x, u_rotation_y);
st = rotate2d(u_rotation) * st;
// move matrix back
st += vec2(0.5);
// apply gradient pattern
vec2 p = vec2(floor(gl_FragCoord.x), floor(gl_FragCoord.y));
float pp = clamp(gl_FragCoord.y,-0.5,st.y);
float val = mod((pp + t), gradientLength);
float alpha = map(val, 0.0, gradientLength, 1.0, 0.0);
gl_FragColor = vec4(color,alpha);
}
</script>
<div id="threejs_canvas"></div>
<script src="https://threejs.org/build/three.min.js"></script>
这里是在等距平面上 space(旋转相同):
var TWO_PI = Math.PI * 2;
var PI = Math.PI;
var width = window.innerHeight - 50;
var height = window.innerHeight - 50;
var aspect = width / height;
var canvasCubeSize = width;
var clock = new THREE.Clock();
var camera, scene, renderer;
var wire_cube;
var plane, geom_plane, mat_plane;
function init() {
// ---------- scene
scene = new THREE.Scene();
// ---------- wire cube
var wire_geometry = new THREE.BoxGeometry(canvasCubeSize / 2, canvasCubeSize / 2, canvasCubeSize / 2);
var wire_material = new THREE.MeshBasicMaterial({
wireframe: true,
color: 0xff0000
});
wire_cube = new THREE.Mesh(wire_geometry, wire_material);
scene.add(wire_cube);
// ---------- plane
var plane_w = canvasCubeSize / 2;
var plane_h = plane_w;
var geom_plane = new THREE.PlaneGeometry(plane_w,
plane_h,
0);
var mat_plane = new THREE.MeshBasicMaterial({
color: 0xffff00,
side: THREE.DoubleSide
});
var shaderMaterial_plane = new THREE.ShaderMaterial({
uniforms: {
u_time: {
value: 1.0
},
u_resolution: {
value: new THREE.Vector2(canvasCubeSize, canvasCubeSize)
},
u_rotation_x: {
value: wire_cube.rotation.y
},
u_rotation_y: {
value: wire_cube.rotation.y
}
},
vertexShader: document.getElementById('vertexshader').textContent,
fragmentShader: document.getElementById('fragmentshader').textContent,
blending: THREE.NormalBlending,
depthTest: true,
transparent: true
});
plane = new THREE.Mesh(geom_plane, shaderMaterial_plane);
plane.rotation.x = -PI / 2;
wire_cube.add(plane);
// ---------- cam
camera = new THREE.OrthographicCamera(width / -2, width / 2, height / 2, height / -2, 1, 5000);
camera.position.set(canvasCubeSize, canvasCubeSize, canvasCubeSize);
camera.lookAt(scene.position);
// ---------- renderer
renderer = new THREE.WebGLRenderer({
antialias: false,
alpha: true
});
renderer.setSize(width, height);
renderer.setClearColor(0x000000);
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
var time = performance.now() * 0.001;
wire_cube.rotation.y = time * 0.2;
if (wire_cube.rotation.y >= TWO_PI) {
wire_cube.rotation.y -= TWO_PI;
}
plane.material.uniforms.u_time.value = time * 0.005;
plane.material.uniforms.u_rotation_x.value = Math.sin(wire_cube.rotation.y);
plane.material.uniforms.u_rotation_y.value = Math.cos(wire_cube.rotation.y);
var delta = clock.getDelta();
render();
}
function render() {
renderer.render(scene, camera);
}
init();
animate();
<script type="x-shader/x-vertex" id="vertexshader">
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
</script>
<script type="x-shader/x-fragment" id="fragmentshader">
uniform vec2 u_resolution; // Canvas size (width,height)
uniform float u_rotation_x;
uniform float u_rotation_y;
mat2 rotate2d(vec2 _angles){
return mat2(_angles.x,
-_angles.x,
_angles.y,
_angles.y);
}
float map(float value, float min1, float max1, float min2, float max2) {
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
vec3 color = vec3(1.0,1.0,1.0);
float gradientLength = 0.2;
float t = 18.;
// move matrix in order to set rotation pivot point to center
st -= vec2(0.5);
// rotate
vec2 u_rotation = vec2(u_rotation_x, u_rotation_y);
st = rotate2d(u_rotation) * st;
// move matrix back
st += vec2(0.5);
// apply gradient pattern
vec2 p = vec2(floor(gl_FragCoord.x), floor(gl_FragCoord.y));
float pp = clamp(gl_FragCoord.y,-0.5,st.y);
float val = mod((pp + t), gradientLength);
float alpha = map(val, 0.0, gradientLength, 1.0, 0.0);
gl_FragColor = vec4(color,alpha);
}
</script>
<div id="threejs_canvas">
</div>
<script src="https://threejs.org/build/three.min.js"></script>
if snippet output is too small see here
旋转说明了着色器如何不模仿等轴测透视。请注意着色器图案如何在旋转时相对于平面的角不保持固定。
这是片段着色器:
uniform vec2 u_resolution; // canvas size (width,height)
uniform float u_rotation_x;
uniform float u_rotation_y;
mat2 rotate2d(vec2 _angles){
return mat2(_angles.x,
-_angles.x,
_angles.y,
_angles.y);
}
float map(float value, float min1, float max1, float min2, float max2) {
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
vec3 color = vec3(1.0,1.0,1.0);
float gradientLength = 0.2;
float t = 18.;
// move matrix in order to set rotation pivot point to center
st -= vec2(0.5);
// rotate
vec2 u_rotation = vec2(u_rotation_x, u_rotation_y);
st = rotate2d(u_rotation) * st;
// move matrix back
st += vec2(0.5);
// apply gradient pattern
vec2 p = vec2(floor(gl_FragCoord.x), floor(gl_FragCoord.y));
float pp = clamp(gl_FragCoord.y,-0.5,st.y);
float val = mod((pp + t), gradientLength);
float alpha = map(val, 0.0, gradientLength, 1.0, 0.0);
gl_FragColor = vec4(color,alpha);
}
有人可以帮助我了解如何 "warp" 着色器中的矩阵,以便在旋转时模拟等距平面的旋转 space 吗?
编辑:我想知道变形矩阵和应用精确旋转是否应该分成两个独立的问题?我正在尝试根据 0 将旋转速度更改为 TWO_PI 方向,但也许这是针对此示例的特定解决方案...
非常有趣的问题(+1)。如何将单位圆转换为椭圆并使用其内接的 90 度偏移基向量?
此处忽略矩阵数学 GL/GLSL/C++ 示例:
CPU 边画:
// GLSL Isometric view
float pan[2]={0.5,0.5};
float u[2]={1.0,0.0};
float v[2]={0.5,0.5};
const float deg=M_PI/180.0;
const float da=1.0*deg;;
static float a=0.0;
u[0]=1.0*cos(a);
u[1]=0.5*sin(a);
v[0]=1.0*cos(a+90.0*deg);
v[1]=0.5*sin(a+90.0*deg);
a+=da; if (a>=2.0*M_PI) a-=2.0*M_PI;
glUseProgram(prog_id);
id=glGetUniformLocation(prog_id,"zoom"); glUniform1f(id,0.5);
id=glGetUniformLocation(prog_id,"pan"); glUniform2fv(id,1,pan);
id=glGetUniformLocation(prog_id,"u"); glUniform2fv(id,1,u);
id=glGetUniformLocation(prog_id,"v"); glUniform2fv(id,1,v);
glBegin(GL_QUADS);
glColor3f(1,1,1);
float x=0.0,y=0.0;
glVertex2f(x+0.0,y+0.0);
glVertex2f(x+0.0,y+1.0);
glVertex2f(x+1.0,y+1.0);
glVertex2f(x+1.0,y+0.0);
glEnd();
glUseProgram(0);
顶点:
#version 120
// Vertex
uniform vec2 pan=vec2(0.5,0.5); // origin [grid cells]
uniform float zoom=0.5; // scale
uniform vec2 u=vec2(1.0,0.0); // basis vectors
uniform vec2 v=vec2(0.5,0.5);
varying vec2 pos; // position [grid cells]
void main()
{
pos=gl_Vertex.xy;
vec2 a=zoom*(gl_Vertex.xy-pan);
gl_Position=vec4((u*a.x)+(v*a.y),0.0,1.0);
}
片段:
#version 120
// Fragment
varying vec2 pos; // texture coordinate
void main()
{
float a;
a=2.0*(pos.x+pos.y);
a-=floor(a);
gl_FragColor=vec4(a,a,a,1.0);
}
最后预览:
重要的东西在顶点着色器中。因此,只需使用 u,v
基向量即可通过公式从 world 2D 转换为 Isometric 2D 位置:
isometric = world.x*u + world.y*v
剩下的就是 pan
和 zoom
...
事实证明解决方案非常简单。我发现我的问题是 dupe,原始问题包含一个说明解决方案的示例(也在下面解释)。
在我的原始代码中,我使用 vec2 st = gl_FragCoord.xy/u_resolution.xy;
获取像素 xy 位置,这是全局 window 位置。在frag shader中获取相对uv位置需要将uv表面的宽高传入vertex shader才能使用threejs得到归一化的像素位置predefined vec3 position
:
uniform float width;
uniform float height;
varying float x;
varying float y;
void main() {
// Get normalized position
x = position.x / width;
y = position.y / height;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
然后它们就可以在片段着色器中使用了:
varying float x; // -0.5 to 0.5
varying float y; // -0.5 to 0.5
void main() {
gl_FragColor = vec4(x, y, 0.0, 1.0);
}