webgl 中的着色
Shading in webgl
我一直在尝试在 webgl 中创建阴影,就像在这个图像中一样:在这里我们可以看到一个圆锥体、一个球体和一个光(我们可以用滑块改变他的位置)。
我试图通过从一些 webgl 辅导网站看到多个阴影示例在 html 文件中编写一些代码,但现在,我什至看不到形状。可以肯定我做错了什么,但我只是不知道在哪里。这是我的代码,我还包含一个 link 因为它包含多个文件。提前致谢。
Link: https://wetransfer.com/downloads/cd0f66f2e2866c0d118e95b02e01cb0520200923203442/274553
<html>
<head>
<title>Light and Shading</title>
<meta http-equiv='content-type' content='text/html; charset=ISO-8859-1'>
<!-- CSS Styles //-->
<link href='css/style.css' type='text/css' rel='stylesheet'>
<link href='css/desert.css' type='text/css' rel='stylesheet'/>
<link href='css/colorpicker.css' type='text/css' rel='stylesheet'/>
<link href='css/smoothness/jquery-ui-1.8.13.custom.css' type='text/css' rel='stylesheet' />
<!-- JavaScript Libraries //-->
<script type='text/javascript' src='js/gl-matrix-min.js'></script>
<script type='text/javascript' src='js/jquery-1.5.1.min.js'></script>
<script type='text/javascript' src='js/jquery-ui-1.8.13.custom.min.js'></script>
<script type='text/javascript' src='js/prettify.js'></script>
<script type='text/javascript' src='js/utils.js'></script>
<script type='text/javascript' src='js/colorpicker.js'></script>
<script type='text/javascript' src='js/codeview.js'></script>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec3 aVertexNormal;
// matrice model-view combinee.
uniform mat4 uMVMatrix;
// matrice de projection
uniform mat4 uPMatrix;
// matrice des normales.
uniform mat3 uNMatrix;
// position de la lumiere.
uniform vec3 uLightPosition;
// La normale transformee
varying vec3 vNormal;
// la direction vertex-lumiere
varying vec3 vLightRay;
// la direction camera-vertex
varying vec3 vEyeVec;
uniform vec4 uLightAmbient;
uniform vec4 uLightDiffuse;
uniform vec4 uLightSpecular;
uniform vec4 uMaterialAmbient;
uniform vec4 uMaterialDiffuse;
uniform vec4 uMaterialSpecular;
void main(void) {
vec4 ambientProduct= uLightAmbient* uMaterialAmbient;
vec4 diffuseProduct= uLightDiffuse*uMaterialDiffuse;
vec4 specularProduct= uLightSpecular*uMaterialSpecular;
vec3 pos = (uMVMatrix*vec4(aVertexPosition, 1.0)).xyz;
// position de l'oeil/camera.
const vec3 eyePosition = vec3(0,0,-40);
//Transformed normal position
vNormal = normalize((uNMatrix* aVertexNormal).xyz) ;
//Transformed light position
vec4 light = uMVMatrix * vec4(uLightPosition,1.0);
vec3 lightPos = (uMVMatrix * light).xyz;
//Light position
vLightRay = normalize(pos - lightPos);
//Vector Eye
vEyeVec = -normalize(pos);
//Final vertex position
gl_Position = uMVMatrix*uPMatrix* vec4(aVertexPosition, 1.0);
}
</script>
<script id="shader-fs" type="x-shader/x-fragment">
#ifdef GL_ES
precision highp float;
#endif
varying vec3 vNormal;
varying vec3 vLightRay;
varying vec3 vEyeVec;
uniform vec4 ambientProduct;
uniform vec4 diffuseProduct;
uniform vec4 specularProduct;
uniform float uShininess;
void main(void)
{
vec4 diffuse = max(dot( vNormal,vLightRay), 0.0) * diffuseProduct;
vec3 H = normalize(vLightRay+vEyeVec);
vec4 specular =
pow(max(dot(vNormal, H), 0.0), uShininess) * specularProduct;
if (dot(vLightRay, vNormal) < 0.0)
specular = vec4(0.0, 0.0, 0.0, 1.0);
vec4 fColor = ambientProduct + diffuse + specular;
fColor.a = 1.0;
gl_FragColor =fColor;
}
</script>
<script id='code-js' type="text/javascript">
var gl = null; // WebGL context
var prg = null; // The program (shaders)
var c_width = 0; // Variable to store the width of the canvas
var c_height = 0; // Variable to store the height of the canvas
var mvMatrix = mat4.create(); // The Model-View matrix
var pMatrix = mat4.create(); // The projection matrix
var nMatrix = mat4.create(); // The normal matrix
var distance = -40;
var animateFlag = false;
var objects = [];
/**
* The program contains a series of instructions that tell the Graphic Processing Unit (GPU)
* what to do with every vertex and fragment that we pass it.
* The vertex shader and the fragment shader together are called the program.
*/
function initProgram() {
var fragmentShader = utils.getShader(gl, "shader-fs");
var vertexShader = utils.getShader(gl, "shader-vs");
prg = gl.createProgram();
gl.attachShader(prg, vertexShader);
gl.attachShader(prg, fragmentShader);
gl.linkProgram(prg);
if (!gl.getProgramParameter(prg, gl.LINK_STATUS)) {
alert("Could not initialise shaders");
}
gl.useProgram(prg);
prg.aVertexPosition = gl.getAttribLocation(prg, "aVertexPosition");
prg.aVertexNormal = gl.getAttribLocation(prg, "aVertexNormal");
prg.uPMatrix = gl.getUniformLocation(prg, "uPMatrix");
prg.uMVMatrix = gl.getUniformLocation(prg, "uMVMatrix");
prg.uNMatrix = gl.getUniformLocation(prg, "uNMatrix");
prg.uMaterialAmbient = gl.getUniformLocation(prg, "uMaterialAmbient");
prg.uMaterialDiffuse = gl.getUniformLocation(prg, "uMaterialDiffuse");
prg.uMaterialSpecular = gl.getUniformLocation(prg, "uMaterialSpecular");
prg.uShininess = gl.getUniformLocation(prg, "uShininess");
prg.uLightPosition = gl.getUniformLocation(prg, "uLightPosition");
prg.uLightAmbient = gl.getUniformLocation(prg, "uLightAmbient");
prg.uLightDiffuse = gl.getUniformLocation(prg, "uLightDiffuse");
prg.uLightSpecular = gl.getUniformLocation(prg, "uLightSpecular");
}
function initLights(){
//Light uniforms
gl.uniform3fv(prg.uLightPosition,[4.5,3.0,15.0]);
gl.uniform4f(prg.uLightAmbient ,1.0,1.0,1.0,1.0);
gl.uniform4f(prg.uLightDiffuse,1.0,1.0,1.0,1.0);
gl.uniform4f(prg.uLightSpecular,1.0,1.0,1.0,1.0);
//Object Uniforms
gl.uniform4f(prg.uMaterialAmbient, 0.1,0.1,0.1,1.0);
gl.uniform4f(prg.uMaterialDiffuse, 0.5,0.8,0.1,1.0);
gl.uniform4f(prg.uMaterialSpecular, 0.6,0.6,0.6,1.0);
gl.uniform1f(prg.uShininess, 200.0);
}
/**
* Creates an AJAX request to load the scene asynchronously
*/
function loadScene(){
loadObject('models/plane.json');
loadObject('models/cone.json','cone');
loadObject('models/sphere.json','sphere');
loadObject('models/smallsph.json','lightsource');
}
function getObject(alias){
for(var i=0; i<objects.length; i++){
if (alias == objects[i].alias) return objects[i];
}
return null;
}
/**
* Ajax and JSON in action
*/
function loadObject(filename,alias){
var request = new XMLHttpRequest();
console.info('Requesting ' + filename);
request.open("GET",filename);
request.onreadystatechange = function() {
if (request.readyState == 4) {
if(request.status == 404) {
console.info(filename + ' does not exist');
}
else {
var o = JSON.parse(request.responseText);
o.alias = (alias==null)?'none':alias;
handleLoadedObject(filename,o);
}
}
}
request.send();
}
/**
* Creates the buffers that contain the geometry of the object
*/
function handleLoadedObject(filename,object) {
console.info(filename + ' has been retrieved from the server');
var vertexBufferObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBufferObject);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(object.vertices), gl.STATIC_DRAW);
var normalBufferObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, normalBufferObject);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(calcNormals(object.vertices, object.indices)), gl.STATIC_DRAW);
var indexBufferObject = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBufferObject);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(object.indices), gl.STATIC_DRAW);
object.vbo = vertexBufferObject;
object.ibo = indexBufferObject;
object.nbo = normalBufferObject;
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
gl.bindBuffer(gl.ARRAY_BUFFER,null);
objects.push(object);
}
/**
* Main rendering function. Called every 500ms according to WebGLStart function (see below)
*/
function drawScene() {
gl.clearColor(0.3,0.3,0.3, 1.0);
gl.clearDepth(100.0);
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
gl.viewport(0, 0, c_width, c_height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.perspective(60, c_width / c_height, 0.1, 1000.0, pMatrix);
try{
gl.enableVertexAttribArray(prg.aVertexPosition);
gl.enableVertexAttribArray(prg.aVertexNormal);
for (var i = 0; i < objects.length; i++){
var object = objects[i];
mat4.identity(mvMatrix);
mat4.translate(mvMatrix, [0.0, 0.0, distance]); //Sets the camera to a reasonable distance to view the part
mat4.rotate(mvMatrix, 30*Math.PI/180, [1,0,0]);
mat4.rotate(mvMatrix, angle*Math.PI/180, [0,1,0]);
if (object.alias == 'lightsource'){
var lightPos = gl.getUniform(prg, prg.uLightPosition);
mat4.translate(mvMatrix,lightPos);
}
gl.uniformMatrix4fv(prg.uMVMatrix, false, mvMatrix);
gl.uniformMatrix4fv(prg.uPMatrix, false, pMatrix);
mat4.set(mvMatrix, nMatrix);
mat4.inverse(nMatrix);
mat4.transpose(nMatrix);
gl.uniformMatrix4fv(prg.uNMatrix, false, nMatrix);
gl.uniform4fv(prg.uMaterialAmbient, object.ambient);
gl.uniform4fv(prg.uMaterialDiffuse, object.diffuse);
gl.uniform4fv(prg.uMaterialSpecular, object.specular);
gl.bindBuffer(gl.ARRAY_BUFFER, object.vbo);
gl.vertexAttribPointer(prg.aVertexPosition, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(prg.aVertexPosition);
gl.bindBuffer(gl.ARRAY_BUFFER, object.nbo);
gl.vertexAttribPointer(prg.aVertexNormal, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(prg.aVertexNormal);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, object.ibo);
gl.drawElements(gl.TRIANGLES, object.indices.length, gl.UNSIGNED_SHORT,0);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
}
}
catch(err){
alert(err);
message(err.description);
}
}
var lastTime = 0;
var angle = 0;
/**
* Updates the angle of rotation by a little bit each time
*/
function animate() {
var timeNow = new Date().getTime();
if (lastTime != 0) {
var elapsed = timeNow - lastTime;
if (animateFlag) angle += (90 * elapsed) / 10000.0;
}
lastTime = timeNow;
}
/**
* Render Loop
*/
function renderLoop() {
requestAnimFrame(renderLoop);
drawScene();
animate();
}
/**
* Entry point. This function is invoked when the page is loaded
*/
function runWebGLApp() {
//Obtains a WebGL context
gl = utils.getGLContext("canvas-element-id");
//Initializes the program (shaders)
initProgram();
//Initializes lights
initLights();
//Load Scene
loadScene();
//Renders the scene!
renderLoop();
}
</script>
</head>
<body onLoad='runWebGLApp()'>
<div id='top'>
<div id='contents'>
<div id='canvasContainer'>
<canvas id='canvas-element-id' width='480' height='400'>
Your browser does not support the HTML5 canvas element.
</canvas>
</div>
</div>
<div id='bottom'>
<table style='padding=0px'>
<tr>
<td>X:</td><td id='slider-x-value' width='30px'>4.5</td><td width='150px'><div id='slider-x'/></td>
</tr>
<tr>
<td>Y:</td><td id='slider-y-value' width='30px'>3.0</td><td width='150px'><div id='slider-y'/></td>
</tr>
<tr>
<td>Z:</td> <td id='slider-z-value' width='30px'>15.0</td><td width='150px'><div id='slider-z'/></td>
</tr>
</table>
</div>
<script>cview.run(cview.MODE_VIEW);</script>
<script>
$('#slider-shininess').slider({value:200, min:1, max:300, step:1, slide:updateShininess});
$('#slider-x').slider({value:4.5, min:-50, max:50, step:0.1, slide:updateLightPosition, change:updateLightPosition});
$('#slider-y').slider({value:3.0, min:0, max:50, step:0.1, slide:updateLightPosition, change:updateLightPosition});
$('#slider-z').slider({value:15.0, min:-50, max:50, step:0.1, slide:updateLightPosition, change:updateLightPosition});
$('#animate-btn').button();
$('#animate-btn').click(
function(){
if ($('#animate-btn:checked').val()==null){
animateFlag = false;
}
else{
animateFlag = true;
}
});
function updateShininess(){
var v = $('#slider-shininess').slider("value");
gl.uniform1f(prg.uShininess, v);
$('#slider-shininess-value').html(v);
}
function updateLightPosition(){
var x = $('#slider-x').slider("value");
var y = $('#slider-y').slider("value");
var z = $('#slider-z').slider("value");
gl.uniform3fv(prg.uLightPosition, [x,y,z]);
$('#slider-x-value').html(x);
$('#slider-y-value').html(y);
$('#slider-z-value').html(z);
}
function updateDistance(){
var d = $('#slider-distance').slider("value");
$('#slider-distance-value').html(distance);
distance = -d;
}
function updateObjectColor(alias, r,g,b){
var object = getObject(alias);
if (object != null){
object.diffuse = [r,g,b,1.0];
}
}
$('#colorSelectorSphere').ColorPicker({
onSubmit: function(hsb, hex, rgb, el) {
$(el).val(hex);
$(el).ColorPickerHide();
},
color: '#00ff00',
onShow: function (colpkr) {
$(colpkr).fadeIn(500);
return false;
},
onHide: function (colpkr) {
$(colpkr).fadeOut(500);
return false;
},
onChange: function (hsb, hex, rgb) {
$('#colorSelectorSphere div').css('backgroundColor', '#' + hex);
updateObjectColor('sphere',rgb.r/256,rgb.g/256,rgb.b/256);
},
onBeforeShow: function (colpkr) {
$(this).ColorPickerSetColor('rgb(0.5,0.8,0.1)');
}
})
$('#colorSelectorCone').ColorPicker({
onSubmit: function(hsb, hex, rgb, el) {
$(el).val(hex);
$(el).ColorPickerHide();
},
color: '#00ff00',
onShow: function (colpkr) {
$(colpkr).fadeIn(500);
return false;
},
onHide: function (colpkr) {
$(colpkr).fadeOut(500);
return false;
},
onChange: function (hsb, hex, rgb) {
$('#colorSelectorCone div').css('backgroundColor', '#' + hex);
updateObjectColor('cone',rgb.r/256,rgb.g/256,rgb.b/256);
},
onBeforeShow: function (colpkr) {
$(this).ColorPickerSetColor('rgb(0.8,0.1,0.5)');
}
})
// Calcule les normales des vertex. La normale de chaque vertex est
// la moyenne des triangles voisins.
//
// vertices: la liste des vertex.
// ind: la liste des indices.
// retour: la liste des normales par vertex.
function calcNormals(vertices, ind){
var x=0;
var y=1;
var z=2;
var v1 = [], v2 = [], thisNormal = [];
// initialiser la liste des normales.
var ns = [];
for(var i=0;i<vertices.length;i++)
{
ns[i]=0.0;
}
for(var i=0;i<ind.length;i=i+3){
//v1 = p1 - p0
v1[x] = vertices[3*ind[i+1]+x] - vertices[3*ind[i]+x];
v1[y] = vertices[3*ind[i+1]+y] - vertices[3*ind[i]+y];
v1[z] = vertices[3*ind[i+1]+z] - vertices[3*ind[i]+z];
// v2 = p2 - p1
v2[x] = vertices[3*ind[i+2]+x] - vertices[3*ind[i]+x];
v2[y] = vertices[3*ind[i+2]+y] - vertices[3*ind[i]+y];
v2[z] = vertices[3*ind[i+2]+z] - vertices[3*ind[i]+z];
// N = v2 x v1 (cross product).
thisNormal[x] = v1[y]*v2[z] - v1[z]*v2[y];
thisNormal[y] = v1[z]*v2[x] - v1[x]*v2[z];
thisNormal[z] = v1[x]*v2[y] - v1[y]*v2[x];
for(j=0;j<3;j++)
{
// N += thisNormal. on additionne les normales.
ns[3*ind[i+j]+x] = ns[3*ind[i+j]+x] + thisNormal[x];
ns[3*ind[i+j]+y] = ns[3*ind[i+j]+y] + thisNormal[y];
ns[3*ind[i+j]+z] = ns[3*ind[i+j]+z] + thisNormal[z];
}
}
// Normalisation.
for(var i=0;i<vertices.length;i=i+3){
var nn=[];
var len = 0;
for(var j = 0; j < 3; j++)
{
nn[j] = ns[i+j];
len += nn[j] * nn[j];
}
// La norme de la normale.
len = Math.sqrt(len);
if (len == 0)
len = 0.00001;
for(var j = 0; j < 3; j++)
ns[i+j] = nn[j] / len;
console.log(len);
}
return ns;
}
</script>
</body>
</html>
老实说,要涵盖的问题太多了。试图让你的代码工作。首先,您确实需要学习如何制作最小的回购协议。您发布的代码没有运行,引用了几个不存在的脚本和不存在的数据。
代码所基于的教程似乎很旧。 2020 年没有人使用 XMLHttpRequest。没有 requestAnimFrame
的功能,它是 requestAnimationFrame
。我认为这是 2011 年的 polyfill 遗留下来的。它仍在使用 <body onload="">
,很少有人再使用了。它还使用 new Date().getTime()
,因为时间被传递到 requestAnimationFrame
,所以没有理由使用它。它正在调用一些函数来获取 webgl 上下文,但在 2020 年也没有理由这样做。它显然也在使用旧版本的 glMatrix,因为 the current version 使用不同的 API。在当前版本中,每个函数都采用一个矩阵来存储结果作为第一个参数。同样在当前版本中,perspective
以弧度表示视野。我不知道它过去是否以度为单位,但代码正在传递度数。
我将 XHR 代码更改为 return 一个立方体。 (“最小完整可验证示例”(mcve) 的最小和完整部分示例 - 我认为现在 S.O 称它们为“最小可复制示例”。我还删除了对 ColorPicker
的所有引用(制作最小回购的另一个例子)
代码应该在 the JavaScript console 中出现错误。你检查过 JavaScript 控制台了吗?特别是 uNMatrix
是一个 mat3 但代码调用 gl.uniformMatrix4fv
来设置它是一个错误。
使用 webgl-lint 指出几个制服没有被设置,包括“ambientProduct”、“diffuseProduct”、“specularProduct”,还有几个被设置的不存在(那部分不一定是错误)但是顶点着色器中有几个制服实际上没有使用,例如颜色似乎设置为
gl.uniform4fv(prg.uMaterialAmbient, object.ambient);
gl.uniform4fv(prg.uMaterialDiffuse, object.diffuse);
gl.uniform4fv(prg.uMaterialSpecular, object.specular);
但是着色器中没有使用这些制服(它们出现在着色器中,但如果您查看代码,您将看不到任何效果)
然后,当我最终消除所有错误时,剩下的问题是 gl_Position
的数学运算将 2 个矩阵倒置。它应该是 projection * modelView * position
但它有 modelView * projection * position
但是,此外,所有 3 个模型都绘制在相同的位置。也许这些模型中的几何图形处于不同的位置。我不知道,但通常你会根据循环索引或一些位置数组或每个对象数据,以某种形式给你绘制的每个东西它自己的位置。
无论如何,屏幕上出现了一些东西,但已经花了 45 分钟,我不想尝试修复照明。相反,我建议您阅读一些稍微更新的教程,例如 this one 及其链接到的教程。
var mat4 = glMatrix.mat4;
var gl = null; // WebGL context
var prg = null; // The program (shaders)
var c_width = 480; // Variable to store the width of the canvas
var c_height = 400; // Variable to store the height of the canvas
var mvMatrix = mat4.create(); // The Model-View matrix
var pMatrix = mat4.create(); // The projection matrix
var nMatrix = mat4.create(); // The normal matrix
var distance = -40;
var animateFlag = false;
var objects = [];
const utils = {
getShader(gl, id) {
const elem = document.getElementById(id);
const type = /vertex/.test(elem.type) ?
gl.VERTEX_SHADER :
gl.FRAGMENT_SHADER;
const sh = gl.createShader(type);
gl.shaderSource(sh, elem.text);
gl.compileShader(sh);
if (!gl.getShaderParameter(sh, gl.COMPILE_STATUS)) {
throw new Error(gl.getShaderInfoLog(sh));
}
return sh;
},
};
/**
* The program contains a series of instructions that tell the Graphic Processing Unit (GPU)
* what to do with every vertex and fragment that we pass it.
* The vertex shader and the fragment shader together are called the program.
*/
function initProgram() {
var fragmentShader = utils.getShader(gl, "shader-fs");
var vertexShader = utils.getShader(gl, "shader-vs");
prg = gl.createProgram();
gl.attachShader(prg, vertexShader);
gl.attachShader(prg, fragmentShader);
gl.linkProgram(prg);
if (!gl.getProgramParameter(prg, gl.LINK_STATUS)) {
alert("Could not initialise shaders");
}
gl.useProgram(prg);
prg.aVertexPosition = gl.getAttribLocation(prg, "aVertexPosition");
prg.aVertexNormal = gl.getAttribLocation(prg, "aVertexNormal");
prg.uPMatrix = gl.getUniformLocation(prg, "uPMatrix");
prg.uMVMatrix = gl.getUniformLocation(prg, "uMVMatrix");
prg.uNMatrix = gl.getUniformLocation(prg, "uNMatrix");
prg.uMaterialAmbient = gl.getUniformLocation(prg, "uMaterialAmbient");
prg.uMaterialDiffuse = gl.getUniformLocation(prg, "uMaterialDiffuse");
prg.uMaterialSpecular = gl.getUniformLocation(prg, "uMaterialSpecular");
prg.uShininess = gl.getUniformLocation(prg, "uShininess");
prg.uLightPosition = gl.getUniformLocation(prg, "uLightPosition");
prg.uLightAmbient = gl.getUniformLocation(prg, "uLightAmbient");
prg.uLightDiffuse = gl.getUniformLocation(prg, "uLightDiffuse");
prg.uLightSpecular = gl.getUniformLocation(prg, "uLightSpecular");
prg.ambientProduct = gl.getUniformLocation(prg, "ambientProduct");
prg.diffuseProduct = gl.getUniformLocation(prg, "diffuseProduct");
prg.specularProduct = gl.getUniformLocation(prg, "specularProduct");
}
function initLights() {
//Light uniforms
gl.uniform3fv(prg.uLightPosition, [4.5, 3.0, 15.0]);
gl.uniform4f(prg.uLightAmbient, 1.0, 1.0, 1.0, 1.0);
gl.uniform4f(prg.uLightDiffuse, 1.0, 1.0, 1.0, 1.0);
gl.uniform4f(prg.uLightSpecular, 1.0, 1.0, 1.0, 1.0);
//Object Uniforms
gl.uniform4f(prg.uMaterialAmbient, 0.1, 0.1, 0.1, 1.0);
gl.uniform4f(prg.uMaterialDiffuse, 0.5, 0.8, 0.1, 1.0);
gl.uniform4f(prg.uMaterialSpecular, 0.6, 0.6, 0.6, 1.0);
gl.uniform1f(prg.uShininess, 200.0);
}
/**
* Creates an AJAX request to load the scene asynchronously
*/
function loadScene() {
loadObject('models/plane.json');
loadObject('models/cone.json', 'cone');
loadObject('models/sphere.json', 'sphere');
loadObject('models/smallsph.json', 'lightsource');
}
function getObject(alias) {
for (var i = 0; i < objects.length; i++) {
if (alias == objects[i].alias) return objects[i];
}
return null;
}
/**
* Ajax and JSON in action
*/
const vertices = [
-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,
];
let modelNum = 0
function loadObject(filename, alias) {
setTimeout(() => {
const o = {
alias: (alias == null) ? 'none' : alias,
ambient: [0.1, 0.1, 0.1, 1],
diffuse: [Math.random(), Math.random(), Math.random(), 1],
specular: [1, 1, 1, 1],
// to make up for the fact the code does not have different positions
// for each model we'll move the vertices (bad)
vertices: vertices.map((v, i) => i % 3 === 0 ? v + modelNum * 3 : v),
indices: [
0, 1, 2, 2, 1, 3,
4, 5, 6, 6, 5, 7,
8, 9, 10, 10, 9, 11,
12, 13, 14, 14, 13, 15,
16, 17, 18, 18, 17, 19,
20, 21, 22, 22, 21, 23,
],
};
handleLoadedObject(filename, o);
++modelNum;
});
}
/**
* Creates the buffers that contain the geometry of the object
*/
function handleLoadedObject(filename, object) {
//console.info(filename + ' has been retrieved from the server');
var vertexBufferObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBufferObject);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(object.vertices), gl.STATIC_DRAW);
var normalBufferObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, normalBufferObject);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(calcNormals(object.vertices, object.indices)), gl.STATIC_DRAW);
var indexBufferObject = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBufferObject);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(object.indices), gl.STATIC_DRAW);
object.vbo = vertexBufferObject;
object.ibo = indexBufferObject;
object.nbo = normalBufferObject;
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
objects.push(object);
}
/**
* Main rendering function. Called every 500ms according to WebGLStart function (see below)
*/
function drawScene() {
gl.clearColor(0.3, 0.3, 0.3, 1.0);
//gl.clearDepth(100.0);
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
gl.viewport(0, 0, c_width, c_height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.perspective(pMatrix, 60 * Math.PI / 180, c_width / c_height, 0.1, 1000.0);
gl.enableVertexAttribArray(prg.aVertexPosition);
gl.enableVertexAttribArray(prg.aVertexNormal);
for (var i = 0; i < objects.length; i++) {
var object = objects[i];
mat4.identity(mvMatrix);
mat4.translate(mvMatrix, mvMatrix, [0.0, 0.0, distance]); //Sets the camera to a reasonable distance to view the part
mat4.rotate(mvMatrix, mvMatrix, 30 * Math.PI / 180, [1, 0, 0]);
mat4.rotate(mvMatrix, mvMatrix, angle * Math.PI / 180, [0, 1, 0]);
if (object.alias == 'lightsource') {
var lightPos = gl.getUniform(prg, prg.uLightPosition);
mat4.translate(mvMatrix, mvMatrix, lightPos);
}
gl.uniformMatrix4fv(prg.uMVMatrix, false, mvMatrix);
gl.uniformMatrix4fv(prg.uPMatrix, false, pMatrix);
mat4.set(mvMatrix, nMatrix);
mat4.invert(nMatrix, nMatrix);
mat4.transpose(nMatrix, nMatrix);
const t3 = glMatrix.mat3.create();
glMatrix.mat3.fromMat4(t3, nMatrix);
gl.uniformMatrix3fv(prg.uNMatrix, false, t3);
gl.uniform4fv(prg.ambientProduct, object.ambient);
gl.uniform4fv(prg.diffuseProduct, object.diffuse);
gl.uniform4fv(prg.specularProduct, object.specular);
gl.bindBuffer(gl.ARRAY_BUFFER, object.vbo);
gl.vertexAttribPointer(prg.aVertexPosition, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(prg.aVertexPosition);
gl.bindBuffer(gl.ARRAY_BUFFER, object.nbo);
gl.vertexAttribPointer(prg.aVertexNormal, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(prg.aVertexNormal);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, object.ibo);
gl.drawElements(gl.TRIANGLES, object.indices.length, gl.UNSIGNED_SHORT, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
}
}
var lastTime = 0;
var angle = 0;
/**
* Updates the angle of rotation by a little bit each time
*/
function animate() {
var timeNow = new Date().getTime();
if (lastTime != 0) {
var elapsed = timeNow - lastTime;
if (animateFlag) angle += (90 * elapsed) / 10000.0;
}
lastTime = timeNow;
}
/**
* Render Loop
*/
function renderLoop() {
drawScene();
animate();
requestAnimationFrame(renderLoop);
}
/**
* Entry point. This function is invoked when the page is loaded
*/
function runWebGLApp() {
//Obtains a WebGL context
gl = document.getElementById("canvas-element-id").getContext('webgl');
//Initializes the program (shaders)
initProgram();
//Initializes lights
initLights();
//Load Scene
loadScene();
//Renders the scene!
renderLoop();
}
$('#slider-shininess').slider({
value: 200,
min: 1,
max: 300,
step: 1,
slide: updateShininess
});
$('#slider-x').slider({
value: 4.5,
min: -50,
max: 50,
step: 0.1,
slide: updateLightPosition,
change: updateLightPosition
});
$('#slider-y').slider({
value: 3.0,
min: 0,
max: 50,
step: 0.1,
slide: updateLightPosition,
change: updateLightPosition
});
$('#slider-z').slider({
value: 15.0,
min: -50,
max: 50,
step: 0.1,
slide: updateLightPosition,
change: updateLightPosition
});
$('#animate-btn').button();
$('#animate-btn').click(
function() {
if ($('#animate-btn:checked').val() == null) {
animateFlag = false;
} else {
animateFlag = true;
}
});
function updateShininess() {
var v = $('#slider-shininess').slider("value");
gl.uniform1f(prg.uShininess, v);
$('#slider-shininess-value').html(v);
}
function updateLightPosition() {
var x = $('#slider-x').slider("value");
var y = $('#slider-y').slider("value");
var z = $('#slider-z').slider("value");
gl.uniform3fv(prg.uLightPosition, [x, y, z]);
$('#slider-x-value').html(x);
$('#slider-y-value').html(y);
$('#slider-z-value').html(z);
}
function updateDistance() {
var d = $('#slider-distance').slider("value");
$('#slider-distance-value').html(distance);
distance = -d;
}
function updateObjectColor(alias, r, g, b) {
var object = getObject(alias);
if (object != null) {
object.diffuse = [r, g, b, 1.0];
}
}
// Calcule les normales des vertex. La normale de chaque vertex est
// la moyenne des triangles voisins.
//
// vertices: la liste des vertex.
// ind: la liste des indices.
// retour: la liste des normales par vertex.
function calcNormals(vertices, ind) {
var x = 0;
var y = 1;
var z = 2;
var v1 = [],
v2 = [],
thisNormal = [];
// initialiser la liste des normales.
var ns = [];
for (var i = 0; i < vertices.length; i++) {
ns[i] = 0.0;
}
for (var i = 0; i < ind.length; i = i + 3) {
//v1 = p1 - p0
v1[x] = vertices[3 * ind[i + 1] + x] - vertices[3 * ind[i] + x];
v1[y] = vertices[3 * ind[i + 1] + y] - vertices[3 * ind[i] + y];
v1[z] = vertices[3 * ind[i + 1] + z] - vertices[3 * ind[i] + z];
// v2 = p2 - p1
v2[x] = vertices[3 * ind[i + 2] + x] - vertices[3 * ind[i] + x];
v2[y] = vertices[3 * ind[i + 2] + y] - vertices[3 * ind[i] + y];
v2[z] = vertices[3 * ind[i + 2] + z] - vertices[3 * ind[i] + z];
// N = v2 x v1 (cross product).
thisNormal[x] = v1[y] * v2[z] - v1[z] * v2[y];
thisNormal[y] = v1[z] * v2[x] - v1[x] * v2[z];
thisNormal[z] = v1[x] * v2[y] - v1[y] * v2[x];
for (j = 0; j < 3; j++) {
// N += thisNormal. on additionne les normales.
ns[3 * ind[i + j] + x] = ns[3 * ind[i + j] + x] + thisNormal[x];
ns[3 * ind[i + j] + y] = ns[3 * ind[i + j] + y] + thisNormal[y];
ns[3 * ind[i + j] + z] = ns[3 * ind[i + j] + z] + thisNormal[z];
}
}
// Normalisation.
for (var i = 0; i < vertices.length; i = i + 3) {
var nn = [];
var len = 0;
for (var j = 0; j < 3; j++) {
nn[j] = ns[i + j];
len += nn[j] * nn[j];
}
// La norme de la normale.
len = Math.sqrt(len);
if (len == 0)
len = 0.00001;
for (var j = 0; j < 3; j++)
ns[i + j] = nn[j] / len;
}
return ns;
}
runWebGLApp();
<link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet">
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec3 aVertexNormal;
// matrice model-view combinee.
uniform mat4 uMVMatrix;
// matrice de projection
uniform mat4 uPMatrix;
// matrice des normales.
uniform mat3 uNMatrix;
// position de la lumiere.
uniform vec3 uLightPosition;
// La normale transformee
varying vec3 vNormal;
// la direction vertex-lumiere
varying vec3 vLightRay;
// la direction camera-vertex
varying vec3 vEyeVec;
uniform vec4 uLightAmbient;
uniform vec4 uLightDiffuse;
uniform vec4 uLightSpecular;
uniform vec4 uMaterialAmbient;
uniform vec4 uMaterialDiffuse;
uniform vec4 uMaterialSpecular;
void main(void) {
vec4 ambientProduct= uLightAmbient* uMaterialAmbient;
vec4 diffuseProduct= uLightDiffuse*uMaterialDiffuse;
vec4 specularProduct= uLightSpecular*uMaterialSpecular;
vec3 pos = (uMVMatrix*vec4(aVertexPosition, 1.0)).xyz;
// position de l'oeil/camera.
const vec3 eyePosition = vec3(0,0,-40);
//Transformed normal position
vNormal = normalize((uNMatrix* aVertexNormal).xyz) ;
//Transformed light position
vec4 light = uMVMatrix * vec4(uLightPosition,1.0);
vec3 lightPos = (uMVMatrix * light).xyz;
//Light position
vLightRay = normalize(pos - lightPos);
//Vector Eye
vEyeVec = -normalize(pos);
//Final vertex position
gl_Position = uPMatrix*uMVMatrix* vec4(aVertexPosition, 1.0);
}
</script>
<script id="shader-fs" type="x-shader/x-fragment">
#ifdef GL_ES
precision highp float;
#endif
varying vec3 vNormal;
varying vec3 vLightRay;
varying vec3 vEyeVec;
uniform vec4 ambientProduct;
uniform vec4 diffuseProduct;
uniform vec4 specularProduct;
uniform float uShininess;
void main(void)
{
vec4 diffuse = max(dot( vNormal,vLightRay), 0.0) * diffuseProduct;
vec3 H = normalize(vLightRay+vEyeVec);
vec4 specular =
pow(max(dot(vNormal, H), 0.0), uShininess) * specularProduct;
if (dot(vLightRay, vNormal) < 0.0)
specular = vec4(0.0, 0.0, 0.0, 1.0);
vec4 fColor = ambientProduct + diffuse + specular;
fColor.a = 1.0;
gl_FragColor =fColor;
}
</script>
<div id='top'>
<div id='contents'>
<div id='canvasContainer'>
<canvas id='canvas-element-id' width='480' height='400'>
Your browser does not support the HTML5 canvas element.
</canvas>
</div>
</div>
<div id='bottom'>
<table style='padding=0px'>
<tr>
<td>X:</td><td id='slider-x-value' width='30px'>4.5</td><td width='150px'><div id='slider-x'/></td>
</tr>
<tr>
<td>Y:</td><td id='slider-y-value' width='30px'>3.0</td><td width='150px'><div id='slider-y'/></td>
</tr>
<tr>
<td>Z:</td> <td id='slider-z-value' width='30px'>15.0</td><td width='150px'><div id='slider-z'/></td>
</tr>
</table>
</div>
<script src="https://cdn.jsdelivr.net/npm/gl-matrix@3.3.0/gl-matrix-min.js"></script>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<script src="https://greggman.github.io/webgl-lint/webgl-lint.js"
data-gman-debug-helper='
{
"warnUndefinedUniforms": false
}
'
></script>
我一直在尝试在 webgl 中创建阴影,就像在这个图像中一样:在这里我们可以看到一个圆锥体、一个球体和一个光(我们可以用滑块改变他的位置)。
我试图通过从一些 webgl 辅导网站看到多个阴影示例在 html 文件中编写一些代码,但现在,我什至看不到形状。可以肯定我做错了什么,但我只是不知道在哪里。这是我的代码,我还包含一个 link 因为它包含多个文件。提前致谢。
Link: https://wetransfer.com/downloads/cd0f66f2e2866c0d118e95b02e01cb0520200923203442/274553
<html>
<head>
<title>Light and Shading</title>
<meta http-equiv='content-type' content='text/html; charset=ISO-8859-1'>
<!-- CSS Styles //-->
<link href='css/style.css' type='text/css' rel='stylesheet'>
<link href='css/desert.css' type='text/css' rel='stylesheet'/>
<link href='css/colorpicker.css' type='text/css' rel='stylesheet'/>
<link href='css/smoothness/jquery-ui-1.8.13.custom.css' type='text/css' rel='stylesheet' />
<!-- JavaScript Libraries //-->
<script type='text/javascript' src='js/gl-matrix-min.js'></script>
<script type='text/javascript' src='js/jquery-1.5.1.min.js'></script>
<script type='text/javascript' src='js/jquery-ui-1.8.13.custom.min.js'></script>
<script type='text/javascript' src='js/prettify.js'></script>
<script type='text/javascript' src='js/utils.js'></script>
<script type='text/javascript' src='js/colorpicker.js'></script>
<script type='text/javascript' src='js/codeview.js'></script>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec3 aVertexNormal;
// matrice model-view combinee.
uniform mat4 uMVMatrix;
// matrice de projection
uniform mat4 uPMatrix;
// matrice des normales.
uniform mat3 uNMatrix;
// position de la lumiere.
uniform vec3 uLightPosition;
// La normale transformee
varying vec3 vNormal;
// la direction vertex-lumiere
varying vec3 vLightRay;
// la direction camera-vertex
varying vec3 vEyeVec;
uniform vec4 uLightAmbient;
uniform vec4 uLightDiffuse;
uniform vec4 uLightSpecular;
uniform vec4 uMaterialAmbient;
uniform vec4 uMaterialDiffuse;
uniform vec4 uMaterialSpecular;
void main(void) {
vec4 ambientProduct= uLightAmbient* uMaterialAmbient;
vec4 diffuseProduct= uLightDiffuse*uMaterialDiffuse;
vec4 specularProduct= uLightSpecular*uMaterialSpecular;
vec3 pos = (uMVMatrix*vec4(aVertexPosition, 1.0)).xyz;
// position de l'oeil/camera.
const vec3 eyePosition = vec3(0,0,-40);
//Transformed normal position
vNormal = normalize((uNMatrix* aVertexNormal).xyz) ;
//Transformed light position
vec4 light = uMVMatrix * vec4(uLightPosition,1.0);
vec3 lightPos = (uMVMatrix * light).xyz;
//Light position
vLightRay = normalize(pos - lightPos);
//Vector Eye
vEyeVec = -normalize(pos);
//Final vertex position
gl_Position = uMVMatrix*uPMatrix* vec4(aVertexPosition, 1.0);
}
</script>
<script id="shader-fs" type="x-shader/x-fragment">
#ifdef GL_ES
precision highp float;
#endif
varying vec3 vNormal;
varying vec3 vLightRay;
varying vec3 vEyeVec;
uniform vec4 ambientProduct;
uniform vec4 diffuseProduct;
uniform vec4 specularProduct;
uniform float uShininess;
void main(void)
{
vec4 diffuse = max(dot( vNormal,vLightRay), 0.0) * diffuseProduct;
vec3 H = normalize(vLightRay+vEyeVec);
vec4 specular =
pow(max(dot(vNormal, H), 0.0), uShininess) * specularProduct;
if (dot(vLightRay, vNormal) < 0.0)
specular = vec4(0.0, 0.0, 0.0, 1.0);
vec4 fColor = ambientProduct + diffuse + specular;
fColor.a = 1.0;
gl_FragColor =fColor;
}
</script>
<script id='code-js' type="text/javascript">
var gl = null; // WebGL context
var prg = null; // The program (shaders)
var c_width = 0; // Variable to store the width of the canvas
var c_height = 0; // Variable to store the height of the canvas
var mvMatrix = mat4.create(); // The Model-View matrix
var pMatrix = mat4.create(); // The projection matrix
var nMatrix = mat4.create(); // The normal matrix
var distance = -40;
var animateFlag = false;
var objects = [];
/**
* The program contains a series of instructions that tell the Graphic Processing Unit (GPU)
* what to do with every vertex and fragment that we pass it.
* The vertex shader and the fragment shader together are called the program.
*/
function initProgram() {
var fragmentShader = utils.getShader(gl, "shader-fs");
var vertexShader = utils.getShader(gl, "shader-vs");
prg = gl.createProgram();
gl.attachShader(prg, vertexShader);
gl.attachShader(prg, fragmentShader);
gl.linkProgram(prg);
if (!gl.getProgramParameter(prg, gl.LINK_STATUS)) {
alert("Could not initialise shaders");
}
gl.useProgram(prg);
prg.aVertexPosition = gl.getAttribLocation(prg, "aVertexPosition");
prg.aVertexNormal = gl.getAttribLocation(prg, "aVertexNormal");
prg.uPMatrix = gl.getUniformLocation(prg, "uPMatrix");
prg.uMVMatrix = gl.getUniformLocation(prg, "uMVMatrix");
prg.uNMatrix = gl.getUniformLocation(prg, "uNMatrix");
prg.uMaterialAmbient = gl.getUniformLocation(prg, "uMaterialAmbient");
prg.uMaterialDiffuse = gl.getUniformLocation(prg, "uMaterialDiffuse");
prg.uMaterialSpecular = gl.getUniformLocation(prg, "uMaterialSpecular");
prg.uShininess = gl.getUniformLocation(prg, "uShininess");
prg.uLightPosition = gl.getUniformLocation(prg, "uLightPosition");
prg.uLightAmbient = gl.getUniformLocation(prg, "uLightAmbient");
prg.uLightDiffuse = gl.getUniformLocation(prg, "uLightDiffuse");
prg.uLightSpecular = gl.getUniformLocation(prg, "uLightSpecular");
}
function initLights(){
//Light uniforms
gl.uniform3fv(prg.uLightPosition,[4.5,3.0,15.0]);
gl.uniform4f(prg.uLightAmbient ,1.0,1.0,1.0,1.0);
gl.uniform4f(prg.uLightDiffuse,1.0,1.0,1.0,1.0);
gl.uniform4f(prg.uLightSpecular,1.0,1.0,1.0,1.0);
//Object Uniforms
gl.uniform4f(prg.uMaterialAmbient, 0.1,0.1,0.1,1.0);
gl.uniform4f(prg.uMaterialDiffuse, 0.5,0.8,0.1,1.0);
gl.uniform4f(prg.uMaterialSpecular, 0.6,0.6,0.6,1.0);
gl.uniform1f(prg.uShininess, 200.0);
}
/**
* Creates an AJAX request to load the scene asynchronously
*/
function loadScene(){
loadObject('models/plane.json');
loadObject('models/cone.json','cone');
loadObject('models/sphere.json','sphere');
loadObject('models/smallsph.json','lightsource');
}
function getObject(alias){
for(var i=0; i<objects.length; i++){
if (alias == objects[i].alias) return objects[i];
}
return null;
}
/**
* Ajax and JSON in action
*/
function loadObject(filename,alias){
var request = new XMLHttpRequest();
console.info('Requesting ' + filename);
request.open("GET",filename);
request.onreadystatechange = function() {
if (request.readyState == 4) {
if(request.status == 404) {
console.info(filename + ' does not exist');
}
else {
var o = JSON.parse(request.responseText);
o.alias = (alias==null)?'none':alias;
handleLoadedObject(filename,o);
}
}
}
request.send();
}
/**
* Creates the buffers that contain the geometry of the object
*/
function handleLoadedObject(filename,object) {
console.info(filename + ' has been retrieved from the server');
var vertexBufferObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBufferObject);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(object.vertices), gl.STATIC_DRAW);
var normalBufferObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, normalBufferObject);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(calcNormals(object.vertices, object.indices)), gl.STATIC_DRAW);
var indexBufferObject = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBufferObject);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(object.indices), gl.STATIC_DRAW);
object.vbo = vertexBufferObject;
object.ibo = indexBufferObject;
object.nbo = normalBufferObject;
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
gl.bindBuffer(gl.ARRAY_BUFFER,null);
objects.push(object);
}
/**
* Main rendering function. Called every 500ms according to WebGLStart function (see below)
*/
function drawScene() {
gl.clearColor(0.3,0.3,0.3, 1.0);
gl.clearDepth(100.0);
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
gl.viewport(0, 0, c_width, c_height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.perspective(60, c_width / c_height, 0.1, 1000.0, pMatrix);
try{
gl.enableVertexAttribArray(prg.aVertexPosition);
gl.enableVertexAttribArray(prg.aVertexNormal);
for (var i = 0; i < objects.length; i++){
var object = objects[i];
mat4.identity(mvMatrix);
mat4.translate(mvMatrix, [0.0, 0.0, distance]); //Sets the camera to a reasonable distance to view the part
mat4.rotate(mvMatrix, 30*Math.PI/180, [1,0,0]);
mat4.rotate(mvMatrix, angle*Math.PI/180, [0,1,0]);
if (object.alias == 'lightsource'){
var lightPos = gl.getUniform(prg, prg.uLightPosition);
mat4.translate(mvMatrix,lightPos);
}
gl.uniformMatrix4fv(prg.uMVMatrix, false, mvMatrix);
gl.uniformMatrix4fv(prg.uPMatrix, false, pMatrix);
mat4.set(mvMatrix, nMatrix);
mat4.inverse(nMatrix);
mat4.transpose(nMatrix);
gl.uniformMatrix4fv(prg.uNMatrix, false, nMatrix);
gl.uniform4fv(prg.uMaterialAmbient, object.ambient);
gl.uniform4fv(prg.uMaterialDiffuse, object.diffuse);
gl.uniform4fv(prg.uMaterialSpecular, object.specular);
gl.bindBuffer(gl.ARRAY_BUFFER, object.vbo);
gl.vertexAttribPointer(prg.aVertexPosition, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(prg.aVertexPosition);
gl.bindBuffer(gl.ARRAY_BUFFER, object.nbo);
gl.vertexAttribPointer(prg.aVertexNormal, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(prg.aVertexNormal);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, object.ibo);
gl.drawElements(gl.TRIANGLES, object.indices.length, gl.UNSIGNED_SHORT,0);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
}
}
catch(err){
alert(err);
message(err.description);
}
}
var lastTime = 0;
var angle = 0;
/**
* Updates the angle of rotation by a little bit each time
*/
function animate() {
var timeNow = new Date().getTime();
if (lastTime != 0) {
var elapsed = timeNow - lastTime;
if (animateFlag) angle += (90 * elapsed) / 10000.0;
}
lastTime = timeNow;
}
/**
* Render Loop
*/
function renderLoop() {
requestAnimFrame(renderLoop);
drawScene();
animate();
}
/**
* Entry point. This function is invoked when the page is loaded
*/
function runWebGLApp() {
//Obtains a WebGL context
gl = utils.getGLContext("canvas-element-id");
//Initializes the program (shaders)
initProgram();
//Initializes lights
initLights();
//Load Scene
loadScene();
//Renders the scene!
renderLoop();
}
</script>
</head>
<body onLoad='runWebGLApp()'>
<div id='top'>
<div id='contents'>
<div id='canvasContainer'>
<canvas id='canvas-element-id' width='480' height='400'>
Your browser does not support the HTML5 canvas element.
</canvas>
</div>
</div>
<div id='bottom'>
<table style='padding=0px'>
<tr>
<td>X:</td><td id='slider-x-value' width='30px'>4.5</td><td width='150px'><div id='slider-x'/></td>
</tr>
<tr>
<td>Y:</td><td id='slider-y-value' width='30px'>3.0</td><td width='150px'><div id='slider-y'/></td>
</tr>
<tr>
<td>Z:</td> <td id='slider-z-value' width='30px'>15.0</td><td width='150px'><div id='slider-z'/></td>
</tr>
</table>
</div>
<script>cview.run(cview.MODE_VIEW);</script>
<script>
$('#slider-shininess').slider({value:200, min:1, max:300, step:1, slide:updateShininess});
$('#slider-x').slider({value:4.5, min:-50, max:50, step:0.1, slide:updateLightPosition, change:updateLightPosition});
$('#slider-y').slider({value:3.0, min:0, max:50, step:0.1, slide:updateLightPosition, change:updateLightPosition});
$('#slider-z').slider({value:15.0, min:-50, max:50, step:0.1, slide:updateLightPosition, change:updateLightPosition});
$('#animate-btn').button();
$('#animate-btn').click(
function(){
if ($('#animate-btn:checked').val()==null){
animateFlag = false;
}
else{
animateFlag = true;
}
});
function updateShininess(){
var v = $('#slider-shininess').slider("value");
gl.uniform1f(prg.uShininess, v);
$('#slider-shininess-value').html(v);
}
function updateLightPosition(){
var x = $('#slider-x').slider("value");
var y = $('#slider-y').slider("value");
var z = $('#slider-z').slider("value");
gl.uniform3fv(prg.uLightPosition, [x,y,z]);
$('#slider-x-value').html(x);
$('#slider-y-value').html(y);
$('#slider-z-value').html(z);
}
function updateDistance(){
var d = $('#slider-distance').slider("value");
$('#slider-distance-value').html(distance);
distance = -d;
}
function updateObjectColor(alias, r,g,b){
var object = getObject(alias);
if (object != null){
object.diffuse = [r,g,b,1.0];
}
}
$('#colorSelectorSphere').ColorPicker({
onSubmit: function(hsb, hex, rgb, el) {
$(el).val(hex);
$(el).ColorPickerHide();
},
color: '#00ff00',
onShow: function (colpkr) {
$(colpkr).fadeIn(500);
return false;
},
onHide: function (colpkr) {
$(colpkr).fadeOut(500);
return false;
},
onChange: function (hsb, hex, rgb) {
$('#colorSelectorSphere div').css('backgroundColor', '#' + hex);
updateObjectColor('sphere',rgb.r/256,rgb.g/256,rgb.b/256);
},
onBeforeShow: function (colpkr) {
$(this).ColorPickerSetColor('rgb(0.5,0.8,0.1)');
}
})
$('#colorSelectorCone').ColorPicker({
onSubmit: function(hsb, hex, rgb, el) {
$(el).val(hex);
$(el).ColorPickerHide();
},
color: '#00ff00',
onShow: function (colpkr) {
$(colpkr).fadeIn(500);
return false;
},
onHide: function (colpkr) {
$(colpkr).fadeOut(500);
return false;
},
onChange: function (hsb, hex, rgb) {
$('#colorSelectorCone div').css('backgroundColor', '#' + hex);
updateObjectColor('cone',rgb.r/256,rgb.g/256,rgb.b/256);
},
onBeforeShow: function (colpkr) {
$(this).ColorPickerSetColor('rgb(0.8,0.1,0.5)');
}
})
// Calcule les normales des vertex. La normale de chaque vertex est
// la moyenne des triangles voisins.
//
// vertices: la liste des vertex.
// ind: la liste des indices.
// retour: la liste des normales par vertex.
function calcNormals(vertices, ind){
var x=0;
var y=1;
var z=2;
var v1 = [], v2 = [], thisNormal = [];
// initialiser la liste des normales.
var ns = [];
for(var i=0;i<vertices.length;i++)
{
ns[i]=0.0;
}
for(var i=0;i<ind.length;i=i+3){
//v1 = p1 - p0
v1[x] = vertices[3*ind[i+1]+x] - vertices[3*ind[i]+x];
v1[y] = vertices[3*ind[i+1]+y] - vertices[3*ind[i]+y];
v1[z] = vertices[3*ind[i+1]+z] - vertices[3*ind[i]+z];
// v2 = p2 - p1
v2[x] = vertices[3*ind[i+2]+x] - vertices[3*ind[i]+x];
v2[y] = vertices[3*ind[i+2]+y] - vertices[3*ind[i]+y];
v2[z] = vertices[3*ind[i+2]+z] - vertices[3*ind[i]+z];
// N = v2 x v1 (cross product).
thisNormal[x] = v1[y]*v2[z] - v1[z]*v2[y];
thisNormal[y] = v1[z]*v2[x] - v1[x]*v2[z];
thisNormal[z] = v1[x]*v2[y] - v1[y]*v2[x];
for(j=0;j<3;j++)
{
// N += thisNormal. on additionne les normales.
ns[3*ind[i+j]+x] = ns[3*ind[i+j]+x] + thisNormal[x];
ns[3*ind[i+j]+y] = ns[3*ind[i+j]+y] + thisNormal[y];
ns[3*ind[i+j]+z] = ns[3*ind[i+j]+z] + thisNormal[z];
}
}
// Normalisation.
for(var i=0;i<vertices.length;i=i+3){
var nn=[];
var len = 0;
for(var j = 0; j < 3; j++)
{
nn[j] = ns[i+j];
len += nn[j] * nn[j];
}
// La norme de la normale.
len = Math.sqrt(len);
if (len == 0)
len = 0.00001;
for(var j = 0; j < 3; j++)
ns[i+j] = nn[j] / len;
console.log(len);
}
return ns;
}
</script>
</body>
</html>
老实说,要涵盖的问题太多了。试图让你的代码工作。首先,您确实需要学习如何制作最小的回购协议。您发布的代码没有运行,引用了几个不存在的脚本和不存在的数据。
代码所基于的教程似乎很旧。 2020 年没有人使用 XMLHttpRequest。没有 requestAnimFrame
的功能,它是 requestAnimationFrame
。我认为这是 2011 年的 polyfill 遗留下来的。它仍在使用 <body onload="">
,很少有人再使用了。它还使用 new Date().getTime()
,因为时间被传递到 requestAnimationFrame
,所以没有理由使用它。它正在调用一些函数来获取 webgl 上下文,但在 2020 年也没有理由这样做。它显然也在使用旧版本的 glMatrix,因为 the current version 使用不同的 API。在当前版本中,每个函数都采用一个矩阵来存储结果作为第一个参数。同样在当前版本中,perspective
以弧度表示视野。我不知道它过去是否以度为单位,但代码正在传递度数。
我将 XHR 代码更改为 return 一个立方体。 (“最小完整可验证示例”(mcve) 的最小和完整部分示例 - 我认为现在 S.O 称它们为“最小可复制示例”。我还删除了对 ColorPicker
的所有引用(制作最小回购的另一个例子)
代码应该在 the JavaScript console 中出现错误。你检查过 JavaScript 控制台了吗?特别是 uNMatrix
是一个 mat3 但代码调用 gl.uniformMatrix4fv
来设置它是一个错误。
使用 webgl-lint 指出几个制服没有被设置,包括“ambientProduct”、“diffuseProduct”、“specularProduct”,还有几个被设置的不存在(那部分不一定是错误)但是顶点着色器中有几个制服实际上没有使用,例如颜色似乎设置为
gl.uniform4fv(prg.uMaterialAmbient, object.ambient);
gl.uniform4fv(prg.uMaterialDiffuse, object.diffuse);
gl.uniform4fv(prg.uMaterialSpecular, object.specular);
但是着色器中没有使用这些制服(它们出现在着色器中,但如果您查看代码,您将看不到任何效果)
然后,当我最终消除所有错误时,剩下的问题是 gl_Position
的数学运算将 2 个矩阵倒置。它应该是 projection * modelView * position
但它有 modelView * projection * position
但是,此外,所有 3 个模型都绘制在相同的位置。也许这些模型中的几何图形处于不同的位置。我不知道,但通常你会根据循环索引或一些位置数组或每个对象数据,以某种形式给你绘制的每个东西它自己的位置。
无论如何,屏幕上出现了一些东西,但已经花了 45 分钟,我不想尝试修复照明。相反,我建议您阅读一些稍微更新的教程,例如 this one 及其链接到的教程。
var mat4 = glMatrix.mat4;
var gl = null; // WebGL context
var prg = null; // The program (shaders)
var c_width = 480; // Variable to store the width of the canvas
var c_height = 400; // Variable to store the height of the canvas
var mvMatrix = mat4.create(); // The Model-View matrix
var pMatrix = mat4.create(); // The projection matrix
var nMatrix = mat4.create(); // The normal matrix
var distance = -40;
var animateFlag = false;
var objects = [];
const utils = {
getShader(gl, id) {
const elem = document.getElementById(id);
const type = /vertex/.test(elem.type) ?
gl.VERTEX_SHADER :
gl.FRAGMENT_SHADER;
const sh = gl.createShader(type);
gl.shaderSource(sh, elem.text);
gl.compileShader(sh);
if (!gl.getShaderParameter(sh, gl.COMPILE_STATUS)) {
throw new Error(gl.getShaderInfoLog(sh));
}
return sh;
},
};
/**
* The program contains a series of instructions that tell the Graphic Processing Unit (GPU)
* what to do with every vertex and fragment that we pass it.
* The vertex shader and the fragment shader together are called the program.
*/
function initProgram() {
var fragmentShader = utils.getShader(gl, "shader-fs");
var vertexShader = utils.getShader(gl, "shader-vs");
prg = gl.createProgram();
gl.attachShader(prg, vertexShader);
gl.attachShader(prg, fragmentShader);
gl.linkProgram(prg);
if (!gl.getProgramParameter(prg, gl.LINK_STATUS)) {
alert("Could not initialise shaders");
}
gl.useProgram(prg);
prg.aVertexPosition = gl.getAttribLocation(prg, "aVertexPosition");
prg.aVertexNormal = gl.getAttribLocation(prg, "aVertexNormal");
prg.uPMatrix = gl.getUniformLocation(prg, "uPMatrix");
prg.uMVMatrix = gl.getUniformLocation(prg, "uMVMatrix");
prg.uNMatrix = gl.getUniformLocation(prg, "uNMatrix");
prg.uMaterialAmbient = gl.getUniformLocation(prg, "uMaterialAmbient");
prg.uMaterialDiffuse = gl.getUniformLocation(prg, "uMaterialDiffuse");
prg.uMaterialSpecular = gl.getUniformLocation(prg, "uMaterialSpecular");
prg.uShininess = gl.getUniformLocation(prg, "uShininess");
prg.uLightPosition = gl.getUniformLocation(prg, "uLightPosition");
prg.uLightAmbient = gl.getUniformLocation(prg, "uLightAmbient");
prg.uLightDiffuse = gl.getUniformLocation(prg, "uLightDiffuse");
prg.uLightSpecular = gl.getUniformLocation(prg, "uLightSpecular");
prg.ambientProduct = gl.getUniformLocation(prg, "ambientProduct");
prg.diffuseProduct = gl.getUniformLocation(prg, "diffuseProduct");
prg.specularProduct = gl.getUniformLocation(prg, "specularProduct");
}
function initLights() {
//Light uniforms
gl.uniform3fv(prg.uLightPosition, [4.5, 3.0, 15.0]);
gl.uniform4f(prg.uLightAmbient, 1.0, 1.0, 1.0, 1.0);
gl.uniform4f(prg.uLightDiffuse, 1.0, 1.0, 1.0, 1.0);
gl.uniform4f(prg.uLightSpecular, 1.0, 1.0, 1.0, 1.0);
//Object Uniforms
gl.uniform4f(prg.uMaterialAmbient, 0.1, 0.1, 0.1, 1.0);
gl.uniform4f(prg.uMaterialDiffuse, 0.5, 0.8, 0.1, 1.0);
gl.uniform4f(prg.uMaterialSpecular, 0.6, 0.6, 0.6, 1.0);
gl.uniform1f(prg.uShininess, 200.0);
}
/**
* Creates an AJAX request to load the scene asynchronously
*/
function loadScene() {
loadObject('models/plane.json');
loadObject('models/cone.json', 'cone');
loadObject('models/sphere.json', 'sphere');
loadObject('models/smallsph.json', 'lightsource');
}
function getObject(alias) {
for (var i = 0; i < objects.length; i++) {
if (alias == objects[i].alias) return objects[i];
}
return null;
}
/**
* Ajax and JSON in action
*/
const vertices = [
-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,
];
let modelNum = 0
function loadObject(filename, alias) {
setTimeout(() => {
const o = {
alias: (alias == null) ? 'none' : alias,
ambient: [0.1, 0.1, 0.1, 1],
diffuse: [Math.random(), Math.random(), Math.random(), 1],
specular: [1, 1, 1, 1],
// to make up for the fact the code does not have different positions
// for each model we'll move the vertices (bad)
vertices: vertices.map((v, i) => i % 3 === 0 ? v + modelNum * 3 : v),
indices: [
0, 1, 2, 2, 1, 3,
4, 5, 6, 6, 5, 7,
8, 9, 10, 10, 9, 11,
12, 13, 14, 14, 13, 15,
16, 17, 18, 18, 17, 19,
20, 21, 22, 22, 21, 23,
],
};
handleLoadedObject(filename, o);
++modelNum;
});
}
/**
* Creates the buffers that contain the geometry of the object
*/
function handleLoadedObject(filename, object) {
//console.info(filename + ' has been retrieved from the server');
var vertexBufferObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBufferObject);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(object.vertices), gl.STATIC_DRAW);
var normalBufferObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, normalBufferObject);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(calcNormals(object.vertices, object.indices)), gl.STATIC_DRAW);
var indexBufferObject = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBufferObject);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(object.indices), gl.STATIC_DRAW);
object.vbo = vertexBufferObject;
object.ibo = indexBufferObject;
object.nbo = normalBufferObject;
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
objects.push(object);
}
/**
* Main rendering function. Called every 500ms according to WebGLStart function (see below)
*/
function drawScene() {
gl.clearColor(0.3, 0.3, 0.3, 1.0);
//gl.clearDepth(100.0);
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
gl.viewport(0, 0, c_width, c_height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.perspective(pMatrix, 60 * Math.PI / 180, c_width / c_height, 0.1, 1000.0);
gl.enableVertexAttribArray(prg.aVertexPosition);
gl.enableVertexAttribArray(prg.aVertexNormal);
for (var i = 0; i < objects.length; i++) {
var object = objects[i];
mat4.identity(mvMatrix);
mat4.translate(mvMatrix, mvMatrix, [0.0, 0.0, distance]); //Sets the camera to a reasonable distance to view the part
mat4.rotate(mvMatrix, mvMatrix, 30 * Math.PI / 180, [1, 0, 0]);
mat4.rotate(mvMatrix, mvMatrix, angle * Math.PI / 180, [0, 1, 0]);
if (object.alias == 'lightsource') {
var lightPos = gl.getUniform(prg, prg.uLightPosition);
mat4.translate(mvMatrix, mvMatrix, lightPos);
}
gl.uniformMatrix4fv(prg.uMVMatrix, false, mvMatrix);
gl.uniformMatrix4fv(prg.uPMatrix, false, pMatrix);
mat4.set(mvMatrix, nMatrix);
mat4.invert(nMatrix, nMatrix);
mat4.transpose(nMatrix, nMatrix);
const t3 = glMatrix.mat3.create();
glMatrix.mat3.fromMat4(t3, nMatrix);
gl.uniformMatrix3fv(prg.uNMatrix, false, t3);
gl.uniform4fv(prg.ambientProduct, object.ambient);
gl.uniform4fv(prg.diffuseProduct, object.diffuse);
gl.uniform4fv(prg.specularProduct, object.specular);
gl.bindBuffer(gl.ARRAY_BUFFER, object.vbo);
gl.vertexAttribPointer(prg.aVertexPosition, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(prg.aVertexPosition);
gl.bindBuffer(gl.ARRAY_BUFFER, object.nbo);
gl.vertexAttribPointer(prg.aVertexNormal, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(prg.aVertexNormal);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, object.ibo);
gl.drawElements(gl.TRIANGLES, object.indices.length, gl.UNSIGNED_SHORT, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
}
}
var lastTime = 0;
var angle = 0;
/**
* Updates the angle of rotation by a little bit each time
*/
function animate() {
var timeNow = new Date().getTime();
if (lastTime != 0) {
var elapsed = timeNow - lastTime;
if (animateFlag) angle += (90 * elapsed) / 10000.0;
}
lastTime = timeNow;
}
/**
* Render Loop
*/
function renderLoop() {
drawScene();
animate();
requestAnimationFrame(renderLoop);
}
/**
* Entry point. This function is invoked when the page is loaded
*/
function runWebGLApp() {
//Obtains a WebGL context
gl = document.getElementById("canvas-element-id").getContext('webgl');
//Initializes the program (shaders)
initProgram();
//Initializes lights
initLights();
//Load Scene
loadScene();
//Renders the scene!
renderLoop();
}
$('#slider-shininess').slider({
value: 200,
min: 1,
max: 300,
step: 1,
slide: updateShininess
});
$('#slider-x').slider({
value: 4.5,
min: -50,
max: 50,
step: 0.1,
slide: updateLightPosition,
change: updateLightPosition
});
$('#slider-y').slider({
value: 3.0,
min: 0,
max: 50,
step: 0.1,
slide: updateLightPosition,
change: updateLightPosition
});
$('#slider-z').slider({
value: 15.0,
min: -50,
max: 50,
step: 0.1,
slide: updateLightPosition,
change: updateLightPosition
});
$('#animate-btn').button();
$('#animate-btn').click(
function() {
if ($('#animate-btn:checked').val() == null) {
animateFlag = false;
} else {
animateFlag = true;
}
});
function updateShininess() {
var v = $('#slider-shininess').slider("value");
gl.uniform1f(prg.uShininess, v);
$('#slider-shininess-value').html(v);
}
function updateLightPosition() {
var x = $('#slider-x').slider("value");
var y = $('#slider-y').slider("value");
var z = $('#slider-z').slider("value");
gl.uniform3fv(prg.uLightPosition, [x, y, z]);
$('#slider-x-value').html(x);
$('#slider-y-value').html(y);
$('#slider-z-value').html(z);
}
function updateDistance() {
var d = $('#slider-distance').slider("value");
$('#slider-distance-value').html(distance);
distance = -d;
}
function updateObjectColor(alias, r, g, b) {
var object = getObject(alias);
if (object != null) {
object.diffuse = [r, g, b, 1.0];
}
}
// Calcule les normales des vertex. La normale de chaque vertex est
// la moyenne des triangles voisins.
//
// vertices: la liste des vertex.
// ind: la liste des indices.
// retour: la liste des normales par vertex.
function calcNormals(vertices, ind) {
var x = 0;
var y = 1;
var z = 2;
var v1 = [],
v2 = [],
thisNormal = [];
// initialiser la liste des normales.
var ns = [];
for (var i = 0; i < vertices.length; i++) {
ns[i] = 0.0;
}
for (var i = 0; i < ind.length; i = i + 3) {
//v1 = p1 - p0
v1[x] = vertices[3 * ind[i + 1] + x] - vertices[3 * ind[i] + x];
v1[y] = vertices[3 * ind[i + 1] + y] - vertices[3 * ind[i] + y];
v1[z] = vertices[3 * ind[i + 1] + z] - vertices[3 * ind[i] + z];
// v2 = p2 - p1
v2[x] = vertices[3 * ind[i + 2] + x] - vertices[3 * ind[i] + x];
v2[y] = vertices[3 * ind[i + 2] + y] - vertices[3 * ind[i] + y];
v2[z] = vertices[3 * ind[i + 2] + z] - vertices[3 * ind[i] + z];
// N = v2 x v1 (cross product).
thisNormal[x] = v1[y] * v2[z] - v1[z] * v2[y];
thisNormal[y] = v1[z] * v2[x] - v1[x] * v2[z];
thisNormal[z] = v1[x] * v2[y] - v1[y] * v2[x];
for (j = 0; j < 3; j++) {
// N += thisNormal. on additionne les normales.
ns[3 * ind[i + j] + x] = ns[3 * ind[i + j] + x] + thisNormal[x];
ns[3 * ind[i + j] + y] = ns[3 * ind[i + j] + y] + thisNormal[y];
ns[3 * ind[i + j] + z] = ns[3 * ind[i + j] + z] + thisNormal[z];
}
}
// Normalisation.
for (var i = 0; i < vertices.length; i = i + 3) {
var nn = [];
var len = 0;
for (var j = 0; j < 3; j++) {
nn[j] = ns[i + j];
len += nn[j] * nn[j];
}
// La norme de la normale.
len = Math.sqrt(len);
if (len == 0)
len = 0.00001;
for (var j = 0; j < 3; j++)
ns[i + j] = nn[j] / len;
}
return ns;
}
runWebGLApp();
<link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet">
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec3 aVertexNormal;
// matrice model-view combinee.
uniform mat4 uMVMatrix;
// matrice de projection
uniform mat4 uPMatrix;
// matrice des normales.
uniform mat3 uNMatrix;
// position de la lumiere.
uniform vec3 uLightPosition;
// La normale transformee
varying vec3 vNormal;
// la direction vertex-lumiere
varying vec3 vLightRay;
// la direction camera-vertex
varying vec3 vEyeVec;
uniform vec4 uLightAmbient;
uniform vec4 uLightDiffuse;
uniform vec4 uLightSpecular;
uniform vec4 uMaterialAmbient;
uniform vec4 uMaterialDiffuse;
uniform vec4 uMaterialSpecular;
void main(void) {
vec4 ambientProduct= uLightAmbient* uMaterialAmbient;
vec4 diffuseProduct= uLightDiffuse*uMaterialDiffuse;
vec4 specularProduct= uLightSpecular*uMaterialSpecular;
vec3 pos = (uMVMatrix*vec4(aVertexPosition, 1.0)).xyz;
// position de l'oeil/camera.
const vec3 eyePosition = vec3(0,0,-40);
//Transformed normal position
vNormal = normalize((uNMatrix* aVertexNormal).xyz) ;
//Transformed light position
vec4 light = uMVMatrix * vec4(uLightPosition,1.0);
vec3 lightPos = (uMVMatrix * light).xyz;
//Light position
vLightRay = normalize(pos - lightPos);
//Vector Eye
vEyeVec = -normalize(pos);
//Final vertex position
gl_Position = uPMatrix*uMVMatrix* vec4(aVertexPosition, 1.0);
}
</script>
<script id="shader-fs" type="x-shader/x-fragment">
#ifdef GL_ES
precision highp float;
#endif
varying vec3 vNormal;
varying vec3 vLightRay;
varying vec3 vEyeVec;
uniform vec4 ambientProduct;
uniform vec4 diffuseProduct;
uniform vec4 specularProduct;
uniform float uShininess;
void main(void)
{
vec4 diffuse = max(dot( vNormal,vLightRay), 0.0) * diffuseProduct;
vec3 H = normalize(vLightRay+vEyeVec);
vec4 specular =
pow(max(dot(vNormal, H), 0.0), uShininess) * specularProduct;
if (dot(vLightRay, vNormal) < 0.0)
specular = vec4(0.0, 0.0, 0.0, 1.0);
vec4 fColor = ambientProduct + diffuse + specular;
fColor.a = 1.0;
gl_FragColor =fColor;
}
</script>
<div id='top'>
<div id='contents'>
<div id='canvasContainer'>
<canvas id='canvas-element-id' width='480' height='400'>
Your browser does not support the HTML5 canvas element.
</canvas>
</div>
</div>
<div id='bottom'>
<table style='padding=0px'>
<tr>
<td>X:</td><td id='slider-x-value' width='30px'>4.5</td><td width='150px'><div id='slider-x'/></td>
</tr>
<tr>
<td>Y:</td><td id='slider-y-value' width='30px'>3.0</td><td width='150px'><div id='slider-y'/></td>
</tr>
<tr>
<td>Z:</td> <td id='slider-z-value' width='30px'>15.0</td><td width='150px'><div id='slider-z'/></td>
</tr>
</table>
</div>
<script src="https://cdn.jsdelivr.net/npm/gl-matrix@3.3.0/gl-matrix-min.js"></script>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<script src="https://greggman.github.io/webgl-lint/webgl-lint.js"
data-gman-debug-helper='
{
"warnUndefinedUniforms": false
}
'
></script>