如何解决Webgl中的阴影
我一直在尝试在webgl中创建阴影,如下图所示:在这里我们可以看到一个圆锥体,一个球体和一个灯光(我们可以使用滑块更改其位置)。
我试图通过从一些webgl辅导网站上看到多个阴影示例来在html文件中编写一些代码,但是现在,我什至看不到形状。可以肯定我做错了什么,但我只是不知道在哪里。这是我的代码,我还包含一个链接,因为它包含多个文件。预先感谢。
链接: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,-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,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);
gl.uniform4f(prg.uLightDiffuse,1.0);
gl.uniform4f(prg.uLightSpecular,1.0);
//Object Uniforms
gl.uniform4f(prg.uMaterialAmbient,0.1,1.0);
gl.uniform4f(prg.uMaterialDiffuse,0.5,0.8,1.0);
gl.uniform4f(prg.uMaterialSpecular,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,1.0);
gl.clearDepth(100.0);
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
gl.viewport(0,c_width,c_height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.perspective(60,c_width / c_height,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,distance]); //Sets the camera to a reasonable distance to view the part
mat4.rotate(mvMatrix,30*Math.PI/180,[1,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,pMatrix);
mat4.set(mvMatrix,nMatrix);
mat4.inverse(nMatrix);
mat4.transpose(nMatrix);
gl.uniformMatrix4fv(prg.uNMatrix,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,0);
gl.enableVertexAttribArray(prg.aVertexPosition);
gl.bindBuffer(gl.ARRAY_BUFFER,object.nbo);
gl.vertexAttribPointer(prg.aVertexNormal,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,change:updateLightPosition});
$('#slider-z').slider({value:15.0,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,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,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.1)');
}
})
$('#colorSelectorCone').ColorPicker({
onSubmit: function(hsb,rgb) {
$('#colorSelectorCone div').css('backgroundColor','#' + hex);
updateObjectColor('cone',onBeforeShow: function (colpkr) {
$(this).ColorPickerSetColor('rgb(0.8,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代码更改为仅返回一个多维数据集。 (“最小可验证示例”(mcve)的最小和完整部分的示例-我认为现在SO称它们为“最小可复制示例”。我还删除了对ColorPicker
的所有引用(另一个示例进行最小的回购)
该代码在the JavaScript console中应该出现错误。您是否检查过JavaScript控制台?特别是uNMatrix
是mat3,但是代码正在调用gl.uniformMatrix4fv
来设置它,这是一个错误。
使用webgl-lint指出没有设置几套制服,包括“ ambientProduct”,“ diffuseProduct”,“ specularProduct”,还有几套不存在的制服(那部分不一定是bug),但是有顶点着色器中有几套实际不使用的制服,例如颜色似乎设置为
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);
gl.uniform4f(prg.uLightDiffuse,1.0);
gl.uniform4f(prg.uLightSpecular,1.0);
//Object Uniforms
gl.uniform4f(prg.uMaterialAmbient,0.1,1.0);
gl.uniform4f(prg.uMaterialDiffuse,0.5,0.8,1.0);
gl.uniform4f(prg.uMaterialSpecular,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,];
let modelNum = 0
function loadObject(filename,alias) {
setTimeout(() => {
const o = {
alias: (alias == null) ? 'none' : alias,ambient: [0.1,1],diffuse: [Math.random(),Math.random(),specular: [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,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,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,1.0);
//gl.clearDepth(100.0);
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
gl.viewport(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,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,30 * Math.PI / 180,[1,0]);
mat4.rotate(mvMatrix,angle * Math.PI / 180,[0,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,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,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,gl.FLOAT,0);
gl.enableVertexAttribArray(prg.aVertexPosition);
gl.bindBuffer(gl.ARRAY_BUFFER,object.nbo);
gl.vertexAttribPointer(prg.aVertexNormal,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,change: updateLightPosition
});
$('#slider-z').slider({
value: 15.0,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,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,-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,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>
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。