Никогда не могу понять, как сделать текстурные работы в TWGL
Это код, который у меня есть для vs / fs и простой куб, который я хочу поместить на свой холст. некоторая часть опущена из-за продолжительности.
<script id="cube-vs" type="notjs">
precision highhp float;
attribute vec3 vpos;
attribute vec3 vnormal;
attribute vec2 vtex;
varying vec3 fColor;
varying vec3 fNormal;
varying vec2 fTexCoord;
uniform mat4 view;
uniform mat4 proj;
uniform mat4 model;
uniform vec3 lightdir;
uniform vec3 cubecolor;
void main(void) {
gl_Position = proj * view * model * vec4(vpos, 1.0);
vec4 normal = normalize(model * vec4(vnormal,0.0));
float diffuse = .2 + abs(dot(normal, vec4(lightdir,0.0)));
fColor = (cubecolor * diffuse);
fTexCoord = vtex;
}
</script>
<script id="cube-fs" type="notjs">
precision highhp float;
varying vec3 fColor;
varying vec3 fNormal;
varying vec2 fTexCoord;
uniform sampler2D texSampler;
void main(void) {
vec4 texColor = texture2d(texSampler, fTexCoord);
gl_FragColor = vec4(fColor*texColor.xyz,1.0);
}
</script>
куб
...
Cube.prototype.init = function(drawingState) {
var gl=drawingState.gl;
// create the shaders once - for all cubes
if (!shaderProgram) {
shaderProgram = twgl.createProgramInfo(gl, ["tree-vs", "tree-fs"]);
}
if (!buffers) {
var arrays = {
vpos : { numComponents: 3, data: [...] },
vnormal : {numComponents:3, data: [...]},
vtex : {numComponents:2, data: [
1,0,0,0,0,1,1,1,
1,0,0,0,0,1,1,1,
1,0,0,0,0,1,1,1,
1,0,0,0,0,1,1,1,
1,0,0,0,0,1,1,1,
1,0,0,0,0,1,1,1,
]},
indices : {[...]}
};
buffers = twgl.createBufferInfoFromArrays(gl,arrays);
}
if (!texture) {
texture = twgl.createTexture(gl, {src:textures/tree.jpg});
}
};
Cube.prototype.draw = function(drawingState) {
var modelM = twgl.m4.scaling([this.size*1.4,this.size*1.4,this.size*1.4]);
twgl.m4.setTranslation(modelM,this.position,modelM);
var gl = drawingState.gl;
gl.useProgram(shaderProgram.program);
twgl.setBuffersAndAttributes(gl,shaderProgram,buffers);
twgl.setUniforms(shaderProgram,{
view:drawingState.view, proj:drawingState.proj, lightdir:drawingState.sunDirection,
cubecolor:this.color, model: modelM, texSampler: texture);
twgl.drawBufferInfo(gl, gl.TRIANGLES, buffers);
};
куб работал без текстуры, но когда я пытался нанести текстуру, он никогда не работал, я попробовал почти все и до сих пор не могу понять, как нанести текстуру. Итак, как я могу наложить текстуру?
любые советы будут очень цениться.
********* edit Мне удалось успешно загрузить координаты текстуры и форму, но изображение не отображается, а куб окрашен в светло-синий цвет. любые предложения будут очень признательны.
1 ответ
Было бы неплохо, если бы вы могли предоставить рабочий пример, а не только части кода. В приведенном выше коде есть несколько опечаток. Например, в setUniforms
часть нет закрытия }
, в createTexture
часть там нет кавычек на URL. Вы написали highp
как highhp
а также texture2D
как texture2d
, Я полагаю, если вы говорите, что он работает, хотя без текстур, это просто ошибки транскрипции, потому что если нет, вы должны увидеть очень четкие ошибки в консоли JavaScript.
Не ясно, что не так, но при отладке WebGL первым делом я проверяю консоль JavaScript. Есть ли какие-нибудь сообщения о неприменимых текстурах?
Нет? Затем я хотел бы изменить фрагментный шейдер на сплошной цвет.
<script id="cube-fs" type="notjs">
precision highhp float;
varying vec3 fColor;
varying vec3 fNormal;
varying vec2 fTexCoord;
uniform sampler2D texSampler;
void main(void) {
vec4 texColor = texture2d(texSampler, fTexCoord);
gl_FragColor = vec4(fColor*texColor.xyz,1.0);
gl_FragColor = vec4(1,0,0,1); // -------ADDED-------------------------
}
</script>
Если вы видите свой куб, то да, проблема связана с текстурой. Если нет, то проблема в другом.
Предположим, вы видите красный куб. Хорошо, следующая вещь - проверить координаты текстуры. Я бы поменял фрагментный шейдер на этот
<script id="cube-fs" type="notjs">
precision highhp float;
varying vec3 fColor;
varying vec3 fNormal;
varying vec2 fTexCoord;
uniform sampler2D texSampler;
void main(void) {
vec4 texColor = texture2d(texSampler, fTexCoord);
gl_FragColor = vec4(fColor*texColor.xyz,1.0);
gl_FragColor = vec4(fTexCoord,0,1); // -------CHANGED-------------------------
}
</script>
Теперь вы должны увидеть куб с красной и зеленой штриховкой. Если нет, у вас плохие координаты текстуры.
Если это выглядит правильно, то следующая вещь, которую я мог бы попробовать, это вернуть шейдер обратно в исходное состояние, а затем проверить, является ли переменная texture
на самом деле установлен.
Есть куча способов проверить это.
Используйте инспектор WebGL
Используйте стандартный JavaScript-отладчик. Установите точку останова на
setUniforms
часть. Проверьте переменныеСделать что-то подобное
var uniforms = { view:drawingState.view, proj:drawingState.proj, lightdir:drawingState.sunDirection, cubecolor:this.color, model: modelM, texSampler: texture, }; window.u = uniforms; twgl.setUniforms(shaderProgram, uniforms);
Теперь откройте консоль JavaScript и введите
u.texSampler
, Это должно напечатать что-то вродеWebGLTexture {}
Если это не так, вероятно,
texture
это не та переменная, о которой вы думаете
Еще один вопрос заключается в том, вы постоянно рендеринг с использованием requestAnimationFrame, как в
function render() {
// draw stuff like maybe call someCube.draw(drawingState)
...
requestAnimationFrame(render);
}
requestAnimationFrame(render);
Я спрашиваю, потому что текстуры загружаются асинхронно, поэтому, если вы выполняете рендеринг только один раз, вы не увидите никаких текстур, потому что они еще не загружены.
У вас есть несколько вариантов.
Рендеринг постоянно (как в примере выше)
По умолчанию twgl будет использовать текстуру 1x1 пикселей, поэтому рендеринг должен работать. Затем изображение, наконец, загружено, оно обновит текстуру
Подождите, пока текстура загрузится.
Если вы не хотите рендерить, пока текстура не будет готова, вы можете добавить обратный вызов
twgl.createTexture
и он перезвонит вам, когда текстура будет готова.
Другое дело, чтобы начать с рабочего образца
var m4 = twgl.m4; // <!------------ ADDED
var v3 = twgl.v3; // <!------------ ADDED
// not sure why these are globals?!???!
var shaderProgram; // <!------------ ADDED
var texture; // <!------------ ADDED
var buffers; // <!------------ ADDED
var canvas = document.querySelector("canvas"); // <!------------ ADDED
var drawingState = { // <!------------ ADDED
gl: canvas.getContext("webgl"), // <!------------ ADDED
view: m4.inverse(m4.lookAt([3,3,6], [0, 0, 0], [0, 1, 0])), // <!------------ ADDED
proj: m4.perspective( // <!------------ ADDED
Math.PI * 0.3, // <!------------ ADDED
canvas.clientWidth / canvas.clientHeight, // <!------------ ADDED
0.1, 10), // <!------------ ADDED
sunDirection: v3.normalize([2,3,-2]), // <!------------ ADDED
}; // <!------------ ADDED
function Cube() { // <!-------------------------------------- ADDED
this.size = 1; // <!-------------------------------------- ADDED
this.position = [0, 0, 0]; // <!-------------------------------------- ADDED
this.color = [1, 1, 1]; // <!-------------------------------------- ADDED
} // <!-------------------------------------- ADDED
Cube.prototype.init = function(drawingState) {
var gl=drawingState.gl;
// create the shaders once - for all cubes
if (!shaderProgram) {
shaderProgram = twgl.createProgramInfo(gl, ["cube-vs", "cube-fs"]); // <!---- CHANGED
}
if (!buffers) {
var arrays = {
vpos: { numComponents: 3, data: [1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1], },
vnormal: { numComponents: 3, data: [1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1], },
vtex: { numComponents: 2, data: [1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1], },
indices: [0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23],
};
buffers = twgl.createBufferInfoFromArrays(gl,arrays);
}
if (!texture) {
texture = twgl.createTexture(gl, {
src: "https://farm6.staticflickr.com/5795/21506301808_efb27ed699_q_d.jpg",
crossOrigin: "", // <!--------- not needed if on same server which "texture/tree.jpg" is
});
}
};
Cube.prototype.draw = function(drawingState) {
var modelM = twgl.m4.scaling([this.size*1.4,this.size*1.4,this.size*1.4]);
twgl.m4.setTranslation(modelM,this.position,modelM);
var gl = drawingState.gl;
gl.useProgram(shaderProgram.program);
twgl.setBuffersAndAttributes(gl,shaderProgram,buffers);
twgl.setUniforms(shaderProgram,{
view:drawingState.view, proj:drawingState.proj, lightdir:drawingState.sunDirection,
cubecolor:this.color, model: modelM, texSampler: texture});
twgl.drawBufferInfo(gl, gl.TRIANGLES, buffers);
};
var cube = new Cube(); // <!------------ ADDED
cube.init(drawingState); // <!------------ ADDED
function render() { // <!------------ ADDED
var gl = drawingState.gl // <!------------ ADDED
gl.enable(gl.DEPTH_TEST); // <!------------ ADDED
cube.draw(drawingState); // <!------------ ADDED
requestAnimationFrame(render); // <!------------ ADDED
} // <!------------ ADDED
requestAnimationFrame(render); // <!------------ ADDED
canvas { border: 1px solid black; }
<script id="cube-vs" type="notjs">
//precision highp float; <!---------------- CHANGED
attribute vec3 vpos;
attribute vec3 vnormal;
attribute vec2 vtex;
varying vec3 fColor;
varying vec3 fNormal;
varying vec2 fTexCoord;
uniform mat4 view;
uniform mat4 proj;
uniform mat4 model;
uniform vec3 lightdir;
uniform vec3 cubecolor;
void main(void) {
gl_Position = proj * view * model * vec4(vpos, 1.0);
vec4 normal = normalize(model * vec4(vnormal,0.0));
float diffuse = .2 + abs(dot(normal, vec4(lightdir,0.0)));
fColor = (cubecolor * diffuse);
fTexCoord = vtex;
}
</script>
<script id="cube-fs" type="notjs">
precision highp float; // <!--------- CHANGED (should probably use mediump though)
varying vec3 fColor;
varying vec3 fNormal;
varying vec2 fTexCoord;
uniform sampler2D texSampler;
void main(void) {
vec4 texColor = texture2D(texSampler, fTexCoord); // < !-------- CHANGED
gl_FragColor = vec4(fColor*texColor.xyz,1.0);
}
</script>
<canvas></canvas>
<script src="https://twgljs.org/dist/twgl-full.min.js"></script>
Еще один вопрос, у вас работает веб-сервер? WebGL требует веб-сервер для чтения текстур. Обратите внимание, что запуск веб-сервера является тривиальным. Действительно хороший здесь. Просто скачайте версию для вашей ОС
path/to/devd-download/devd path/to/project
Затем перейдите к http://localhost:8000/nameOfYourHtmlFile.html
Я предполагаю, что это не было проблемой, потому что если бы это было, вы бы увидели явную ошибку в консоли JavaScript о невозможности загрузить текстуру, но вы не упомянули ошибки в консоли JavaScript