我目前正在开发一个关于WebGL的网站。我和我的伙伴想要使用一个小而有趣的WebGL背景。
我们要做的是让一个盒子在画布上旋转。现在,它的原理已经起作用了。我们已经有一个旋转框,但是许多三角形使用错误的顶点形成三角形,导致下图:
The rotating cube with a bad triangle setup.
所以,我们想:让我们使用指数来正确设置它。然而,这会导致盒子从画布上消失。它似乎不再是任何地方了。
我们的问题是:有人能看出为什么会这样吗?我们感觉我们非常接近,但这个微小的细节确实给我们带来了一些麻烦。
我们正在使用的代码如下所示。我们也欢迎任何其他反馈。
当前计划
// ROTATING EXAMPLE
// The canvas that the GL environment will be using.
var canvas = null;
// The Graphics Library, aka: WebGL.
var openGL = null;
// The shader used by the graphics library.
var shaderProgram = null;
// Our matrices.
var modelViewMatrix;
var modelNormalMatrix;
var perspectiveMatrix;
var VertexBuffer;
var ColorBuffer;
var NormalBuffer;
var IndicesBuffer;
var vertexPositionAttribute;
var vertexColorAttribute;
var vertexNormalAttribute;
var squareRotation = 0.0;
var lastSquareUpdateTime = null;
// Encapsulation of the initialisation of WebGL.
function initWebGL(openGLCanvas) {
var gl = null;
// Attempt to build the context.
try {
gl = openGLCanvas.getContext("webgl", { premultipliedAlpha: false })
|| openGLCanvas.getContext("experimental-webgl", { premultipliedAlpha: false });
}
// Report back to use when some exception is thrown.
catch (exception) {
console.log("An error happened when trying to initialise the openGL environment. See the exception below for details.");
console.log(exception);
gl = null;
}
return gl;
}
function initialise(){
// Keep this variable local. We do not need it globally.
var openGLCanvas = document.getElementById("openGLCanvas");
openGL = initWebGL(openGLCanvas);
if(openGL)
{
// The color to use to clear the screen.
openGL.clearColor(0.9, 0.9, 0.9, 1.0);
openGL.clearDepth(1.0);
// Enables the depth testing.
openGL.enable(openGL.DEPTH_TEST);
// Closer things will overlap with things further away.
openGL.depthFunc(openGL.LEQUAL);
// Clear both the color as the depth buffer.
openGL.clear(openGL.COLOR_BUFFER_BIT |openGL.DEPTH_BUFFER_BIT);
openGL.viewport(0, 0, openGLCanvas.width, openGLCanvas.height);
InitialiseShaders();
InitialiseBuffers();
setInterval(drawScene, 15);
//drawScene();
}
}
function InitialiseShaders()
{
var fragmentShader = retrieveShader(openGL, "04fragment", "f", "shader");
var vertexShader = retrieveShader(openGL, "04vertex", "v", "shader");
//console.log(fragmentShader);
//console.log(vertexShader);
shaderProgram = openGL.createProgram();
openGL.attachShader(shaderProgram, vertexShader);
openGL.attachShader(shaderProgram, fragmentShader);
openGL.linkProgram(shaderProgram);
if(!openGL.getProgramParameter(shaderProgram, openGL.LINK_STATUS))
{
console.log("Something went wrong during the initialisation of the shader program. See below for extra information.");
console.log(openGL.getProgramParameter(shaderProgram, openGL.LINK_STATUS));
}
openGL.useProgram(shaderProgram);
vertexPositionAttribute = openGL.getAttribLocation(shaderProgram, "position");
openGL.enableVertexAttribArray(vertexPositionAttribute);
vertexColorAttribute = openGL.getAttribLocation(shaderProgram, "color");
openGL.enableVertexAttribArray(vertexColorAttribute);
vertexNormalAttribute = openGL.getAttribLocation(shaderProgram, "normal");
openGL.enableVertexAttribArray(vertexNormalAttribute);
}
function retrieveShader(openGL, filename, type, filetype)
{ // Ensure the file type is always given.
filetype = filetype || "txt";
// Read out the source file.
var source = "";
$.ajax({
url: "Shaders/" + filename + "." + filetype,
async: false,
success: function(data) { source = data; }
});
console.info("Found source for the following filename: " + filename + ", of type: " + type + ".");
console.info(source);
// Check what type the shader should be.
// If the type is unknown we can see the error report within the console.
var shader;
if(type == "f")
{ shader = openGL.createShader(openGL.FRAGMENT_SHADER);}
else if (type == "v")
{ shader = openGL.createShader(openGL.VERTEX_SHADER);}
else
{
console.log("Unknown shader type. See below for extra information.");
console.log(identification);
console.log(shaderScript.type);
return null;
}
// Attempt to compile the shader.
openGL.shaderSource(shader, source);
openGL.compileShader(shader);
// Check whether or not there are any compilation errors.
// If there are any, we'll be able to see the error report within the console.
if(!openGL.getShaderParameter(shader, openGL.COMPILE_STATUS))
{
console.log("An error occured during the compilation of the shader. See below for extra information.");
console.log(openGL.getShaderInfoLog(shader));
return null;
}
// All is green.
// Lets start this baby up.
return shader;
}
function InitialiseBuffers()
{
bufferPosition();
bufferColor();
bufferNormal();
bufferIndices();
}
function bufferIndices(){
var indices = [
0, 1, 2, 0, 2, 3, // front
4, 5, 6, 4, 6, 7, // back
8, 9, 10, 8, 10, 11, // top
12, 13, 14, 12, 14, 15, // bottom
16, 17, 18, 16, 18, 19, // right
20, 21, 22, 20, 22, 23 // left
];
IndicesBuffer = openGL.createBuffer();
openGL.bindBuffer(openGL.ELEMENT_ARRAY_BUFFER, IndicesBuffer);
openGL.bufferData(openGL.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), openGL.STATIC_DRAW);
}
function bufferPosition()
{
// Vertex data for a 3D box.
var vertices = [
// Front face
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
// Back face
-1.0, -1.0, -1.0,
-1.0, 1.0, -1.0,
1.0, 1.0, -1.0,
1.0, -1.0, -1.0,
// Top face
-1.0, 1.0, -1.0,
-1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, -1.0,
// Bottom face
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, -1.0, 1.0,
-1.0, -1.0, 1.0,
// Right face
1.0, -1.0, -1.0,
1.0, 1.0, -1.0,
1.0, 1.0, 1.0,
1.0, -1.0, 1.0,
// Left face
-1.0, -1.0, -1.0,
-1.0, -1.0, 1.0,
-1.0, 1.0, 1.0,
-1.0, 1.0, -1.0
];
// Create a buffer, prep it for filling and then fill it.
VertexBuffer = openGL.createBuffer();
openGL.bindBuffer(openGL.ARRAY_BUFFER, VertexBuffer);
openGL.bufferData(openGL.ARRAY_BUFFER, new Float32Array(vertices), openGL.STATIC_DRAW);
}
function bufferColor()
{
// Color data for a 3D Box.
var colorPerFace = [
[0.8, 0.9, 0.75, 1.0], // Front face
[0.8, 0.9, 0.75, 1.0], // Back face
[0.8, 0.9, 0.75, 1.0], // Top face
[0.8, 0.9, 0.75, 1.0], // Bottom face
[0.8, 0.9, 0.75, 1.0], // Right face
[0.8, 0.9, 0.75, 1.0], // Left face
];
var colors = [];
// For each face.
for (j=0; j<6; j++) {
var c = colorPerFace[j];
// generate a color for every vertex on that face.
for (var i=0; i<4; i++) {
colors = colors.concat(c);
}
}
// Create a buffer, prep it and then fill it.
ColorBuffer = openGL.createBuffer();
openGL.bindBuffer(openGL.ARRAY_BUFFER, ColorBuffer);
openGL.bufferData(openGL.ARRAY_BUFFER, new Float32Array(colors), openGL.STATIC_DRAW);
}
function bufferNormal()
{
var vertexNormals = [
// Front
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
// Back
0.0, 0.0, -1.0,
0.0, 0.0, -1.0,
0.0, 0.0, -1.0,
0.0, 0.0, -1.0,
// Top
0.0, 1.0, 0.0,
0.0, 1.0, 0.0,
0.0, 1.0, 0.0,
0.0, 1.0, 0.0,
// Bottom
0.0, -1.0, 0.0,
0.0, -1.0, 0.0,
0.0, -1.0, 0.0,
0.0, -1.0, 0.0,
// Right
1.0, 0.0, 0.0,
1.0, 0.0, 0.0,
1.0, 0.0, 0.0,
1.0, 0.0, 0.0,
// Left
-1.0, 0.0, 0.0,
-1.0, 0.0, 0.0,
-1.0, 0.0, 0.0,
-1.0, 0.0, 0.0
];
NormalBuffer = openGL.createBuffer();
openGL.bindBuffer(openGL.ARRAY_BUFFER, NormalBuffer);
openGL.bufferData(openGL.ARRAY_BUFFER, new Float32Array(vertexNormals), openGL.STATIC_DRAW);
}
function drawScene()
{
openGL.clear(openGL.GL_COLOR_BUFFER_BIT | openGL.DEPTH_BUFFER_BIT);
updateScene();
// Clear both the color as the depth buffer.
openGLBindings();
openGL.drawElements(openGL.TRIANGLE, 24, openGL.UNSIGNED_SHORT, 0);
openGL.drawArrays(openGL.TRIANGLE_STRIP, 0, 24);
console.log("Scene made!");
}
function updateScene()
{
var currentTime = Date.now();
if (lastSquareUpdateTime) {
var delta = currentTime - lastSquareUpdateTime;
squareRotation += (30 * delta) / 2000.0;
}
lastSquareUpdateTime = currentTime;
// Calculate the matrices
modelViewMatrix = Matrix.I(4);
var inRadians = squareRotation * Math.PI / 180;
modelViewMatrix = modelViewMatrix.x(Matrix.Translation($V([0.0, 0.0, -12.0])).ensure4x4());
modelViewMatrix = modelViewMatrix.x(Matrix.Rotation(inRadians, $V([1, 1, 0])).ensure4x4());
modelNormalMatrix = modelViewMatrix.inverse();
modelNormalMatrix = modelNormalMatrix.transpose();
perspectiveMatrix = makePerspective(45, 520 / 520, 0.1, 100.0);
// Send the matrices to the GPU.
var mvUniform = openGL.getUniformLocation(shaderProgram, "matrixModelView");
openGL.uniformMatrix4fv(mvUniform,
false,
new Float32Array(modelViewMatrix.flatten()));
var pUniform = openGL.getUniformLocation(shaderProgram, "matrixPerspective");
openGL.uniformMatrix4fv(pUniform,
false,
new Float32Array(perspectiveMatrix.flatten()));
var nUniform = openGL.getUniformLocation(shaderProgram, "matrixNormal");
openGL.uniformMatrix4fv(nUniform,
false,
new Float32Array(modelNormalMatrix.flatten()));
}
function openGLBindings()
{
// Send the data to the GPU.
openGL.bindBuffer(openGL.ARRAY_BUFFER, VertexBuffer);
openGL.vertexAttribPointer(vertexPositionAttribute, // Where to bind it to
3, // The number of data per set.
openGL.FLOAT, // The type of data
false, // Normalisation (or not).
0, // Stride
0); // Offset
openGL.bindBuffer(openGL.ARRAY_BUFFER, ColorBuffer);
openGL.vertexAttribPointer(vertexColorAttribute, // Where to bind it to
4, // The number of data per set.
openGL.FLOAT, // The type of data.
false, // Normalisation (or not).
0, // Stride
0); // Offset
openGL.bindBuffer(openGL.ARRAY_BUFFER, NormalBuffer);
openGL.vertexAttribPointer(vertexNormalAttribute, // Where to bind it to
3, // The number of data per set.
openGL.FLOAT, // The type of data.
false, // Normalisation (or not).
0, // Stride
0); // Offset
openGL.bindBuffer(openGL.ELEMENT_ARRAY_BUFFER, IndicesBuffer);
}
片段着色器
varying lowp vec4 fColor;
void main(void) {
gl_FragColor = fColor;
}
顶点着色器
attribute vec3 position;
attribute vec3 normal;
attribute vec4 color;
uniform mat4 matrixModelView;
uniform mat4 matrixPerspective;
uniform mat4 matrixNormal;
varying lowp vec4 fColor;
void main(void) {
gl_Position = matrixPerspective * matrixModelView * vec4(position, 1.0);
highp vec3 directionalVector = vec3(1.0, 0.85, 0.6);
highp vec4 transformedNormal = matrixNormal * vec4(normal, 1.0);
highp float directional = max(dot(transformedNormal.xyz, directionalVector), 0.0);
fColor = color * directional;
}
答案 0 :(得分:1)
快速浏览代码后,我找到了以下一行
li
很可疑。您总共有6个(四边形)* 2(三角形/四边形)* 3(顶点/三角形)= 36个索引而不是24个。此外,您的bufferindices包含36个整数。
然而,紧接着的行
openGL.drawElements(openGL.TRIANGLE, 24, openGL.UNSIGNED_SHORT, 0);
显示您正在将四边形绘制为三角形条带。绘制三角形时需要保持一致,即将它们全部渲染为TRIANGLES或TRIANGLE_STRIP。如果你想绘制为TRIANGLE_STRIP,那么
的定义openGL.drawArrays(openGL.TRIANGLE_STRIP, 0, 24);
不是定义四边形三角形行程的正确顺序。正确的方法应该是
var vertices = [
// Front face
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
........
];
同样适用于其他面孔的定义。