三。WebGLShader 在创建大量点光源时"Error: To many uniforms"



背景

我正在尝试制作一个光环,正如你在下面的功能中看到的那样

function createLightRing(radius, options) {
let nopIsDefault = false;

...

但是当我运行它时,得到这个错误

THREE.WebGLProgram: shader error:  0 35715 false gl.getProgramInfoLog invalid shaders  THREE.WebGLShader: gl.getShaderInfoLog() fragment
ERROR: too many uniforms
1: #version 300 es
2: #define varying in
3: out highp vec4 pc_fragColor;
4: #define gl_FragColor pc_fragColor
5: #define gl_FragDepthEXT gl_FragDepth
6: #define texture2D texture
7: #define textureCube texture
...

我只是想做一个戒指:(

我尝试过的

  • 降低半径
  • 降低质量

一些代码

我的代码在repl.it上运行,所以请在这里查看

我的功能:

function createLightRing(radius, options) {
let nopIsDefault = false;
let lights = [];
const defaultOptions = {
start: 0,
end: 360,
copyLights: [],
color: 0xffffff, // White
lightType: "PointLight",
intensity: 1,
copyLightMap: "loop", // loops the arrays from colors and other values like it
rotation: new p5.Vector(0, 0, 0),
target: null,
quality: 6,
numberOfPoints: null,
override: false
}
// applys the default to options
options = {...defaultOptions, ...options}
const copyLightMap = options.copyLightMap.toString().toLowerCase();

// runs only if "numberOfPoints" exists
if (!options.numberOfPoints) {
options.numberOfPoints = (options.end - options.start) * options.quality
nopIsDefault = true;
}

// Mode 1 (soft / soft-(force / end) / 1, forces the loop to end when it finishes lopping thought "copyLights", but makes sure to finnish the loop. TL;DR: Sets "numberOfPoints" to "copyLights"'s length)
if (copyLightMap == '1' || copyLightMap == 'soft' || copyLightMap == 'soft-end' || copyLightMap == 'soft-force') {  
options.numberOfPoints = options.copyLights.length
nopIsDefault = true;
}
// updates "quality" to the right value
options.quality = nopIsDefault ? options.quality : options.numberOfPoints / (options.end - options.start)
for (let i = options.start; i <= options.end; i += 1 / options.quality) {

let light;
let dontCheck = false;
let realI = (1 / options.quality) * i;

const x = radius * cos(i);
const y = radius * sin(i);

// try to create a light with the spesified type
try {
light = new THREE[options.lightType]();
}
// if it fails, just use the defult
catch(err) {
light = new THREE[defaultOptions.lightType]();
}
light = setLightProprties(light, options);     // inits the light proprties
// only runs the switch if both "copyLights" has at lest one element and it can run in the first place
if (options.copyLights[0] && dontCheck) {
const copyLightMap = options.copyLightMap.toString().toLowerCase();
switch (copyLightMap) {

// Mode 0 (force / end / 0, forces the loop to end when done)
case 'force':
case 'end':
case '0':
if (realI < circleLoop) {
dontCheck = true;
break;
}
light = options.copyLights[realI];
break;

// Mode 2 (loop / 2, go back to beggining copyLights when there are no more values left in it)
case 'loop':
case '2':
light = options.copyLights[realI % options.copyLights.lenght];
break;
}

}
if (options.override) {
light = setLightProprties(light, options);   // updates light's proprties
}
light.position.set(x, y, 0);   // sets the light's position
lights.push(light);   // adds the new light to the array
}
return lights;
}

其他的都在我的回复中。所以去看看吧!

答案在您的错误中。着色器中的制服太多,不适用于正在使用的浏览器/平台。

打开浏览器以:https://webglreport.com/

在CCD_ 1和CCD_;Max _____ Uniform Vectors:";。这是制服尺寸的硬性限制,根据浏览器/GPU的不同,您会在这里看到不同的值。这些值由GL实现控制,并且可以通过GL常量访问。下面是一个可运行的片段,展示了如何获取这些值。

const canvas1 = document.createElement('canvas')
const gl1 = canvas1.getContext('webgl')
if (gl1) {
document.getElementById('wg1-mvuv').innerText = gl1.getParameter(gl1.MAX_VERTEX_UNIFORM_VECTORS)
document.getElementById('wg1-mfuv').innerText = gl1.getParameter(gl1.MAX_FRAGMENT_UNIFORM_VECTORS)
}
const canvas2 = document.createElement('canvas')
const gl2 = canvas2.getContext('webgl2')
if (gl2) {
document.getElementById('wg2-mvuv').innerText = gl2.getParameter(gl2.MAX_VERTEX_UNIFORM_VECTORS)
document.getElementById('wg2-mfuv').innerText = gl2.getParameter(gl2.MAX_FRAGMENT_UNIFORM_VECTORS)
}
html * {
font-family: monospace;
}
td {
border: 1px black solid;
}
<table>
<caption>WebGL</caption>
<tr>
<td>GL_MAX_VERTEX_UNIFORM_VECTORS</td>
<td id="wg1-mvuv">UNSUPPORTED</td>
</tr>
<tr>
<td>GL_MAX_FRAGMENT_UNIFORM_VECTORS</td>
<td id="wg1-mfuv">UNSUPPORTED</td>
</tr>
</table>
<table>
<caption>WebGL 2</caption>
<tr>
<td>GL_MAX_VERTEX_UNIFORM_VECTORS</td>
<td id="wg2-mvuv">UNSUPPORTED</td>
</tr>
<tr>
<td>GL_MAX_FRAGMENT_UNIFORM_VECTORS</td>
<td id="wg2-mfuv">UNSUPPORTED</td>
</tr>
</table>

您是否将任何大数组传递到一个统一,或者您的(最终)着色器代码是否有数百个统一?(有WebGL检查器浏览器插件可以帮助您查看最终的着色器代码。)创建尽可能低功能的着色器,然后在内存允许的情况下添加,这是一条很好的经验法则。

就我个人而言,我在内存更稀缺的移动平台上看到的最多。

最新更新