2017-02-19 6 views
4

У меня есть проблема с мерцанием THREE.Points в зависимости от их УФ координат, как показано в следующих codepen: http://codepen.io/anon/pen/qrdQeY?editors=0010мерцанием THREE.Points на основании положения камеры и текстурных координат, но только на Nvidia карты

код в codepen конденсируется вниз как можно больше (171 строк), но суммировать то, что я делаю:

  • рендеринга спрайтов с использованием THREE.Points
  • BufferGeometry содержит индекс spritesheet и положение для каждого спрайта
  • RawShaderMaterial с пользовательскими вершинных и пиксельных шейдеров для поиска до УФ-координаты спрайта для данного индекса
  • 128x128px spritesheet с 4x4 клеток содержит спрайты

Вот код:

/// FRAGMENT SHADER =========================================================== 
const fragmentShader = ` 
precision highp float; 

uniform sampler2D spritesheet; 

// number of spritesheet subdivisions both vertically and horizontally 
// e.g. for a 4x4 spritesheet this number is 4 
uniform float spritesheetSubdivisions; 

// vParams[i].x = sprite index 
// vParams[i].z = sprite alpha 
varying vec3 vParams; 

/** 
* Maps regular UV coordinates spanning the entire spritesheet 
* to a specific sprite within the spritesheet based on the given index, 
* which points into a spritesheel cell (depending on spritesheetSubdivisions 
* and assuming that the spritesheet is regular and square). 
*/ 
vec2 spriteIndexToUV(float idx, vec2 uv) { 
    float cols = spritesheetSubdivisions; 
    float rows = spritesheetSubdivisions; 

    float x = mod(idx, cols); 
    float y = floor(idx/cols); 

    return vec2(x/cols + uv.x/cols, 1.0 - (y/rows + (uv.y)/rows)); 
} 

void main() { 
    vec2 uv = spriteIndexToUV(vParams.x, gl_PointCoord); 
    vec4 diffuse = texture2D(spritesheet, uv); 

    float alpha = diffuse.a * vParams.z; 
    if (alpha < 0.5) discard; 

    gl_FragColor = vec4(diffuse.xyz, alpha); 
} 
` 

// VERTEX SHADER ============================================================== 
const vertexShader = ` 
precision highp float; 

uniform mat4 modelViewMatrix; 
uniform mat4 projectionMatrix; 
uniform float size; 
uniform float scale; 

attribute vec3 position; 
attribute vec3 params; // x = sprite index, y = unused, z = sprite alpha 
attribute vec3 color; 

varying vec3 vParams; 

void main() { 
    vParams = params; 

    vec4 mvPosition = modelViewMatrix * vec4(position, 1.0); 
    gl_Position = projectionMatrix * mvPosition; 
    gl_PointSize = size * (scale/- mvPosition.z); 
} 
` 

// THREEJS CODE =============================================================== 

const scene = new THREE.Scene(); 
const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000); 

const renderer = new THREE.WebGLRenderer({canvas: document.querySelector("#mycanvas")}); 
renderer.setSize(window.innerWidth, window.innerHeight); 
renderer.setClearColor(0xf0f0f0) 

const pointGeometry = new THREE.BufferGeometry() 
pointGeometry.addAttribute("position", new THREE.BufferAttribute(new Float32Array([ 
    -1.5, -1.5, 0, 
    -0.5, -1.5, 0, 
    0.5, -1.5, 0, 
    1.5, -1.5, 0, 

    -1.5, -0.5, 0, 
    -0.5, -0.5, 0, 
    0.5, -0.5, 0, 
    1.5, -0.5, 0, 

    -1.5, 0.5, 0, 
    -0.5, 0.5, 0, 
    0.5, 0.5, 0, 
    1.5, 0.5, 0, 

    -1.5, 1.5, 0, 
    -0.5, 1.5, 0, 
    0.5, 1.5, 0, 
    1.5, 1.5, 0, 
]), 3)) 

pointGeometry.addAttribute("params", new THREE.BufferAttribute(new Float32Array([ 
    0, 0, 1, // sprite index 0 (row 0, column 0) 
    1, 0, 1, // sprite index 1 (row 0, column 1) 
    2, 0, 1, // sprite index 2 (row 0, column 2) 
    3, 0, 1, // sprite index 3 (row 0, column 4) 

    4, 0, 1, // sprite index 4 (row 1, column 0) 
    5, 0, 1, // sprite index 5 (row 1, column 1) 
    6, 0, 1, // ... 
    7, 0, 1, 

    8, 0, 1, 
    9, 0, 1, 
    10, 0, 1, 
    11, 0, 1, 

    12, 0, 1, 
    13, 0, 1, 
    14, 0, 1, 
    15, 0, 1 
]), 3)) 

const img = document.querySelector("img") 
const texture = new THREE.TextureLoader().load(img.src); 

const pointMaterial = new THREE.RawShaderMaterial({ 
    transparent: true, 
    vertexShader: vertexShader, 
    fragmentShader: fragmentShader, 
    uniforms: { 
    spritesheet: { 
     type: "t", 
     value: texture 
    }, 
    spritesheetSubdivisions: { 
     type: "f", 
     value: 4 
    }, 
    size: { 
     type: "f", 
     value: 1 
    }, 
    scale: { 
     type: "f", 
     value: window.innerHeight/2 
    } 
    } 
}) 

const points = new THREE.Points(pointGeometry, pointMaterial) 
scene.add(points) 

const render = function (timestamp) { 
    requestAnimationFrame(render); 


    camera.position.z = 5 + Math.sin(timestamp/1000.0) 

    renderer.render(scene, camera); 
}; 

render(); 

// resize viewport 
window.addEventListener('resize', onWindowResize, false); 

function onWindowResize(){ 

    camera.aspect = window.innerWidth/window.innerHeight; 
    camera.updateProjectionMatrix(); 

    renderer.setSize(window.innerWidth, window.innerHeight); 

} 

Если у вас есть карта Nvidia, вы увидите мерцание трех спрайтов, когда камера перемещается вперед и назад по оси Z. На интегрированных графических чипах Intel проблема не возникает.

Я не уверен, как решить эту проблему. Поврежденные uv-координаты кажутся случайными. Я был бы благодарен за любые указатели.

+0

Интересно! Я могу подтвердить различное поведение (на настольном компьютере Macbook с Intel HD). Вы пытались использовать * highp * для шейдеров? Поскольку это * подсказка *, интерпретация по умолчанию может быть разной. Я не могу с легкостью сказать из вашего кода, в какой степени отображаются разные слои, поскольку они прозрачны, а также на стороне процессора, которая может быть связана между тремя группами. –

+0

Спасибо, что посмотрели! Спринты слегка визуализируются (z = 0,12 против z = 0 рельефа). Увеличение этого ничего не меняет. Также изменение свойства прозрачности материала на значение false не помогает мерцанию. Шейдеры используют highp, насколько я могу судить.Или есть что-то еще, что вам нужно сделать, кроме добавления «precision highp»? в верхней части шейдера? – Bunkerbewohner

+0

N/m мой последний комментарий относительно «highp», только что заметил, что шейдер, который я связал, использует «mediump». К сожалению, изменение этого параметра на «highp» тоже не помогает. – Bunkerbewohner

ответ

1

Расчеты mod()/floor() внутри вашей функции spriteIndexToUV() вызывают проблемы в определенных созвездиях (когда spriteindex является кратным spritesheetSubdivisions).

я мог бы исправить это настраивая COLS переменной с небольшим эпсилон:

vec2 spriteIndexToUV(float idx, vec2 uv) 
{ 
    float cols = spritesheetSubdivisions - 1e-6; // subtract epsilon 
    float rows = spritesheetSubdivisions; 

    float x = mod(idx, cols); 
    float y = floor(idx/cols); 

    return vec2(x/cols + uv.x/cols, 1.0 - (y/rows + (uv.y)/rows)); 
} 

PS: Это codepen материал действительно круто, не знал, что это существовало :-)

редактирования: это может быть даже лучше/понятнее написать это:

float cols = spritesheetSubdivisions; 
float rows = spritesheetSubdivisions; 

float y = floor ((idx+0.5)/cols); 
float x = idx - cols * y; 

Таким образом, мы продолжаем полностью от каких-либо критических ситуаций в работе пола - плюс мы избавимся от вызова мод().

Относительно того, почему floor (idx/4) иногда производит 0 вместо 1, когда idxдолжно быть ровно 4.0, можно только предположить, что varying vec3 vParams подвергается некоторой интерполяции, когда она идет от вершины-шейдера на стадии фрагмента-шейдера , что приводит к тому, что фрагмент-шейдер видит, например, 3.999999 вместо ровно 4.0.

+0

О, боже, наконец! Благодаря тонну! :-D Можете ли вы объяснить, что происходит? Не должно ли мода (4, 4) быть 0.0? – Bunkerbewohner

+0

Спасибо за добавление! Я собираюсь наградить вас щедростью, как только stackoverflow позволит мне. :) – Bunkerbewohner

Смежные вопросы