将纹理映射到THREE.Points

时间:2016-04-24 12:09:02

标签: three.js webgl

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

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

;; Signature: mix-rows(rows1 rows2)
;; Purpose: returns a list of rows of the cartesian product of both rows 
;; Type: [ List(Row) * List(Row) -> List(Row) ]
;; Tests:
;; (mix-rows (list '(10 11) '(20 21)) (list '('u 'v) '('p 'q)))
;; ==> ((10 11 'u 'v)
;;      (10 11 'p 'q)
;;      (20 21 'u 'v)
;;      (20 21 'p 'q))
(define mix-rows
  (lambda (rows1 rows2)
    (map (lambda (row1)
           (foldr (lambda (row2)
                  (append row1 row2))
                  '()
                rows2))
         rows1)))

用于测试的Codepen是here

任何想法如何正确计算?

期望的结果将是这样的,只有瓷砖之间会有空间。

enter image description here

1 个答案:

答案 0 :(得分:2)

50000点或50000个平面完全相同,你需要某种方法来传递每个点或每个平面的数据,以便计算纹理坐标。就个人而言,我选择飞机是因为你可以旋转,缩放和翻转飞机,你不能用点来做到这一点。

无论如何,虽然有很多种方法可以让你选择一个。对于点数,每点获得1“大块”数据,其中“块”是指您设置的所有属性中的所有数据。

因此,例如,你可以设置一个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>