Шейдер массива проходов WebGL - PullRequest
3 голосов
/ 10 октября 2011

Я новичок в WebGL и сталкиваюсь с некоторыми проблемами с шейдерами. Я хочу сделать несколько источников света на сцене. Я искал в Интернете и знал, что в WebGL нельзя передавать массив в фрагментный шейдер, поэтому единственный способ - использовать текстуру. Вот проблема, которую я не могу понять.

Сначала я создаю текстуру 32x32, используя следующий код:

var pix = [];

for(var i=0;i<32;i++)
{

    for(var j=0;j<32;j++)   
        pix.push(0.8,0.8,0.1);
}

gl.activeTexture(gl.TEXTURE0);

gl.bindTexture(gl.TEXTURE_2D, lightMap);
gl.pixelStorei(gl.UNPACK_ALIGNMENT,1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 32,32,0, gl.RGB,  gl.UNSIGNED_BYTE,new Float32Array(pix));

gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.uniform1i(g_loader.program.set_uniform["u_texture2"],0);

Но, однако, когда я попытался получить доступ к текстуре в шейдере:

[Фрагмент шейдера]

varying vec2 v_texcoord;

uniform sampler2D u_texture2;

void main(void)
{

vec3 lightLoc = texture2D(u_texture, v_texcoord).rgb;

gl_FragData[0] = vec4(lightLoc,1.0);

}

Результат полностью черный. Кто-нибудь знает, как правильно получить или создать текстуру?

Ответы [ 4 ]

3 голосов
/ 23 марта 2012

Интуитивно понятно, что можно было бы реализовать несколько источников света, делая что-то вроде этого:

uniform int NUM_LIGHTS;
uniform vec3 uLa[NUM_LIGHTS]; 

Но WebGL выдает такую ​​ошибку:

ERROR: 0:12: ":constant expression required
ERROR: 0:12: ":array size must be a constant integer expression"

Тем не менее, вы на самом деле можете передавать единообразные массивы в шейдер фрагментов для представления нескольких источников света. Единственное предостережение в том, что вам нужно заранее знать размер этих массивов. Например:

const int NUM_LIGHTS = 5;
uniform vec3  uLa[NUM_LIGHTS];   //ambient
uniform vec3  uLd[NUM_LIGHTS];   //diffuse
uniform vec3  uLs[NUM_LIGHTS];   //specular

Это правильно. Также вам необходимо убедиться, что вы отображаете плоский массив на стороне JavaScript. Поэтому вместо этого:

var ambientLightArray = [[0.1,0.1,0.1][0.1,0.1,0.1],...]

сделать это:

var ambientLightArray = [0.1,0.1,0.1,0.1,0.1,0.1,..]

Тогда вы делаете:

var location = gl.getUniformLocation(prg,"uLa");
gl.uniform3fv(location, ambientLightArray);

После того, как вы настроили массивы с заранее заданным размером, вы можете делать такие вещи:

//Example: Calculate diffuse contribution from all lights to the current fragment
//vLightRay[] and vNormal are varyings calculated in the Vertex Shader
//uKa and uKd are material properties (ambient and diffuse)

vec3 COLOR = vec3(0.0,0.0,0.0);
vec3 N = normalize(vNormal);
for(int i = 0; i < NUM_LIGHTS; i++){    
   L = normalize(vLightRay[i]);     
   COLOR += (uLa[i] * uKa) + (uLd[i] * uKd * clamp(dot(N, -L),0.0,1.0));
}   
gl_FragColor =  vec4(COLOR,1.0);

Я надеюсь, что это может быть полезно

1 голос
/ 10 октября 2011

Вы звоните glTexImage2D с типом GL_UNSIGNED_BYTE, но затем вы даете ему массив с плавающей точкой (Float32Array). Согласно спецификации Это вызывает ошибку GL_INVALID_OPERATION.

Вы должны скорее преобразовать свои позиции из [0,1] с плавающей точкой в ​​целые числа в диапазоне [0,255] и использовать Uint8Array. К сожалению, это теряет некоторую точность, и все ваши позиции должны находиться в диапазоне [0,1] (или, по крайней мере, в некотором фиксированном диапазоне, в который вы позже преобразуете значения [0,1], полученные из текстуры). Но я точно помню, что в данный момент WebGL не поддерживает текстуры с плавающей запятой.

РЕДАКТИРОВАТЬ: Из-за ссылки в вашем комментарии WebGL действительно поддерживает текстуры с плавающей точкой. Таким образом, использование типа GL_FLOAT и Float32Array также должно работать. Но в этом случае вы должны убедиться, что ваше оборудование также поддерживает текстуры с плавающей запятой (начиная с ~ GeForce 6), а ваша реализация WebGL поддерживает расширение OES_texture_float.

Вы также можете попробовать установить режимы фильтрации на GL_NEAREST, так как старое оборудование может не поддерживать линейно фильтрованные текстуры с плавающей запятой. И поскольку вы все равно хотите использовать текстуру в качестве простого массива, вам не нужна интерполяция.

1 голос
/ 15 октября 2011

Обратите внимание, что в WebGL, в отличие от OpenGL, вы должны явно вызывать getExtension, прежде чем сможете использовать расширение, такое как OES_texture_float.А затем вы хотите передать gl.FLOAT в качестве параметра типа для texImage2D.

0 голосов
/ 10 октября 2011

Функция texImage2D ожидает и изображение как параметр, а не массив.Вы должны записать свою текстуру в Canvas, а затем использовать изображение холста в качестве параметра texImage2D.

Проверьте эту ссылку:

http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#pixel-manipulation

...