Ваша настоящая ошибка, скорее всего, где-то еще и связана с тем, что вы неправильно связали свои текстуры или искали неправильные места или что-то еще
ПРЕДУПРЕЖДЕНИЕ О РЕГЕНСЕРЕК: текстура не привязана к юниту 0
Вот рабочий пример с вашей однородной структурой
const fs = `
precision mediump float;
struct PhongMaterial {
vec4 diffuse;
sampler2D diffuseMap;
vec4 specular;
sampler2D specularMap;
float shininess;
samplerCube environmentMap;
};
uniform PhongMaterial material;
void main() {
vec4 diffuse = texture2D(material.diffuseMap, gl_PointCoord.xy);
vec4 specular = texture2D(material.specularMap, gl_PointCoord.xy);
vec4 cube = textureCube(
material.environmentMap,
vec3(gl_PointCoord.xy, gl_PointCoord.x * gl_PointCoord.y) * 2. - 1.);
// use all 3 textures so we can see they were set
vec4 diffuseOrSpecular = mix(diffuse, specular, step(0.25, gl_PointCoord.y));
gl_FragColor = mix(diffuseOrSpecular, cube, step(0.5, gl_PointCoord.y));
}
`
const vs = `
void main() {
gl_Position = vec4(0, 0, 0, 1);
gl_PointSize = 128.0;
}
`;
const gl = document.querySelector('canvas').getContext('webgl');
const prg = twgl.createProgram(gl, [vs, fs]);
const diffuseLocation = gl.getUniformLocation(prg, 'material.diffuseMap');
const specularLocation = gl.getUniformLocation(prg, 'material.specularMap');
const envmapLocation = gl.getUniformLocation(prg, 'material.environmentMap');
const texDiffuse = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texDiffuse);
{
const level = 0;
const format = gl.RGBA;
const width = 1;
const height = 1;
const type = gl.UNSIGNED_BYTE;
const pixel = new Uint8Array([255, 255, 0, 255]); // yellow
gl.texImage2D(gl.TEXTURE_2D, level, format, width, height, 0, format, type, pixel);
}
const texSpecular = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texSpecular);
{
const level = 0;
const format = gl.RGBA;
const width = 1;
const height = 1;
const type = gl.UNSIGNED_BYTE;
const pixel = new Uint8Array([0, 0, 255, 255]); // blue
gl.texImage2D(gl.TEXTURE_2D, level, format, width, height, 0, format, type, pixel);
}
const texCube = gl.createTexture();
gl.bindTexture(gl.TEXTURE_CUBE_MAP, texCube);
for (let i = 0; i < 6; ++i) {
const level = 0;
const format = gl.RGBA;
const width = 1;
const height = 1;
const type = gl.UNSIGNED_BYTE;
const pixel = new Uint8Array([(i & 1) * 255, (i & 2) * 255, (i & 4) * 255, 255]);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, level, format, width, height, 0, format, type, pixel);
}
gl.useProgram(prg);
// put the yellow diffuse texture on texture unit 0
gl.activeTexture(gl.TEXTURE0 + 0);
gl.bindTexture(gl.TEXTURE_2D, texDiffuse);
// use texture on texture unit 0
gl.uniform1i(diffuseLocation, 0);
// put the blue specular texture on texture unit 1
gl.activeTexture(gl.TEXTURE0 + 1);
gl.bindTexture(gl.TEXTURE_2D, texSpecular);
// tell the specular sampler to use texture unit 1
gl.uniform1i(specularLocation, 1);
// put the cubemap on texture unit 2
gl.activeTexture(gl.TEXTURE0 + 2);
gl.bindTexture(gl.TEXTURE_CUBE_MAP, texCube);
// tell the cubemap sampler to use texture unit 2
gl.uniform1i(envmapLocation, 2);
// draw one 128x128 pixel point
gl.drawArrays(gl.POINTS, 0, 1);
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>
ПРИМЕЧАНИЕ: вы должны предоставить действительную текстуру для каждого сэмплера, если ваш шейдер утверждает, что он используется независимо от того, действительно ли он используется.
Чтобы узнать, утверждает ли шейдер, что он используется, вызовите
gl.getUniformLocation(program, nameOfSamplerUniform);
Если он возвращает ненулевое значение, тогда AFAIK, как и WebGL, должен предоставить корректную текстуру для этого сэмплера.
Если вам на самом деле он не нужен (из-за условий или чего-то еще), оставьте текстуру в 1 пиксель для текстуры 2D или 6 пикселов, по 1 пикселю на лицо для карт куба и прикрепите эту текстуру, когда вы нене нужна конкретная текстура.
В этих случаях я обычно держу вокруг белую и / или черную текстуру.Например, скажем, у меня была математика типа
color = diffuseMapColor * diffuseColor + envMapColor;
Если я хочу только diffuseColor
, тогда я могу установить diffuseMapColor
на белый и envMapColor
на черный, что эффективно
color = 1 * diffuseColor + 0;
Точно так же, как я только хочу diffuseMapColor
Я могу установить diffuseColor
на белый и envMapColor
на черный и получить
color = diffuseMapColor * 1 + 0;
, и если я только хочу envMapColor
, тогда установка diffuseColor
на 0 будетwork
color = diffuseMapColor * 0 + envMapColor;
- это то же самое, что и
color = 0 + envMapColor;
С другой стороны, большинство 3D-движков генерируют разные шейдеры для этих случаев.Если карта окружения не используется, они генерируют шейдер, который не включает карту окружения.Это связано с тем, что обычно выполнение меньшего количества работы в шейдере происходит быстрее, чем большее, поэтому хороший 3D-движок генерирует шейдеры для каждого необходимого случая.