将纹理映射到 THREE.Points

Mapping texture to THREE.Points

我正在尝试将一个纹理(与立方体的一侧相同)映射到多个点,以便一个点用纹理的一部分着色,所有点一起构成一个完整的图像。

为此,我有一个自定义着色器,它尝试将点位置映射到纹理,如下所示:

var uniform = THREE.TextureShader.uniforms();
uniform.texture.value = texture;
uniform.bbMin.value = new THREE.Vector3(-2.5, -2.5, 0); //THREE.Points Box3 min value
uniform.bbMax.value = new THREE.Vector3(2.5, 2.5, 0); //THREE.Points Box3 max value

//Shader

"vec3 p = (position - bbMin) / (bbMax - bbMin);",
/*This should give me fraction between 0 and 1 to match part of texture but it is not*/
"vColor = texture2D(texture, p.xy).rgb;",

用于测试的 Codepen 是 here

知道如何正确计算吗?

想要的结果应该是这样的,只是瓷砖之间会有 space。

50000 个点或 50000 个平面都是一样的,您需要某种方法来传递每个点或每个平面的数据,以便您计算纹理坐标。我个人会选择平面,因为您可以旋转、缩放和翻转平面,而使用 POINTS 无法做到这一点。

在任何情况下,尽管有无数种方法可以做到,所以您真的要选择一种。对于点,每个点获得 1 "chunk" 数据,其中 "chunk" 我的意思是来自您设置的所有属性的所有数据。

因此,例如,您可以设置一个属性,其中包含一个 X、Y 位置,表示您要绘制精灵的哪一部分。在您的示例中,您将其划分为 6x6,因此创建一个值为 0-5、0-5 的 vec2 属性,选择精灵的部分。

将其传递到顶点着色器,然后您可以在那里做一些数学运算或直接将其传递到片段着色器。假设您直接将它传递给片段着色器。

gl_PointCoord 是 POINT 从 0 到 1 的纹理坐标所以

varying vec2 segment;  // the segment of the sprite 0-5x, 0-5y

vec2 uv = (v_segment + gl_PointCoord) / 6.0;    
vec4 color = texture2D(yourTextureUniform, uv);

似乎可行。

那个硬编码为 6x6。通过将其传递给

将其更改为 NxM
varying vec2 segment;     // the segment of the sprite 
uniform vec2 numSegments; // number of segments across and down sprite

vec2 uv = (v_segment + gl_PointCoord) / numSegments    
vec4 color = texture2D(yourTextureUniform, uv);

示例:

"use strict";
var gl = twgl.getWebGLContext(document.getElementById("c"));
var programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);

// make a rainbow circle texture from a 2d canvas as it's easier than downloading
var ctx = document.createElement("canvas").getContext("2d");
ctx.canvas.width = 128;
ctx.canvas.height = 128;
var gradient = ctx.createRadialGradient(64,64,60,64,64,0);
for (var i = 0; i <= 12; ++i) {
  gradient.addColorStop(i / 12,"hsl(" + (i / 12 * 360) + ",100%,50%");
}
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 128, 128);

// make points and segment data
var numSegmentsAcross = 6;
var numSegmentsDown = 5;
var positions = [];
var segments = [];
for (var y = 0; y < numSegmentsDown; ++y) {
  for (var x = 0; x < numSegmentsAcross; ++x) {
    positions.push(x / (numSegmentsAcross - 1) * 2 - 1, y / (numSegmentsDown - 1) * 2 - 1);
    segments.push(x, y);
  }
}   

var arrays = {
  position: { size: 2, data: positions },
  segment: { size: 2, data: segments },
};
var bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
var tex = twgl.createTexture(gl, { src: ctx.canvas });

var uniforms = {
  u_numSegments: [numSegmentsAcross, numSegmentsDown],
  u_texture: tex,
};

gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
twgl.drawBufferInfo(gl, gl.POINTS, bufferInfo);
canvas { border: 1px solid black; }
  <script id="vs" type="notjs">
attribute vec4 position;
attribute vec2 segment;

varying vec2 v_segment;

void main() {
  gl_Position = position;
  v_segment = segment;  
  gl_PointSize = 20.0;
}
  </script>
  <script id="fs" type="notjs">
precision mediump float;

varying vec2 v_segment;
uniform vec2 u_numSegments;
uniform sampler2D u_texture;

void main() {
  vec2 uv = (v_segment + vec2(gl_PointCoord.x, 1.0 - gl_PointCoord.y)) / u_numSegments;
  gl_FragColor = texture2D(u_texture, uv);
}
  </script>
  <script src="https://twgljs.org/dist/twgl.min.js"></script>
<canvas id="c"></canvas>