我正在编写光线追踪程序,主要思想是将三角形和.obj模型的索引保存为2个纹理:
a)顶点纹理 b)指数纹理
我这样做是为了在我的GLSL片段着色器中进行光线三角形交叉,浏览器告诉我我的纹理有这个问题:
a) Mozilla Firefox :
错误#1(带顶点纹理):错误:WebGL:texImage2D:无效类型0x1406 。
错误#2(带索引纹理):错误:WebGL:texImage2D:无效类型0x1403 。
b) Google Chrome :
两种纹理都出错: webgl invalid_enum teximage2d无效纹理类型
以下是代码:
Obj.prototype.initTextures = function(){
this.vertexTexture = gl.createTexture();
gl.activeTexture(gl.TEXTURE0)
gl.bindTexture(gl.TEXTURE_2D, this.vertexTexture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, this.vertexSize, 1, 0, gl.RGB, gl.FLOAT, new Float32Array(this.vertexArray));
gl.bindTexture(gl.TEXTURE_2D, null);
this.trianglesTexture = gl.createTexture();
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, this.trianglesTexture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, this.faceSize, 1, 0, gl.RGB, gl.UNSIGNED_SHORT, new Uint16Array(this.faceArray));
gl.bindTexture(gl.TEXTURE_2D, null);
}
由于显而易见的原因,this.vertexArray和this.faceArray都有这些数据。
答案 0 :(得分:5)
gl.RGB
/ gl.FLOAT
纹理。
var floatTextures = gl.getExtension('OES_texture_float');
if (!floatTextures) {
alert('no floating point texture support');
return;
}
WebGL上 gl.RGB
/ gl.UNSIGNED_SHORT
纹理不存在。您可以尝试将无符号短值编码为R * 256 + G * 65536
或沿着这些行进行编码。或者也可以在这里使用花车。
注意:像gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
一样过滤浮动内容是一个单独的扩展程序OES_texture_float_linear
,但在您的情况下,由于您只使用gl.NEAREST
,因此您不需要检查该扩展名
至于将顶点数据放在纹理中,您可能会发现必须做一些工作来提取正确的值。
要索引纹理中的值,您需要计算将访问正确纹理元素的纹理坐标。要做到这一点,您需要从第一个纹素的中间访问到最后一个纹素的中间。
换句话说,如果我们有3个值(因此有3个像素),我们就会有类似的东西
------3x1 ----- texels ----------
[ ][ ][ ]
0.0 |<----------------------------->| 1.0
如果我们只是使用index / numValues来计算纹理坐标,我们就得到
[ ][ ][ ]
| | |
0.0 0.333 0.666
在texel之间是正确的,所以我们添加了halfTexel来获得这个
[ ][ ][ ]
| | |
0.167 0.5 0.833
希望有道理。这是一个片段
var gl = document.querySelector("canvas").getContext("webgl");
var ext = gl.getExtension("OES_texture_float");
if (!ext) {
alert("need OES_texture_float extension cause I'm lazy");
//return;
}
if (gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS) < 2) {
alert("need to be able to access textures from vertex shaders");
//return;
}
var m4 = twgl.m4;
var v3 = twgl.v3;
var program = twgl.createProgramFromScripts(gl, ["vshader", "fshader"]);
var positionIndexLoc = gl.getAttribLocation(program, "a_positionIndex");
var normalIndexLoc = gl.getAttribLocation(program, "a_normalIndex");
var colorLoc = gl.getUniformLocation(program, "u_color");
var mvpMatrixLoc = gl.getUniformLocation(program, "u_mvpMatrix");
var mvMatrixLoc = gl.getUniformLocation(program, "u_mvMatrix");
var lightDirLoc = gl.getUniformLocation(
program, "u_lightDirection");
var u_positionsLoc = gl.getUniformLocation(
program, "u_positions");
var u_normalsLoc = gl.getUniformLocation(
program, "u_normals");
gl.uniform1i(u_positionsLoc, 0); // use texture unit 0 for positions
gl.uniform1i(u_normalsLoc, 1); // use texture unit 1 for normals
// Cube data
var positions = [
-1, -1, -1, // 0 lbb
+1, -1, -1, // 1 rbb 2---3
-1, +1, -1, // 2 ltb /| /|
+1, +1, -1, // 3 rtb 6---7 |
-1, -1, +1, // 4 lbf | | | |
+1, -1, +1, // 5 rbf | 0-|-1
-1, +1, +1, // 6 ltf |/ |/
+1, +1, +1, // 7 rtf 4---5
];
var positionIndices = [
3, 7, 5, 3, 5, 1, // right
6, 2, 0, 6, 0, 4, // left
6, 7, 3, 6, 3, 2, // top
0, 1, 5, 0, 5, 4, // bottom
7, 6, 4, 7, 4, 5, // front
2, 3, 1, 2, 1, 0, // back
];
var normals = [
+1, 0, 0,
-1, 0, 0,
0, +1, 0,
0, -1, 0,
0, 0, +1,
0, 0, -1,
]
var normalIndices = [
0, 0, 0, 0, 0, 0, // right
1, 1, 1, 1, 1, 1, // left
2, 2, 2, 2, 2, 2, // top
3, 3, 3, 3, 3, 3, // bottom
4, 4, 4, 4, 4, 4, // front
5, 5, 5, 5, 5, 5, // back
];
function degToRad(deg) {
return deg * Math.PI / 180;
}
function uploadIndices(loc, data, indices) {
// scale indices into texture coordinates
var scaledIndices = new Float32Array(indices.length);
// to index the value in the texture we need to
// compute a texture coordinate that will access
// the correct texel. To do that we need access from
// the middle of the first texel to the middle of the
// last texel.
//
// In other words if we had 3 values (and therefore
// 3 texels) we'd have something like this
//
// ------3x1 ----- texels ----------
// [ ][ ][ ]
// 0.0 |<----------------------------->| 1.0
//
// If we just did index / numValues we'd get
//
// [ ][ ][ ]
// | | |
// 0.0 0.333 0.666
//
// Which is right between texels so we add a
// a halfTexel to get this
//
// [ ][ ][ ]
// | | |
// 0.167 0.5 0.833
var size = data.length / 3;
var texel = 1 / size;
var halfTexel = texel / 2;
for (var ii = 0; ii < indices.length; ++ii) {
scaledIndices[ii] = indices[ii] / size + halfTexel;
}
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER,
scaledIndices,
gl.STATIC_DRAW);
gl.enableVertexAttribArray(loc);
gl.vertexAttribPointer(loc, 1, gl.FLOAT, false, 0, 0);
}
function uploadTexture(unit, data) {
gl.activeTexture(gl.TEXTURE0 + unit);
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB,
data.length / 3, 1, 0,
gl.RGB, gl.FLOAT, new Float32Array(data));
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER,
gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER,
gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S,
gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T,
gl.CLAMP_TO_EDGE);
}
uploadIndices(positionIndexLoc, positions, positionIndices);
uploadIndices(normalIndexLoc, normals, normalIndices);
uploadTexture(0, positions);
uploadTexture(1, normals);
var xRot = 30;
var yRot = 20;
var zRot = 0;
var lightDir = v3.normalize([-0.2, -0.1, 0.5]);
function draw() {
xRot += 0;
yRot += 1;
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.useProgram(program);
var projection = m4.perspective(
degToRad(45),
gl.canvas.clientWidth / gl.canvas.clientHeight,
0.1, 100.0);
var world = m4.identity();
world = m4.translate(world, [0.0, 0.0, -5.0]);
world = m4.rotateX(world, degToRad(xRot));
world = m4.rotateY(world, degToRad(yRot));
world = m4.rotateZ(world, degToRad(zRot));
var mvp = m4.multiply(projection, world);
gl.uniformMatrix4fv(mvMatrixLoc, false, world);
gl.uniformMatrix4fv(mvpMatrixLoc, false, mvp);
gl.uniform4f(colorLoc, 0.5, 0.8, 1, 1);
gl.uniform3fv(lightDirLoc, lightDir);
gl.drawArrays(gl.TRIANGLES, 0, 36);
requestAnimationFrame(draw);
}
draw();
&#13;
body {
margin: 0;
}
canvas {
width: 100vw;
height: 100vh;
display: block;
}
&#13;
<script src="//twgljs.org/dist/2.x/twgl-full.min.js"></script>
<script id="vshader" type="whatever">
attribute float a_positionIndex;
attribute float a_normalIndex;
attribute vec4 a_pos;
uniform sampler2D u_positions;
uniform sampler2D u_normals;
uniform mat4 u_mvpMatrix;
uniform mat4 u_mvMatrix;
varying vec3 v_normal;
void main() {
vec3 position = texture2D(
u_positions, vec2(a_positionIndex, 0.5)).rgb;
vec3 normal = texture2D(
u_normals, vec2(a_normalIndex, 0.5)).rgb;
gl_Position = u_mvpMatrix * vec4(position, 1);
v_normal = (u_mvMatrix * vec4(normal, 0)).xyz;
}
</script>
<script id="fshader" type="whatever">
precision mediump float;
uniform vec4 u_color;
uniform vec3 u_lightDirection;
varying vec3 v_normal;
void main() {
float light = dot(
normalize(v_normal), u_lightDirection) * 0.5 + 0.5;
gl_FragColor = vec4(u_color.rgb * light, u_color.a);
}
</script>
<canvas></canvas>
&#13;