Я пытаюсь смоделировать глобус в javascript с помощью WebGL и начал делать это, следуя этому руководству .
Текстура, отображаемая на сетке, должна иметь минимальное искажение.Чтобы избежать искаженной области, расстояния и формы, я использую прерванную синусоидальную проекцию карты вместо равноугольной.Для тестирования я использую текстуру земли, найденную на этом сайте .
Проблема, с которой я сталкиваюсь, состоит в том, что вершины отображаются за пределами ожидаемых границ текстуры.Чем выше количество вершин I, тем меньше видимая «внешняя» текстура (слева направо счетчики широты и долготы удваиваются с каждым шагом):
Формула проекции должна быть правильной, я смог создать файл трафарета, чтобы убедиться, что в c # tho я не настолько привык к js:
Итак, мой вопрос: как улучшить приближение сферы и не показывать пиксели за пределами области предполагаемой текстуры?
Соответствующий код:
// the projection used in the tutorial
function project_equirectangular(xangle, yangle) {
return [xangle, yangle];
}
// the projection I intend to use to minimize distortion
function project_sinusoidial(xangle, yangle, segments) {
var segment = Math.round(segments*yangle-1/2)+1;
var segment_middle = (segment-1/2)/segments;
return [
(yangle-segment_middle)*Math.cos(Math.PI*(1/2-xangle))+segment_middle,
xangle
];
}
// creating the spherical mesh for the globe
function initBuffers() {
var M = 6;
var N = 2*M;
var radius = 1;
var vertexPositionData = [];
var normalData = [];
var textureCoordData = [];
for (var m=0; m <= M; m++) {
var theta = Math.PI * m / M;
var sinTheta = Math.sin(theta);
var cosTheta = Math.cos(theta);
for (var n=0; n <= N; n++) {
var phi = 2 * Math.PI * n / N;
var sinPhi = Math.sin(phi);
var cosPhi = Math.cos(phi);
var x = cosPhi * sinTheta;
var y = cosTheta;
var z = sinPhi * sinTheta;
var proj = project_sinusoidial(m/M, n/N, 12);
var u = 1 - proj[0];
var v = 1 - proj[1];
normalData.push(x);
normalData.push(y);
normalData.push(z);
textureCoordData.push(u);
textureCoordData.push(v);
vertexPositionData.push(radius * x);
vertexPositionData.push(radius * y);
vertexPositionData.push(radius * z);
}
}
var indexData = [];
for (var m=0; m < M; m++) {
for (var n=0; n < N; n++) {
var first = (m * (N + 1)) + n;
var second = first + N + 1;
indexData.push(first);
indexData.push(second);
indexData.push(first + 1);
indexData.push(second);
indexData.push(second + 1);
indexData.push(first + 1);
}
}
planetVertexNormalBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, planetVertexNormalBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normalData), gl.STATIC_DRAW);
planetVertexNormalBuffer.itemSize = 3;
planetVertexNormalBuffer.numItems = normalData.length / 3;
planetVertexTextureCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, planetVertexTextureCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordData), gl.STATIC_DRAW);
planetVertexTextureCoordBuffer.itemSize = 2;
planetVertexTextureCoordBuffer.numItems = textureCoordData.length / 2;
planetVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, planetVertexPositionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexPositionData), gl.STATIC_DRAW);
planetVertexPositionBuffer.itemSize = 3;
planetVertexPositionBuffer.numItems = vertexPositionData.length / 3;
planetVertexIndexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, planetVertexIndexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexData), gl.STATIC_DRAW);
planetVertexIndexBuffer.itemSize = 1;
planetVertexIndexBuffer.numItems = indexData.length;
}