问题描述
我有一个问题,可能与此类似:WebGL shading/lighting too dark on some triangles
我正在尝试将我的旧练习之一从使用过时的glaux的C ++ OpenGL移植到WebGL。
问题在于圆锥体显示错误的照明,当有多个切片时闪烁微弱:
有一个以阿基米德螺线为底的圆锥,当有单个切片时可以使用:
左边是120个扇区,右边是12个扇区,在WebGL上是可以的。
当我使用多个切片(例如3个切片)时,问题就开始了:
该图像看起来有点脏,请参阅左侧图像。上部三角形(在右侧图像中突出显示)看起来显示的是错误的照明。
当我显示法线时,看起来计算正确。由于法线在两个三角形的拐角处重合:
我想使代码段更短,但是数学确实很长,也无法从GitHub添加脚本,因此我将它们内联。 verts
代表顶点,verts_norms
代表法线,nverts
代表突出显示的法线。数学很简单,两个对称的阿基米德螺旋线相互叠加:
螺旋描述为F(φ)= [φ* cos(φ),φ* sin(φ)]
计算出的法线∇F(φ)= [sin(φ)+φ* cos(φ),-cos(φ)+φ* sin(φ),φ]
更新1,着色器:
<canvas id = "cone1 heart geometry" width = "400" height = "400" class="yellow">
<script src="./webgl3/cone1_heart_geometry3.js"></script>
<script type="x-shader/x-vertex">
attribute vec4 coordinates;
attribute vec3 inputnormal;
uniform float isDrawnorms;
varying vec3 nm; //varying mediump
varying float isnormsColor; //in place of flag
void main()
{
gl_Position = coordinates;
nm = inputnormal;
isnormsColor = isDrawnorms;
}
</script>
<script type="x-shader/x-fragment">
precision mediump float;
varying vec3 nm; //varying mediump
varying float isnormsColor;
const vec4 greenColor = vec4( 0.0,1.0,0.0,1.0);
const vec3 lightDirection = -normalize(vec3(-1.0,-1.0,-1.0));
void main()
{
if (isnormsColor < 0.5) gl_FragColor = vec4(greenColor.rgb * dot(lightDirection,normalize(nm)),1.0);
if (isnormsColor > 0.5) gl_FragColor = vec4(0.5 * (nm + vec3(1.0)),1.0);
}
</script>
</canvas>
<html>
<head>
<title>webgl test</title>
<style>
canvas.cyan {border:2px solid cyan;}
canvas.magenta {border:2px solid magenta;}
canvas.blue {border:2px solid blue;}
canvas.red {border:2px solid red;}
canvas.yellow {border:2px solid yellow;}
canvas.green {border:1px solid green;}
div.sample { display: inline-block;white-space: Nowrap; border:1px solid magenta}
</style>
<script>
const RADGRAD = Math.PI / 180;
const C2PI = 2 * Math.PI;
function wrap(x)
{
if (isFinite(x)) return x;
if (x == Number.POSITIVE_INFINITY) return Number.MAX_VALUE;
if (x == Number.NEGATIVE_INFINITY) return Number.MIN_VALUE;
return 0.0;
}
function delta3v(p1,p2)
{
return {x:(p2.x - p1.x),y:(p2.y - p1.y),z:(p2.z - p1.z)};
}
function cross3v(p1,p2,p3)
{
let v1 = delta3v(p1,p2);
let v2 = delta3v(p1,p3);
return {x:(v1.y * v2.z - v1.z * v2.y),y:(v1.z * v2.x - v1.x * v2.z),z: (v1.x * v2.y - v1.y * v2.x)};
}
function mul3v(v,f)
{
return [v[0] * f[0],v[1] * f[1],v[2] * f[2]];
}
function dot3v(v,f)
{
return v[0] * f[0] + v[1] * f[1] + v[2] * f[2];
}
</script>
<script>
function buildGlProgram(canvasVar)
{
let canvas = null;
let gl = null;
if (typeof canvasVar == "string")
canvas = document.getElementById(canvasVar);
else if (typeof canvasVar == "object")
canvas = canvasVar;
//gl = canvas.getContext('webgl2');
//gl = canvas.getContext('experimental-webgl2');
gl = canvas.getContext('experimental-webgl');
gl.viewport(0,canvas.width,canvas.height);
let canvas_id = canvas.id;
let codes = getGLshadercodes (canvas);
let vertCode = codes.vertCode;
let vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader,vertCode);
gl.compileShader(vertShader);
let fragCode = codes.fragCode;
let fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader,fragCode);
gl.compileShader(fragShader);
let shaderProgram = gl.createProgram();
gl.attachShader (shaderProgram,vertShader);
gl.attachShader (shaderProgram,fragShader);
gl.linkProgram (shaderProgram);
gl.useProgram (shaderProgram);
return {canvas:canvas,gl:gl,shaderProgram:shaderProgram};
}
function getGLshadercodes (canvas)
{
let vertCode = "";
let fragCode = "";
let vertElement = null;
let fragElement = null;
let els = canvas.getElementsByTagName("script");
for (let i = 0; i < els.length; i++)
{
let el = els.item(i);
switch ( el.getAttribute("type") )
{
case "x-shader/x-vertex":
vertElement = el;
break;
case "x-shader/x-fragment":
fragElement = el;
break;
}
}
if(vertElement == null) vertElement = document.getElementById(canvas.getAttribute("id") + "_vertex_shader");
if(fragElement == null) fragElement = document.getElementById(canvas.getAttribute("id") + "_fragment_shader");
if(vertElement) vertCode = vertElement.innerText;
if(fragElement) fragCode = fragElement.innerText;
return {vertCode:vertCode,fragCode:fragCode};
}
</script>
</head>
<body>
<div class="sample">
<canvas id = "cone1 heart geometry" width = "400" height = "400" class="yellow">
<script>
{
let canvas = document.currentScript.parentElement;
function normalize3v(norm)
{
let len = Math.sqrt (norm[0] * norm[0] + norm[1] * norm[1] + norm[2] * norm[2]);
return [norm[0] / len,norm[1] / len,norm[2] / len];
}
function buildGeometry (sectors,revealInvisible)
{
let dfi = 2 * Math.PI / sectors;
let base = [],norms = [];
let sec2 = sectors / 2;
// Calculate from 0 to PI
for (let i = 0,fi = 0; i <= sec2; i++,fi += dfi)
{
//Calculate and normalize geometry: Resize all 0..PI to 0..1
base[i] = mul3v([ fi * Math.cos(fi),fi * Math.sin(fi),0.0],[1.0 / Math.PI,1.0 / Math.PI,1.0 ]);
norms[i] = mul3v([Math.sin(fi) + fi * Math.cos(fi),-(Math.cos(fi) - fi * Math.sin(fi)),fi],[1.0,1.0 / Math.PI]);
norms[i] = normalize3v(norms[i]);
}
if(revealInvisible) base[0] = [0.5,0];
return {base:base,norms:norms};
}
function buildSides (geometry,slices,sectors)
{
let sec2 = sectors / 2;
let dh = 1 / slices;
let sides = [[],[]];
for (let j = 0,s = 1,h = 1 - dh; j < slices; j++,s++,h -= dh)
{
sides[0][j] = [];
sides[1][j] = [];
for (let i = 0,i2 = sec2; i <= sec2; i++,i2--)
{
let bs = geometry.base[i];
let ns = geometry.norms[i];
sd = [s * bs[0] / slices,s * bs[1] / slices,h,ns[0],ns[1],ns[2]]; //[coords.xyz | norms.xyz]
sides[0][j][i] = [sd[0],sd[1],sd[2],sd[3],sd[4],sd[5]];
sides[1][j][i2] = [sd[0],-sd[1],-sd[4],sd[5]];
}
}
return sides;
}
function buildShape ()
{}
function buildCone(slices,sectors,revealInvisibles,snlen)
{
let nfi = 0;
if (sectors & 3) throw "Number of sectors must be a multiple of 4: " + sectors;
if (sectors < 8) throw "Must have no less than 8 sectors: " + sectors;
if (slices < 1) throw "Must have no less than 1 slices: " + slices;
let geo = buildGeometry (sectors,revealInvisibles);
let sides = buildSides(geo,sectors);
let sec2 = sectors / 2;
let verts = [];
let verts_norms = [];
let nverts = [];
let i0 = 0,i1 = 1,i2 = 2;
let n0 = 0,n1 = 1,n2 = 2;
const nv = snlen;
for (let side of sides)
for (let j = 0; j < slices; j++)
for (let i = 0; i < sec2; i++)
{
let s11,s12; // s11 \ // s11 <- s12
let s21,s22; // s21 -> s22 // \ s22
if (j == 0) //tip of the cone
{
s11 = [0,1,0]; //coord:xyz norm:000
s21 = side [j] [i]; s22 = side[j] [i+1];
}
else
{
s11 = side [j-1][i]; s12 = side[j-1][i+1];
s21 = side [j] [i]; s22 = side[j] [i+1];
}
//if (j == 0){
verts [i0] = s21[0];
verts [i1] = s21[1];
verts [i2] = s21[2];
verts_norms[i0] = s21[3];
verts_norms[i1] = s21[4];
verts_norms[i2] = s21[5];
nverts [n0] = s21[0];
nverts [n1] = s21[1];
nverts [n2] = -s21[2];
nverts [n0 + 3] = s21[0] + s21[3] / nv;
nverts [n1 + 3] = s21[1] + s21[4] / nv;
nverts [n2 + 3] = s21[2] - s21[5] / nv;
verts [i0 + 3] = s22[0];
verts [i1 + 3] = s22[1];
verts [i2 + 3] = s22[2];
verts_norms[i0 + 3] = s22[3];
verts_norms[i1 + 3] = s22[4];
verts_norms[i2 + 3] = s22[5];
nverts [n0 + 6] = s22[0];
nverts [n1 + 6] = s22[1];
nverts [n2 + 6] = -s22[2];
nverts [n0 + 9] = s22[0] + s22[3] / nv;
nverts [n1 + 9] = s22[1] + s22[4] / nv;
nverts [n2 + 9] = s22[2] - s22[5] / nv;
verts [i0 + 6] = s11[0];
verts [i1 + 6] = s11[1];
verts [i2 + 6] = s11[2];
verts_norms[i0 + 6] = s11[3];
verts_norms[i1 + 6] = s11[4];
verts_norms[i2 + 6] = s11[5];
nverts [n0 + 12] = s11[0];
nverts [n1 + 12] = s11[1];
nverts [n2 + 12] = -s11[2];
nverts [n0 + 15] = s11[0] + s11[3] / nv;
nverts [n1 + 15] = s11[1] + s11[4] / nv;
nverts [n2 + 15] = s11[2] - s11[5] / nv;
i0 += 9; i1 += 9; i2 += 9;
n0 += 18; n1 += 18; n2 += 18;
//}
// because this is the tip of the cone
if (j == 0) continue;
//if(0){
verts [i0] = s22[0];
verts [i1] = s22[1];
verts [i2] = s22[2];
verts_norms[i0] = s22[3];
verts_norms[i1] = s22[4];
verts_norms[i2] = s22[5];
nverts [n0] = s22[0];
nverts [n1] = s22[1];
nverts [n2] = -s22[2];
nverts [n0 + 3] = s22[0] + s22[3] / nv;
nverts [n1 + 3] = s22[1] + s22[4] / nv;
nverts [n2 + 3] = s22[2] - s22[5] / nv;
verts [i0 + 3] = s12[0];
verts [i1 + 3] = s12[1];
verts [i2 + 3] = s12[2];
verts_norms[i0 + 3] = s12[3];
verts_norms[i1 + 3] = s12[4];
verts_norms[i2 + 3] = s12[5];
nverts [n0 + 6] = s12[0];
nverts [n1 + 6] = s12[1];
nverts [n2 + 6] = -s12[2];
nverts [n0 + 9] = s12[0] + s12[3] / nv;
nverts [n1 + 9] = s12[1] + s12[4] / nv;
nverts [n2 + 9] = s12[2] - s12[5] / nv;
verts [i0 + 6] = s11[0];
verts [i1 + 6] = s11[1];
verts [i2 + 6] = s11[2];
verts_norms[i0 + 6] = s11[3];
verts_norms[i1 + 6] = s11[4];
verts_norms[i2 + 6] = s11[5];
nverts [n0 + 12] = s11[0];
nverts [n1 + 12] = s11[1];
nverts [n2 + 12] = -s11[2];
nverts [n0 + 15] = s11[0] + s11[3] / nv;
nverts [n1 + 15] = s11[1] + s11[4] / nv;
nverts [n2 + 15] = s11[2] - s11[5] / nv;
//}
i0 += 9; i1 += 9; i2 += 9;
n0 += 18; n1 += 18; n2 += 18;
}
return {verts:verts,norms:verts_norms,nverts:nverts};
}
let func = () =>
{
let prog = buildGlProgram(canvas);
let gl = prog.gl;
gl.clearColor(0.5,0.5,0.9);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
gl.clear (gl.COLOR_BUFFER_BIT);
////////////////////////////////////
const revealInvisibles = false;
let ns = 12,nh = 3,show_norms = true;
let obj;
try
{
obj = buildCone(nh,ns,8);
}
catch(err)
{
alert(err);
}
let verts = obj.verts;
let norms = obj.norms;
////////////////////////////////////
let vertex_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(verts),gl.STATIC_DRAW);
let shaderProgram = prog.shaderProgram;
let coord = gl.getAttribLocation (shaderProgram,"coordinates");
gl.vertexAttribPointer (coord,3,gl.FLOAT,false,0);
gl.enabLevertexAttribArray (coord);
let normalBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,normalBuffer);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(norms),gl.STATIC_DRAW);
let noord = gl.getAttribLocation (shaderProgram,"inputnormal");
gl.vertexAttribPointer (noord,0);
gl.enabLevertexAttribArray (noord);
let drawnorms = gl.getUniformlocation(prog.shaderProgram,'isDrawnorms');
gl.uniform1f(drawnorms,0.0);
gl.drawArrays(gl.TRIANGLES,ns * 3 + ns * 6 * (nh - 1));
if (show_norms)
{
gl.uniform1f(drawnorms,1.0);
let nverts = obj.nverts;
let nvert_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,nvert_buffer);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(nverts),gl.STATIC_DRAW);
//coord = gl.getAttribLocation (shaderProgram,"coordinates");
gl.vertexAttribPointer (coord,0);
gl.enabLevertexAttribArray (coord);
gl.drawArrays(gl.LInes,2* ( ns * 3 + ns * 6 * (nh - 1)));
//gl.drawArrays(gl.LINE_STRIP,ns * 3 + ns * 6 * (nh - 1));
}
}
document.addEventListener('DOMContentLoaded',func);
}</script>
<script type="x-shader/x-vertex">
attribute vec4 coordinates;
attribute vec3 inputnormal;
uniform float isDrawnorms;
varying vec3 nm; //varying mediump
varying float isnormsColor; //in place of flag
void main()
{
gl_Position = coordinates;
nm = inputnormal;
isnormsColor = isDrawnorms;
}
</script>
<script type="x-shader/x-fragment">
precision mediump float;
varying vec3 nm; //varying mediump
varying float isnormsColor;
const vec4 greenColor = vec4( 0.0,1.0);
const vec3 lightDirection = -normalize(vec3(-1.0,-1.0));
void main()
{
if (isnormsColor < 0.5) gl_FragColor = vec4(greenColor.rgb * dot(lightDirection,1.0);
if (isnormsColor > 0.5) gl_FragColor = vec4(0.5 * (nm + vec3(1.0)),1.0);
}
</script>
</canvas>
</div>
</body>
</html>
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)