Javascript 在webgl中切换着色器
我对用webgl编写的程序有问题,我不知道如何调试它,因为浏览器控制台没有显示错误。Webgl什么也没画 我有以下一组着色器:Javascript 在webgl中切换着色器,javascript,webgl,shader,Javascript,Webgl,Shader,我对用webgl编写的程序有问题,我不知道如何调试它,因为浏览器控制台没有显示错误。Webgl什么也没画 我有以下一组着色器: <script id="shader-fs" type="x-shader/x-fragment"> precision mediump float; uniform sampler2D uSampler; varying vec2 vTextureCoord; varying vec3 vEye; varying vec3 vNormal; u
<script id="shader-fs" type="x-shader/x-fragment">
precision mediump float;
uniform sampler2D uSampler;
varying vec2 vTextureCoord;
varying vec3 vEye;
varying vec3 vNormal;
uniform vec3 uLightDirection; // Vector direccion de la luz
uniform vec3 uDirectionalColor; // Color de la luz direcional
uniform vec3 uColShadeless;
uniform vec3 uAmbientColor;
uniform float uKAmbiente;
uniform vec3 uColDifuso;
uniform float uKDifuso;
uniform vec3 uColEspecular;
uniform float uKEspecular;
uniform float uGlossiness;
void main(void)
{
vec3 normal = normalize(vNormal);
float mLambert = max(dot(normal, uLightDirection), 0.0);
vec3 vLuzLambert = uDirectionalColor * mLambert;
vec3 r = 2.0 * max(dot(normal, uLightDirection), 0.0) * normal - uLightDirection;
//vec3 r = reflect(uLightDirection, normal); // <- Da glossines del otro lado también
float specular = pow(max(dot(r, normalize(vEye)), 0.0), uGlossiness) ;
vec4 textureColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
vec3 componenteShadeless = uColShadeless * textureColor.rgb * uColDifuso; // luz autoiluminada * colores difusos
vec3 componenteAmbiente = uKAmbiente * uAmbientColor * textureColor.rgb * uColDifuso; // k% * luz ambiente * colores difusos
vec3 componenteDifusa = uKDifuso * textureColor.rgb * uColDifuso * vLuzLambert;
vec3 componenteEspecular = uKEspecular * specular * uColEspecular ;
gl_FragColor = vec4(componenteShadeless + componenteAmbiente + componenteDifusa + componenteEspecular, textureColor.a);
}
</script>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec3 aVertexNormal;
attribute vec2 aTextureCoord;
uniform mat4 uViewMatrix;
uniform mat4 uModelMatrix;
uniform mat4 uPMatrix;
uniform mat3 uNMatrix;
varying vec2 vTextureCoord;
varying vec3 vEye;
varying vec3 vNormal;
uniform vec2 aUVOffset;
void main(void)
{
// Transformamos al vértice al espacio de la cámara
vec4 pos_camera_view = uViewMatrix * uModelMatrix * vec4(aVertexPosition, 1.0);
// Transformamos al vértice al espacio de la proyección
gl_Position = uPMatrix * pos_camera_view;
// Coordenada de textura
vTextureCoord.x = aTextureCoord.x + aUVOffset.x;
vTextureCoord.y = aTextureCoord.y + aUVOffset.y;
// Para iluminación
vEye = -vec3(pos_camera_view.xyz);
vNormal = uNMatrix * aVertexNormal;
}
</script>
<script id="vs" type="x-shader/x-vertex">
attribute vec3 aPositionL;
attribute vec3 aNormalL;
attribute vec3 aTangentL;
attribute vec2 aTexCoord;
uniform mat4 uMatrixMVP;
uniform mat4 uMatrixMV;
varying vec4 vPositionV;
varying vec3 vNormalV;
varying vec3 vTangentV;
varying vec2 vTexCoord;
attribute vec3 aVertexPosition;
attribute vec3 aVertexNormal;
attribute vec2 aTextureCoord;
uniform mat4 uViewMatrix;
uniform mat4 uModelMatrix;
uniform mat4 uPMatrix;
uniform mat3 uNMatrix;
varying vec3 vNormal;
uniform vec2 aUVOffset;
void main(void)
{
// Transformamos al vértice al espacio de la cámara
vec4 pos_camera_view = uViewMatrix * uModelMatrix * vec4(aPositionL, 1.0);
// Transformamos al vértice al espacio de la proyección
gl_Position = uPMatrix * pos_camera_view;
vNormal = uNMatrix * aVertexNormal;
vPositionV = uMatrixMV * vec4(aPositionL, 1.0);
vNormalV = (uMatrixMV * vec4(aNormalL, 0.0)).xyz;
vTangentV = (uMatrixMV * vec4(aTangentL, 0.0)).xyz;
vTexCoord = aTexCoord;
}
</script>
<script id="fs" type="x-shader/x-fragment">
#ifdef GL_ES
precision highp float;
#endif
uniform sampler2D uColorSampler;
uniform sampler2D uNormalSampler;
uniform float uTime;
varying vec4 vPositionV;
varying vec3 vNormalV;
varying vec3 vTangentV;
varying vec2 vTexCoord;
void main(void) {
vec3 diffuse = texture2D(uColorSampler, vTexCoord).rgb;
vec3 normalT = texture2D(uNormalSampler, vTexCoord).xyz;
normalT.y = 1.0 - normalT.y;
normalT = 2.0 * normalT - vec3(1.0, 1.0, 1.0);
normalT.z *= 10.0;
vec3 binormalV = cross(vNormalV, vTangentV);
vec3 normalV = normalT.x * vTangentV + normalT.y * binormalV + normalT.z * vNormalV;
normalV = normalize(normalV);
vec3 lightV = normalize(vec3(10.0 * cos(uTime), 10.0, 10.0 * sin(uTime)));
float d = dot(normalV, lightV);
float s = dot(reflect(-lightV, normalV), normalize(-vPositionV.xyz));
s = pow(s, 30.0);
vec3 color = diffuse * (0.1 + 0.5 * d + 0.4 * s);
gl_FragColor = vec4(color, 1.0);
}
所以我首先调用函数“changeShaderBasic”,当我想用法线贴图绘制曲面时,我会这样做:
changeShaderNormal();
*Draw the surface*
changeShaderBasic();
如果我删除了代码的这一部分,它就会工作——因此着色器fs和着色器vs似乎工作正常。问题似乎在于其他着色器(vs和fs)或在着色器之间切换的函数
我省略了程序用来创建纹理的代码部分
我不知道我做错了什么,也不知道如何发现问题 问题在于未启用
shaderProgramMap
的某些着色器参数。例如,有
及
但是,shaderProgramMap
没有任何内容,该脚本还具有shaderProgramMap
属性
当您开始遇到此类问题时,您无法找到所编写代码的错误之处,这是因为代码不再清晰:概述丢失了。
有重复的代码:同样的事情要做两次,即编译、链接和配置着色器。然后,是重构的时候了:提取所有重复的代码,并参数化不同之处
有许多可能的步骤。一个是抽象着色器参数:属性
和制服
下面的代码将生成一个参数hashmap,其中包含有关着色器源中所有参数的信息。请注意,它可能不包括所有的可能性,但它只是给你一个想法
function initShaderParams( gl, shaderProgram, vs, fs )
{
/** We'll be returning this: */
var params = {
uniform:{},
attribute:{},
uniforms: function(arr) {
for ( var a in arr )
if ( params.uniform[a] )
params.uniform[ a ].set( arr[a] );
else throw new Error("unknown uniform '"+a+"' referenced in shader " + vs+"+"+fs
+ ";\navailable uniforms: " + Object.keys(params.uniform)
);
},
enable: function() {
for ( var a in this.attribute )
gl.disableVertexAttribArray( this.attribute[a] );
}
// disable: ....
};
/** returns a function to set the value of a uniform given it's type */
function getUniformFN( type ) {
switch ( type ) {
case 'vec2': return function(v){gl.uniform2f( this.loc, false, v[0], v[1] );};
case 'mat4': return function(v){gl.uniformMatrix4fv( this.loc, false, v );};
default:
throw new Error("unknown uniform type " + type + " in shader " + vs+"+"+fs );
}
}
/** same, for attributes. */
function getAttributeFN( type ) {
switch ( type ) {
case 'vec2': return function(v){ gl.bindBuffer( gl.ARRAY_BUFFER, v ); gl.vertexAttribPointer( this.loc, 2, gl.FLOAT, false, 0, 0 ); };
case 'vec3': return function(v){ gl.bindBuffer( gl.ARRAY_BUFFER, v ); gl.vertexAttribPointer( this.loc, 3, gl.FLOAT, false, 0, 0 ); };
case 'vec4': return function(v){ gl.bindBuffer( gl.ARRAY_BUFFER, v ); gl.vertexAttribPointer( this.loc, 4, gl.FLOAT, false, 0, 0 ); };
default:
throw new Error("unknown uniform type " + type + " in shader " + vs+"+"+fs );
}
}
/** Utility method to map a regex callback */
function regexMap(regex, text, callback) {
while ((result = regex.exec(text)) != null)
callback(result);
}
// extract parameters:
var src = vs + fs;
regexMap(/(uniform)\s+(\w+)\s+(\w+)(\[\d+\])?\s*;/g, src, function(groups) {
var loc = gl.getUniformLocation( shaderProgram, groups[3] );
if ( loc == null ) {
console.warn("declared ", groups[0], " not used" );
return;
}
params.uniform[ groups[3] ] = {
type: groups[2],
loc: loc,
set: getUniformFN( groups[2] )
};
} );
regexMap(/(attribute)\s+(\w+)\s+(\w+)\s*;/g, src, function(groups) {
var loc = gl.getAttribLocation ( shaderProgram, groups[3] );
if ( loc == -1 ) {
console.warn("declared ", groups[0], " not used" );
return;
}
params.attribute[ groups[3] ] = {
type: groups[2],
loc: loc,
set: getAttributeFN( groups[2] )
};
} );
return params;
}
调用此方法可以访问着色器参数,并且
迭代它们,或一次将它们全部设置为:
var params = initShaderParams( gl, shaderProgram, vsSource, fsSource );
params.uniforms( {
uViewMatrix: ...,
uModelMatrix: ...,
...
} );
这样,代码变得更加清晰,并且更容易发现缺少的内容。您甚至可以编写一个函数来为您执行此操作:params.uniforms
键和给定的参数,以查看它们是否都已指定,或者跟踪它们是否使用setter函数设置。
当然,还有很多其他的方法;您还可以创建着色器
类并重写方法
复制粘贴编码会导致无法维护的代码。根据经验,每当你必须编写两次程序时,你就太频繁了 你应该检查
-1
的getAttriblLocation
的返回值和getUniformLocation
的null
的返回值,以防找不到它们。我刚刚检查了它们,问题仍然存在。谢谢你的建议。我看到你禁用了VertexAttributeArray(ShaderProgramm.vertexPositionAttribute)
,但没有在shaderProgramMap.vertexPositionAttribute上启用它;您也没有初始化它。tex坐标和顶点法线也是一样。我以前从未尝试过(切换着色器),我不明白你的意思。shaderProgramMap没有该属性(vertexPositionAttribute)。两个着色器是否应具有相同的属性?
gl.disableVertexAttribArray(shaderProgram.vertexPositionAttribute);
function initShaderParams( gl, shaderProgram, vs, fs )
{
/** We'll be returning this: */
var params = {
uniform:{},
attribute:{},
uniforms: function(arr) {
for ( var a in arr )
if ( params.uniform[a] )
params.uniform[ a ].set( arr[a] );
else throw new Error("unknown uniform '"+a+"' referenced in shader " + vs+"+"+fs
+ ";\navailable uniforms: " + Object.keys(params.uniform)
);
},
enable: function() {
for ( var a in this.attribute )
gl.disableVertexAttribArray( this.attribute[a] );
}
// disable: ....
};
/** returns a function to set the value of a uniform given it's type */
function getUniformFN( type ) {
switch ( type ) {
case 'vec2': return function(v){gl.uniform2f( this.loc, false, v[0], v[1] );};
case 'mat4': return function(v){gl.uniformMatrix4fv( this.loc, false, v );};
default:
throw new Error("unknown uniform type " + type + " in shader " + vs+"+"+fs );
}
}
/** same, for attributes. */
function getAttributeFN( type ) {
switch ( type ) {
case 'vec2': return function(v){ gl.bindBuffer( gl.ARRAY_BUFFER, v ); gl.vertexAttribPointer( this.loc, 2, gl.FLOAT, false, 0, 0 ); };
case 'vec3': return function(v){ gl.bindBuffer( gl.ARRAY_BUFFER, v ); gl.vertexAttribPointer( this.loc, 3, gl.FLOAT, false, 0, 0 ); };
case 'vec4': return function(v){ gl.bindBuffer( gl.ARRAY_BUFFER, v ); gl.vertexAttribPointer( this.loc, 4, gl.FLOAT, false, 0, 0 ); };
default:
throw new Error("unknown uniform type " + type + " in shader " + vs+"+"+fs );
}
}
/** Utility method to map a regex callback */
function regexMap(regex, text, callback) {
while ((result = regex.exec(text)) != null)
callback(result);
}
// extract parameters:
var src = vs + fs;
regexMap(/(uniform)\s+(\w+)\s+(\w+)(\[\d+\])?\s*;/g, src, function(groups) {
var loc = gl.getUniformLocation( shaderProgram, groups[3] );
if ( loc == null ) {
console.warn("declared ", groups[0], " not used" );
return;
}
params.uniform[ groups[3] ] = {
type: groups[2],
loc: loc,
set: getUniformFN( groups[2] )
};
} );
regexMap(/(attribute)\s+(\w+)\s+(\w+)\s*;/g, src, function(groups) {
var loc = gl.getAttribLocation ( shaderProgram, groups[3] );
if ( loc == -1 ) {
console.warn("declared ", groups[0], " not used" );
return;
}
params.attribute[ groups[3] ] = {
type: groups[2],
loc: loc,
set: getAttributeFN( groups[2] )
};
} );
return params;
}
var params = initShaderParams( gl, shaderProgram, vsSource, fsSource );
params.uniforms( {
uViewMatrix: ...,
uModelMatrix: ...,
...
} );