I need help figuring out how to add textures to my basketball.
What should i add to my vertex and fragment shaders.
Fragment shader
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
struct MaterialProperties {
vec4 diffuseColor;
vec3 specularColor;
vec3 emissiveColor;
float specularExponent;
};
struct LightProperties {
bool enabled;
vec4 position;
vec3 color;
};
uniform MaterialProperties material; // do two-sided lighting, but assume front and back materials are the same
uniform LightProperties lights[4];
uniform mat3 normalMatrix;
varying vec3 v_normal;
varying vec3 v_eyeCoords;
vec3 lightingEquation( LightProperties light, MaterialProperties material,
vec3 eyeCoords, vec3 N, vec3 V ) {
// N is normal vector, V is direction to viewer.
vec3 L, R; // Light direction and reflected light direction.
if ( light.position.w == 0.0 ) {
L = normalize( light.position.xyz );
}
else {
L = normalize( light.position.xyz/light.position.w - v_eyeCoords );
}
if (dot(L,N) <= 0.0) {
return vec3(0.0);
}
vec3 reflection = dot(L,N) * light.color * material.diffuseColor.rgb;
R = -reflect(L,N);
if (dot(R,V) > 0.0) {
float factor = pow(dot(R,V),material.specularExponent);
reflection += factor * material.specularColor * light.color;
}
return reflection;
}
void main() {
vec3 normal = normalize( normalMatrix*v_normal );
vec3 viewDirection = normalize( -v_eyeCoords); // (Assumes a perspective projection.)
vec3 color = material.emissiveColor;
for (int i = 0; i < 4; i++) {
if (lights[i].enabled) {
if (gl_FrontFacing) {
color += lightingEquation( lights[i], material, v_eyeCoords,
normal, viewDirection);
}
else {
color += lightingEquation( lights[i], material, v_eyeCoords,
-normal, viewDirection);
}
}
}
gl_FragColor = vec4(color,material.diffuseColor.a);
}
The function "world()" is being draw in my "Draw ()" function. The world consist of a scene, but for the sake of readability i will just like the ball i want to add texture to.
function world() {
// Ground
pushMatrix();
mat4.translate(modelview,modelview,[-1,-3,0]);
mat4.rotate(modelview,modelview,(90)/180*Math.PI,[1,0,0]);
mat4.scale(modelview,modelview,[9,9,0.5]);
currentColor = [0.0,0.7,0.0,1];
cube.render();
popMatrix();
//Basketball
pushMatrix();
mat4.translate(modelview,modelview,[xval,yval,3]);//
mat4.scale(modelview,modelview,[0.15,0.15,0.15]);
currentColor = [1,0.3,0,1];
sphere.render();
popMatrix();
}
I have a createModel function that holds all my buffers.
I have a createProgram function that creates a program using the vertex and fragment shaders.
I have a initGL function that initializes the webgl context and gets attributes and uniform locations.
I have a init function that is called when the page is loaded.
Complete version of my code:
<!DOCTYPE html>
<meta charset="UTF-8">
<html>
<!--
A demo of lighting and hierarchical modeling using WebGL.
Emissive color is used to make the lights seem to glow yellow when
they are turned on.
Derived from code available from Diskworld-2.html
The Shaders are still complex but have been simplified slightly.
-->
<head>
<title>Project 4 - Shooting basketball</title>
<style>
body {
background-color: #EEEEEE;
}
label {
white-space: pre;
margin-left: 25px;
}
</style>
<!-- This shader is exactly as provided -->
<script type="x-shader/x-vertex" id="vshader-source">
attribute vec3 a_coords;
attribute vec3 a_normal;
uniform mat4 modelview;
uniform mat4 projection;
varying vec3 v_normal;
varying vec3 v_eyeCoords;
void main() {
vec4 coords = vec4(a_coords,1.0);
vec4 eyeCoords = modelview * coords;
gl_Position = projection * eyeCoords;
v_normal = normalize(a_normal);
v_eyeCoords = eyeCoords.xyz/eyeCoords.w;
}
</script>
<!-- This shader has simplified lighting model and equation
Notice the light only has 3 properties now -->
<script type="x-shader/x-fragment" id="fshader-source">
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
struct MaterialProperties {
vec4 diffuseColor;
vec3 specularColor;
vec3 emissiveColor;
float specularExponent;
};
struct LightProperties {
bool enabled;
vec4 position;
vec3 color;
};
uniform MaterialProperties material; // do two-sided lighting, but assume front and back materials are the same
uniform LightProperties lights[4];
uniform mat3 normalMatrix;
varying vec3 v_normal;
varying vec3 v_eyeCoords;
vec3 lightingEquation( LightProperties light, MaterialProperties material,
vec3 eyeCoords, vec3 N, vec3 V ) {
// N is normal vector, V is direction to viewer.
vec3 L, R; // Light direction and reflected light direction.
if ( light.position.w == 0.0 ) {
L = normalize( light.position.xyz );
}
else {
L = normalize( light.position.xyz/light.position.w - v_eyeCoords );
}
if (dot(L,N) <= 0.0) {
return vec3(0.0);
}
vec3 reflection = dot(L,N) * light.color * material.diffuseColor.rgb;
R = -reflect(L,N);
if (dot(R,V) > 0.0) {
float factor = pow(dot(R,V),material.specularExponent);
reflection += factor * material.specularColor * light.color;
}
return reflection;
}
void main() {
vec3 normal = normalize( normalMatrix*v_normal );
vec3 viewDirection = normalize( -v_eyeCoords); // (Assumes a perspective projection.)
vec3 color = material.emissiveColor;
for (int i = 0; i < 4; i++) {
if (lights[i].enabled) {
if (gl_FrontFacing) {
color += lightingEquation( lights[i], material, v_eyeCoords,
normal, viewDirection);
}
else {
color += lightingEquation( lights[i], material, v_eyeCoords,
-normal, viewDirection);
}
}
}
gl_FragColor = vec4(color,material.diffuseColor.a);
}
</script>
<script src="gl-matrix-min.js"></script>
<script src="trackball-rotator.js"></script>
<script src="basic-object-models-IFS.js"></script>
<script>
"use strict";
var gl; // The webgl context.
var xval= 1.3;
var yval= -1.8;
var kval = 0; // Kick leg start
var a_coords_loc; // Location of the a_coords attribute variable in the shader program.
var a_normal_loc; // Location of a_normal attribute
var a_texCoords_loc;
// var texture;
var u_modelview; // Locations for uniform matrices
var u_projection;
var u_normalMatrix;
var u_material; // An object tolds uniform locations for the material.
var u_lights; // An array of objects that holds uniform locations for light properties.
var projection = mat4.create(); // projection matrix
var modelview; // modelview matrix; value comes from rotator
var normalMatrix = mat3.create(); // matrix, derived from modelview matrix, for transforming normal vectors
var rotator; // A TrackballRotator to implement rotation by mouse.
var frameNumber = 0; // frame number during animation (actually only goes up by 0.5 per frame)
var torus, sphere, cone, cylinder, disk, ring, cube; // basic objects, created using function createModel
var matrixStack = []; // A stack of matrices for implementing hierarchical graphics.
var currentColor = [1,1,1,1]; // The current diffuseColor; render() functions in the basic objects set
// the diffuse color to currentColor when it is called before drawing the object.
// Other color properties, which don't change often are handled elsewhere.
var textureURLs = [
"textures/basketball.jpg" // array to hold textures
];
/**
* Draws the image, which consists of either the "world" or a closeup of the "car".
*/
function draw() {
gl.clearColor(0,0,0,1);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.perspective(projection, Math.PI/4, 1, 1, 50);
gl.uniformMatrix4fv(u_projection, false, projection );
modelview = rotator.getViewMatrix();
lights();
world();
}
function setLightPosition( u_position_loc, modelview, lightPosition ) {
var transformedPosition = new Float32Array(4);
vec4.transformMat4(transformedPosition, lightPosition, modelview);
gl.uniform4fv(u_position_loc, transformedPosition);
}
function lights() {
gl.uniform1i( u_lights[0].enabled, 1 );
gl.uniform4f( u_lights[0].position, 0,0,1,0 );
gl.uniform3f( u_lights[0].color, 0.15,0.15,0.15 );
// Sun light
gl.uniform1i( u_lights[1].enabled, 1 );
gl.uniform3f( u_lights[1].color, 1,0.3,0.0 );
//Lamp at night
gl.uniform1i( u_lights[2].enabled, 1 );
gl.uniform3f( u_lights[2].color, 0.35, 0.35, 0.1 ); // light 1 is the lamp at night
gl.uniform1f( u_lights[2].attenuation, 2 );
gl.uniform1i( u_lights[3].enabled, 1 );
gl.uniform3f( u_lights[3].color, 0.35, 0.35, 0.1 ); // light 1 is the lamp at night
gl.uniform1f( u_lights[3].attenuation, 2 );
currentColor = [ 0.3, 0.3, 0.3, 1 ];
//SunSetlight
pushMatrix();
mat4.translate(modelview,modelview,[7,-3,-10]);//
mat4.scale(modelview,modelview,[0.8,0.8,0.8]);
setLightPosition(u_lights[1].position, modelview, [1,0,0,0]);
gl.uniform3f( u_material.emissiveColor, 1.5,0.4, 0 );
sphere.render();
gl.uniform3f( u_material.emissiveColor, 0, 0, 0 );
popMatrix();
// lamp for night
pushMatrix();
mat4.translate(modelview,modelview,[-1,-0.8,3]);
mat4.scale(modelview,modelview,[0.4,0.1,0.1]);
setLightPosition(u_lights[2].position, modelview, [0,0,0,1]);
gl.uniform3f( u_material.emissiveColor, 1, 1, 0 );
cube.render();
gl.uniform3f( u_material.emissiveColor, 0, 0, 0 );
popMatrix();
pushMatrix();
mat4.translate(modelview,modelview,[-1,-0.8,-3]);
mat4.scale(modelview,modelview,[0.4,0.1,0.1]);
setLightPosition(u_lights[3].position, modelview, [0,0,0,1]);
gl.uniform3f( u_material.emissiveColor, 1, 1, 0 );
cube.render();
gl.uniform3f( u_material.emissiveColor, 0, 0, 0 );
popMatrix();
}
/**
* Draws a boxman figure using transformation from cubes and cylinders.
* Note for every push their should be a pop. This resets the transformations
*/
function world() {
// Ground
pushMatrix();
mat4.translate(modelview,modelview,[-1,-3,0]);
mat4.rotate(modelview,modelview,(90)/180*Math.PI,[1,0,0]);
mat4.scale(modelview,modelview,[9,9,0.5]);
currentColor = [0.0,0.7,0.0,1];
cube.render();
popMatrix();
// Street lamp
pushMatrix();
mat4.translate(modelview,modelview,[-0.8,-4.7,3]);
mat4.scale(modelview,modelview,[0.5,0.5,0.5]);
streetLight();
popMatrix();
// Street lamp
pushMatrix();
mat4.translate(modelview,modelview,[-0.8,-4.7,-3]);
mat4.scale(modelview,modelview,[0.5,0.5,0.5]);
streetLight();
popMatrix();
// Basketball court
pushMatrix();
mat4.translate(modelview,modelview,[2,-2.75,3]);
mat4.rotate(modelview,modelview,(90)/180*Math.PI,[1,0,0]);
mat4.scale(modelview,modelview,[3,3,0.1]);
currentColor = [0.2,0.2,0.2,1];
cube.render();
popMatrix();
//Road
pushMatrix();
mat4.translate(modelview,modelview,[-2,-2.75,0]);
mat4.rotate(modelview,modelview,(90)/180*Math.PI,[1,0,0]);
mat4.scale(modelview,modelview,[2,9,0.1]);
currentColor = [0.2,0.2,0.2,1];
cube.render();
popMatrix();
//Road
pushMatrix();
mat4.translate(modelview,modelview,[-2,-2.72,0]);
mat4.rotate(modelview,modelview,(90)/180*Math.PI,[1,0,0]);
mat4.scale(modelview,modelview,[0.2,9,0.1]);
currentColor = [1,1,1,1];
cube.render();
popMatrix();
//Basketball
pushMatrix();
mat4.translate(modelview,modelview,[xval,yval,3]);//
mat4.scale(modelview,modelview,[0.15,0.15,0.15]);
currentColor = [1,0.3,0,1];
sphere.render();
popMatrix();
// BasketBall Player
// Player 1
pushMatrix();
mat4.translate(modelview,modelview,[1,-2.2,3]);
mat4.scale(modelview,modelview,[0.15,0.15,0.15]);
mat4.rotate(modelview,modelview,(90)/180*Math.PI,[0,1,0]);
// Arms
pushMatrix();
mat4.translate(modelview,modelview,[0,-0.5,-2]);
mat4.rotate(modelview,modelview,(-45)/180*Math.PI,[1,0,0]);
mat4.scale(modelview,modelview,[0.5,0.5,3]);
currentColor = [0.7,0.4,0.1,1];
cylinder.render();
popMatrix();
pushMatrix();
mat4.translate(modelview,modelview,[-2,-0.5,-2]);
mat4.rotate(modelview,modelview,(-45)/180*Math.PI,[1,0,0]);
mat4.scale(modelview,modelview,[0.5,0.5,3]);
currentColor = [0.7,0.4,0.1,1];
cylinder.render();
popMatrix();
player();
popMatrix();
// PLayer 2
pushMatrix();
pushMatrix();
mat4.translate(modelview,modelview,[2.4,-2.2,3.2]);
mat4.scale(modelview,modelview,[0.2,0.2,0.2]);
mat4.rotate(modelview,modelview,(-90)/180*Math.PI,[0,1,0]);
// Arms
pushMatrix();
mat4.translate(modelview,modelview,[0,1.2,-3]);
mat4.rotate(modelview,modelview,(kval)/180*Math.PI,[1,0,0]);
mat4.scale(modelview,modelview,[0.5,0.5,3]);
currentColor = [0.7,0.4,0.1,1];
cylinder.render();
popMatrix();
pushMatrix();
mat4.translate(modelview,modelview,[-2,1.2,-3]);
mat4.rotate(modelview,modelview,(kval)/180*Math.PI,[1,0,0]);
mat4.scale(modelview,modelview,[0.5,0.5,3]);
currentColor = [0.7,0.4,0.1,1];
cylinder.render();
popMatrix();
player();
popMatrix();
//baskethoop
pushMatrix();
mat4.translate(modelview,modelview,[3,-4.3,3]);
mat4.scale(modelview,modelview,[0.5,0.5,0.5]);
basketballhoop();
popMatrix();
//Houses
pushMatrix();
mat4.translate(modelview,modelview,[-4,-2,2]);
mat4.scale(modelview,modelview,[0.6,0.6,0.6]);
house();
popMatrix();
pushMatrix();
mat4.translate(modelview,modelview,[-4,-2,-2.3]);
mat4.scale(modelview,modelview,[0.6,0.6,0.6]);
house();
popMatrix();
}
function streetLight(){
pushMatrix();
mat4.translate(modelview,modelview,[0,0,0]);
mat4.rotate(modelview,modelview,(90)/180*Math.PI,[-1,0,0]);
mat4.scale(modelview,modelview,[0.2,0.2,4]);
cylinder.render();
popMatrix();
}
function house(){
pushMatrix();
currentColor = [0.5,0.4,0.2,1];
mat4.scale(modelview,modelview,[2,2,2]);
cube.render();
popMatrix();
pushMatrix();
currentColor = [0.5,0.4,0.2,1];
mat4.translate(modelview,modelview,[0,-0.5,1.6]);
mat4.scale(modelview,modelview,[1.3,1.3,1.3]);
cube.render();
popMatrix();
pushMatrix();
currentColor = [0.2,0.2,0.2,1];
mat4.translate(modelview,modelview,[0,1,0.0]);
mat4.scale(modelview,modelview,[4,1.5,4]);
mat4.rotate(modelview,modelview,(90)/180*Math.PI,[-1,0,0]);
cone.render();
popMatrix();
}
function basketballhoop(){
pushMatrix();
currentColor = [0.1,0.1,0.1,1];
mat4.translate(modelview,modelview,[0,0,0]);
mat4.scale(modelview,modelview,[0.2,3,0.2]);
mat4.rotate(modelview,modelview,(90)/180*Math.PI,[-1,0,0]);
cylinder.render();
popMatrix();
pushMatrix();
currentColor = [0.5,0.5,0.5,1];
mat4.scale(modelview,modelview,[0.15,0.15,0.15]);
mat4.rotate(modelview,modelview,(90)/180*Math.PI,[-1,0,0]);
mat4.translate(modelview,modelview,[-4.5,0,43]);
ring.render();
popMatrix();
pushMatrix();
currentColor = [0,0,0.5,1];
mat4.scale(modelview,modelview,[0.1,1.5,2]);
mat4.translate(modelview,modelview,[0,4.4,0]);
cube.render();
popMatrix();
}
function player(){
pushMatrix();
//Head
mat4.translate(modelview,modelview,[-1,3,0]);
mat4.rotate(modelview,modelview,(90)/180*Math.PI,[1,0,0]);
mat4.scale(modelview,modelview,[0.5,0.4,0.8]);
currentColor = [0.7,0.4,0.1,1];
sphere.render();
popMatrix();
// Neck
pushMatrix();
mat4.translate(modelview,modelview,[-1,2.5,0]);
mat4.rotate(modelview,modelview,(90)/180*Math.PI,[1,0,0]);
mat4.scale(modelview,modelview,[0.3,0.4,0.3]);
currentColor = [0.7,0.4,0.1,1];
cylinder.render();
popMatrix();
// Body
pushMatrix();
mat4.translate(modelview,modelview,[-1,1.0,0]);
mat4.rotate(modelview,modelview,(90)/180*Math.PI,[1,0,0]);
mat4.scale(modelview,modelview,[1.3,1,2]);
currentColor = [0.0,0.0,0.9,1];
cube.render();
popMatrix();
// Legs
pushMatrix();
mat4.translate(modelview,modelview,[-1.3,3.1,0]);
mat4.rotate(modelview,modelview,(90)/180*Math.PI,[1,0,0]);
mat4.scale(modelview,modelview,[0.6,0.6,3.0]);
currentColor = [0.0,0.0,1,1];
cylinder.render();
popMatrix();
pushMatrix();
mat4.translate(modelview,modelview,[-0.7,3.1,0]);
mat4.rotate(modelview,modelview,(90)/180*Math.PI,[1,0,0]);
mat4.scale(modelview,modelview,[0.6,0.6,3.0]);
currentColor = [0.0,0.0,1,1];
cylinder.render();
popMatrix();
}
/**
* Push a copy of the current modelview matrix onto the matrix stack.
*/
function pushMatrix() {
matrixStack.push( mat4.clone(modelview) );
}
/**
* Restore the modelview matrix to a value popped from the matrix stack.
*/
function popMatrix() {
modelview = matrixStack.pop();
}
<!-- As is no changes -->
/**
* Create one of the basic objects. The modelData holds the data for
* an IFS using the structure from basic-objects-IFS.js. This function
* creates VBOs to hold the coordinates, normal vectors, and indices
* from the IFS, and it loads the data into those buffers. The function
* creates a new object whose properties are the identifies of the
* VBOs. The new object also has a function, render(), that can be called to
* render the object, using all the data from the buffers. That object
* is returned as the value of the function. (The second parameter,
* xtraTranslate, is there because this program was ported from a Java
* version where cylinders were created in a different position, with
* the base on the xy-plane instead of with their center at the origin.
* The xtraTranslate parameter is a 3-vector that is applied as a
* translation to the rendered object. It is used to move the cylinders
* into the position expected by the code that was ported from Java.)
*/
function createModel(modelData, xtraTranslate) {
var model = {};
model.coordsBuffer = gl.createBuffer();
model.normalBuffer = gl.createBuffer();
model.indexBuffer = gl.createBuffer();
model.count = modelData.indices.length;
if (xtraTranslate)
model.xtraTranslate = xtraTranslate;
else
model.xtraTranslate = null;
gl.bindBuffer(gl.ARRAY_BUFFER, model.coordsBuffer);
gl.bufferData(gl.ARRAY_BUFFER, modelData.vertexPositions, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, model.normalBuffer);
gl.bufferData(gl.ARRAY_BUFFER, modelData.vertexNormals, gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, model.indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, modelData.indices, gl.STATIC_DRAW);
model.render = function() { // This function will render the object.
// Since the buffer from which we are taking the coordinates and normals
// change each time an object is drawn, we have to use gl.vertexAttribPointer
// to specify the location of the data. And to do that, we must first
// bind the buffer that contains the data. Similarly, we have to
// bind this object's index buffer before calling gl.drawElements.
gl.bindBuffer(gl.ARRAY_BUFFER, this.coordsBuffer);
gl.vertexAttribPointer(a_coords_loc, 3, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, this.normalBuffer);
gl.vertexAttribPointer(a_normal_loc, 3, gl.FLOAT, false, 0, 0);
gl.uniform4fv(u_material.diffuseColor, currentColor);
if (this.xtraTranslate) {
pushMatrix();
mat4.translate(modelview,modelview,this.xtraTranslate);
}
gl.uniformMatrix4fv(u_modelview, false, modelview );
mat3.normalFromMat4(normalMatrix, modelview);
gl.uniformMatrix3fv(u_normalMatrix, false, normalMatrix);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
gl.drawElements(gl.TRIANGLES, this.count, gl.UNSIGNED_SHORT, 0);
if (this.xtraTranslate) {
popMatrix();
}
}
return model;
}
/* Creates a program for use in the WebGL context gl, and returns the
* identifier for that program. If an error occurs while compiling or
* linking the program, an exception of type String is thrown. The error
* string contains the compilation or linking error. If no error occurs,
* the program identifier is the return value of the function.
* The second and third parameters are the id attributes for <script>
* elementst that contain the source code for the vertex and fragment
* shaders.
*/
function createProgram(gl, vertexShaderID, fragmentShaderID) {
function getTextContent( elementID ) {
// This nested function retrieves the text content of an
// element on the web page. It is used here to get the shader
// source code from the script elements that contain it.
var element = document.getElementById(elementID);
var node = element.firstChild;
var str = "";
while (node) {
if (node.nodeType == 3) // this is a text node
str += node.textContent;
node = node.nextSibling;
}
return str;
}
try {
var vertexShaderSource = getTextContent( vertexShaderID );
var fragmentShaderSource = getTextContent( fragmentShaderID );
}
catch (e) {
throw "Error: Could not get shader source code from script elements.";
}
var vsh = gl.createShader( gl.VERTEX_SHADER );
gl.shaderSource(vsh,vertexShaderSource);
gl.compileShader(vsh);
if ( ! gl.getShaderParameter(vsh, gl.COMPILE_STATUS) ) {
throw "Error in vertex shader: " + gl.getShaderInfoLog(vsh);
}
var fsh = gl.createShader( gl.FRAGMENT_SHADER );
gl.shaderSource(fsh, fragmentShaderSource);
gl.compileShader(fsh);
if ( ! gl.getShaderParameter(fsh, gl.COMPILE_STATUS) ) {
throw "Error in fragment shader: " + gl.getShaderInfoLog(fsh);
}
var prog = gl.createProgram();
gl.attachShader(prog,vsh);
gl.attachShader(prog, fsh);
gl.linkProgram(prog);
if ( ! gl.getProgramParameter( prog, gl.LINK_STATUS) ) {
throw "Link error in program: " + gl.getProgramInfoLog(prog);
}
return prog;
}
/* Initialize the WebGL context. Called from init() */
function initGL() {
var prog = createProgram(gl,"vshader-source","fshader-source");
gl.useProgram(prog);
gl.enable(gl.DEPTH_TEST);
/* Get attribute and uniform locations */
a_coords_loc = gl.getAttribLocation(prog, "a_coords");
a_normal_loc = gl.getAttribLocation(prog, "a_normal");
gl.enableVertexAttribArray(a_coords_loc);
gl.enableVertexAttribArray(a_normal_loc);
u_modelview = gl.getUniformLocation(prog, "modelview");
u_projection = gl.getUniformLocation(prog, "projection");
u_normalMatrix = gl.getUniformLocation(prog, "normalMatrix");
u_material = {
diffuseColor: gl.getUniformLocation(prog, "material.diffuseColor"),
specularColor: gl.getUniformLocation(prog, "material.specularColor"),
emissiveColor: gl.getUniformLocation(prog, "material.emissiveColor"),
specularExponent: gl.getUniformLocation(prog, "material.specularExponent")
};
u_lights = new Array(4);
for (var i = 0; i < 4; i++) {
u_lights[i] = {
enabled: gl.getUniformLocation(prog, "lights[" + i + "].enabled"),
position: gl.getUniformLocation(prog, "lights[" + i + "].position"),
color: gl.getUniformLocation(prog, "lights[" + i + "].color")
};
}
gl.uniform3f( u_material.specularColor, 0.1, 0.1, 0.1 ); // specular properties don't change
gl.uniform1f( u_material.specularExponent, 16 );
gl.uniform3f( u_material.emissiveColor, 0, 0, 0); // default, will be changed temporarily for some objects
for (var i = 1; i < 4; i++) { // set defaults for lights
gl.uniform1i( u_lights[i].enabled, 0 );
gl.uniform4f( u_lights[i].position, 0, 0, 1, 0 );
gl.uniform3f( u_lights[i].color, 1,1,1 );
}
// Lights are set on in the draw() method
} // end initGL()
//--------------------------------- animation framework ------------------------------
var animating = false;
/*
This is where you control the animation by changing positions,
and rotations values as needed.
Trial and error works on the numbers. Graph paper design is more efficient.
*/
function frame() {
if (animating) {
frameNumber += 1;
// Positions of the soccer ball
xval += 0.05;
yval += 0.05;
// Rotation of kick leg
// Not perfect by anymeans but Okay for at least one viewing angle.
kval -= 1.5;
if (xval > 8.5 || yval < -8.5) {
xval= 1.3;
yval= -1.8;
kval = 0;
}
if (kval < -90) {
kval = -90; // Don't overextend the soccer all
}
draw();
requestAnimationFrame(frame);
}
}
function setAnimating(run) {
if (run != animating) {
animating = run;
if (animating)
requestAnimationFrame(frame);
}
}
//-------------------------------------------------------------------------
/**
* initialization function that will be called when the page has loaded
*/
function init() {
try {
var canvas = document.getElementById("webglcanvas");
gl = canvas.getContext("webgl") ||
canvas.getContext("experimental-webgl");
if ( ! gl ) {
throw "Browser does not support WebGL";
}
}
catch (e) {
document.getElementById("message").innerHTML =
"<p>Sorry, could not get a WebGL graphics context.</p>";
return;
}
try {
initGL(); // initialize the WebGL graphics context
}
catch (e) {
document.getElementById("message").innerHTML =
"<p>Sorry, could not initialize the WebGL graphics context:" + e + "</p>";
return;
}
document.getElementById("animCheck").checked = false;
document.getElementById("reset").onclick = function() {
rotator.setView(17,[0,1,2]);
frameNumber = 0;
// Initialize soccer ball positions
xval = 1.5;
yval = -1.5;
animating = false;
document.getElementById("animCheck").checked = false;
draw();
}
// Not really using all of these
// As you create your scene use these or create from primitives
torus = createModel(uvTorus(0.5,1,16,8)); // Create all the basic objects.
sphere = createModel(uvSphere(1));
cone = createModel(uvCone(),[0,0,.5]);
cylinder = createModel(uvCylinder(),[0,0,1.5]);
disk = createModel(uvCylinder(5.5,0.5,64),[0,0,.25]);
ring = createModel(ring(3.3,4.8,40));
cube = createModel(cube());
// This controls the zoom and initial placement
rotator = new TrackballRotator(canvas,function() {
if (!animating)
draw();
},17,[0,1,2]);
draw();
}
</script>
</head>
I'm trying to render a sphere in webgl, im using a method from webglfundamentals but somehow in my programm the sphere is just rendered to 20%. In chrome i get this error: L ERROR :GL_INVALID_OPERATION : glDrawArrays: attempt to access out of range vertices in attribute 1
var canvas;
var gl;
var index = 0;
var pointsArray = [];
var normalsArray = [];
var indexArray = [];
var colorArray = [];
var near = -10;
var far = 10;
var radius = 1.5;
var theta = 0.0;
var phi = 0.0;
var dr = 5.0 * Math.PI/180.0;
var left = -3.0;
var right = 3.0;
var ytop =3.0;
var bottom = -3.0;
var va = vec4(0.0, 0.0, -1.0,1);
var vb = vec4(0.0, 0.942809, 0.333333, 1);
var vc = vec4(-0.816497, -0.471405, 0.333333, 1);
var vd = vec4(0.816497, -0.471405, 0.333333,1);
var lightPosition = vec4(0.0, 1.0, 1.0, 0.0 );
var lightAmbient = vec4(0.2, 0.2, 0.2, 1.0 );
var lightDiffuse = vec4( 1.0, 1.0, 1.0, 1.0 );
var lightSpecular = vec4( 1.0, 1.0, 1.0, 1.0 );
var materialAmbient = vec4( 1.0, 0.0, 1.0, 1.0 );
var materialDiffuse = vec4( 1.0, 0.0, 0.0, 1.0 );
var materialSpecular = vec4( 1.0, 0.8, 0.0, 1.0 );
var materialShininess = 100.0;
var ctm;
var ambientColor, diffuseColor, specularColor;
var texture;
var modelViewMatrix, projectionMatrix;
var modelViewMatrixLoc, projectionMatrixLoc;
var eye;
var at = vec3(0.0, 0.0, 0.0);
var up = vec3(0.0, 1.0, 0.0);
var iBuffer;
function createSphereVertices(
radius,
subdivisionsAxis,
subdivisionsHeight,
opt_startLatitudeInRadians,
opt_endLatitudeInRadians,
opt_startLongitudeInRadians,
opt_endLongitudeInRadians) {
if (subdivisionsAxis <= 0 || subdivisionsHeight <= 0) {
throw Error('subdivisionAxis and subdivisionHeight must be > 0');
}
opt_startLatitudeInRadians = opt_startLatitudeInRadians || 0;
opt_endLatitudeInRadians = opt_endLatitudeInRadians || Math.PI;
opt_startLongitudeInRadians = opt_startLongitudeInRadians || 0;
opt_endLongitudeInRadians = opt_endLongitudeInRadians || (Math.PI * 2);
var latRange = opt_endLatitudeInRadians - opt_startLatitudeInRadians;
var longRange = opt_endLongitudeInRadians - opt_startLongitudeInRadians;
// We are going to generate our sphere by iterating through its
// spherical coordinates and generating 2 triangles for each quad on a
// ring of the sphere.
// var numVertices = (subdivisionsAxis + 1) * (subdivisionsHeight + 1);
var positions = [];
// var normals = webglUtils.createAugmentedTypedArray(3, numVertices);
// var texCoords = webglUtils.createAugmentedTypedArray(2 , numVertices);
// Generate the individual vertices in our vertex buffer.
for (var y = 0; y <= subdivisionsHeight; y++) {
for (var x = 0; x <= subdivisionsAxis; x++) {
// Generate a vertex based on its spherical coordinates
var u = x / subdivisionsAxis;
var v = y / subdivisionsHeight;
var theta = longRange * u;
var phi = latRange * v;
var sinTheta = Math.sin(theta);
var cosTheta = Math.cos(theta);
var sinPhi = Math.sin(phi);
var cosPhi = Math.cos(phi);
var ux = cosTheta * sinPhi;
var uy = cosPhi;
var uz = sinTheta * sinPhi;
positions.push(vec4(radius * ux, radius * uy, radius * uz,1.0));
normalsArray.push(vec4(ux, uy, uz,1.0));
// texCoords.push(1 - u, v);
}
}
var numVertsAround = subdivisionsAxis + 1;
// var indices = webglUtils.createAugmentedTypedArray(3, subdivisionsAxis * subdivisionsHeight * 2, Uint16Array);
for (var x = 0; x < subdivisionsAxis; x++) {
for (var y = 0; y < subdivisionsHeight; y++) {
// Make triangle 1 of quad.
pointsArray.push(positions[(y + 0) * numVertsAround + x]);
pointsArray.push(positions[(y + 0) * numVertsAround + x + 1]);
pointsArray.push(positions[(y + 1) * numVertsAround + x]);
// Make triangle 2 of quad.
pointsArray.push(positions[(y + 1) * numVertsAround + x]);
pointsArray.push(positions[(y + 0) * numVertsAround + x + 1]);
pointsArray.push(positions[(y + 1) * numVertsAround + x + 1]);
index +=6;
}
}
}
window.onload = function init() {
canvas = document.getElementById( "gl-canvas" );
gl = WebGLUtils.setupWebGL( canvas );
if ( !gl ) { alert( "WebGL isn't available" ); }
gl.viewport( 0, 0, canvas.width, canvas.height );
gl.clearColor( 0.0, 0.0, 0.0, 1.0 );
gl.enable(gl.DEPTH_TEST);
//
// Load shaders and initialize attribute buffers
//
var program = initShaders( gl, "vertex-shader", "fragment-shader" );
gl.useProgram( program );
createSphereVertices(1,12,12);
ambientProduct = mult(lightAmbient, materialAmbient);
diffuseProduct = mult(lightDiffuse, materialDiffuse);
specularProduct = mult(lightSpecular, materialSpecular);
var nBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, nBuffer);
gl.bufferData( gl.ARRAY_BUFFER, flatten(normalsArray), gl.STATIC_DRAW );
var vNormal = gl.getAttribLocation( program, "vNormal" );
gl.vertexAttribPointer( vNormal, 4, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vNormal);
var vBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer);
gl.bufferData(gl.ARRAY_BUFFER, flatten(pointsArray), gl.STATIC_DRAW);
var vPosition = gl.getAttribLocation( program, "vPosition");
gl.vertexAttribPointer(vPosition, 4, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vPosition);
modelViewMatrixLoc = gl.getUniformLocation( program, "modelViewMatrix" );
projectionMatrixLoc = gl.getUniformLocation( program, "projectionMatrix" );
gl.uniform4fv( gl.getUniformLocation(program,
"ambientProduct"),flatten(ambientProduct) );
gl.uniform4fv( gl.getUniformLocation(program,
"diffuseProduct"),flatten(diffuseProduct) );
gl.uniform4fv( gl.getUniformLocation(program,
"specularProduct"),flatten(specularProduct) );
gl.uniform4fv( gl.getUniformLocation(program,
"lightPosition"),flatten(lightPosition) );
gl.uniform1f( gl.getUniformLocation(program,
"shininess"),materialShininess );
render();
}
function render() {
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
eye = vec3(radius*Math.sin(theta)*Math.cos(phi),
radius*Math.sin(theta)*Math.sin(phi), radius*Math.cos(theta));
modelViewMatrix = lookAt(eye, at , up);
projectionMatrix = ortho(left, right, bottom, ytop, near, far);
gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(modelViewMatrix) );
gl.uniformMatrix4fv(projectionMatrixLoc, false, flatten(projectionMatrix) );
for( var i=0; i<index; i+=3)
gl.drawArrays( gl.TRIANGLES, i, 3);
window.requestAnimFrame(render);
}
project1.html
<!DOCTYPE html>
<html>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition;
attribute vec4 vNormal;
varying vec3 N, L, E;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform vec4 lightPosition;
void main()
{
vec3 pos = -(modelViewMatrix * vPosition).xyz;
vec3 light = lightPosition.xyz;
L = normalize( light - pos );
E = -pos;
N = normalize( (modelViewMatrix*vNormal).xyz);
gl_Position = projectionMatrix * modelViewMatrix * vPosition;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
uniform vec4 ambientProduct;
uniform vec4 diffuseProduct;
uniform vec4 specularProduct;
uniform float shininess;
varying vec3 N, L, E;
void main()
{
vec4 fColor;
vec3 H = normalize( L + E );
vec4 ambient = ambientProduct;
float Kd = max( dot(L, N), 0.0 );
vec4 diffuse = Kd*diffuseProduct;
float Ks = pow( max(dot(N, H), 0.0), shininess );
vec4 specular = Ks * specularProduct;
if( dot(L, N) < 0.0 ) specular = vec4(0.0, 0.0, 0.0, 1.0);
fColor = ambient + diffuse +specular;
fColor.a = 1.0;
gl_FragColor = fColor;
}
</script>
<script type="text/javascript" src="./Common/webgl-utils.js"></script>
<script type="text/javascript" src="./Common/initShaders.js"></script>
<script type="text/javascript" src="./Common/MV.js"></script>
<script type="text/javascript" src="project1.js"></script>
<body>
<canvas id="gl-canvas" width="512" height="512">
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
</body>
</html>
This is what i get only a unfinished sphere:
I don't know this is actual correct answer since I didn't check this by running codes.
But, I just guess why this error occured.
Major reason of "out of range in attribute variable"
Basically, this will happen when the buffer you passed didn't have enough length.
Therefore, you need to check the count of buffer source you created.
And your error is ":GL_INVALID_OPERATION : glDrawArrays: attempt to access out of range vertices in attribute 1". In this case, attribute 1 in the error message means "vNormal" attribute in your GLSL code.
Because it is 2nd attribute variable in your GLSL code.
(If the error code says attribute 0, this problem should be made by vPosition)
As long as I saw your code, I think there is mismatch of length with normal buffer and position buffer.
Surface count in your code : Subdivision Height * Subdivision Axis * 2
Position element count in your code:Subdivision Height * Subdivision Axis *6
Normal element count in your code: Subdivision Height * Subdivision Axis * 4
I guess this is the reason of the problem.
Each vertex must have position and normal in this case, so your normal element count must be Subdivision Height * Subdivision Axis * 6
2nd argument in gl.vertexAttribPointer
I think you have mistake about 2nd argument in gl.vertexAttribPointer.
This is the count which means how many float elements needs to be passed each vertex.
In this case, you pushed 3 float elements for each vertex. So, you needs to specify 3 as argument for vPosition even if you used vec4 in your GLSL code.
By this argument, GPU can split these buffers for each vertex and pass them into vertex shader parallely.
4th element in vector
This is not strongly related to your question.But I found the code can be a reason of bug.
positions.push(vec4(radius * ux, radius * uy, radius * uz,1.0));
normalsArray.push(vec4(ux, uy, uz,1.0));
You need to understand what the meaning of 4th element in vec4. When this vector means coordinates, 4th element must be 1.However, when this vector means directions, 4th element must be 0.
Because, if this means directions, direction can not be affected by translation transform. ( I suggest you to learn affine transform to understand this)
So, you need to rewrite that code like this.
positions.push(vec4(radius * ux, radius * uy, radius * uz,1.0));
normalsArray.push(vec4(ux, uy, uz,0));
I hope this answer could help you...