THREE.WebGLShader "Error: To many uniforms" when creating a lot of Point Lights
THREE.WebGLShader "Error: To many uniforms" when creating a lot of Point Lights
背景
我正在尝试制作一圈光,正如您在下面的函数中看到的那样
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, so check it out here
上线
我的函数:
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;
}
其他的都在我的 repl.it 里,所以去看看吧!
答案在你的错误中。对于您正在使用的browser/platform,您的着色器中的制服太多了。
打开浏览器:https://webglreport.com/
在Vertex Shader
和Fragment Shader
下你会看到一个“Max _____ Uniform Vectors:
”。这是制服尺寸的硬性限制,根据您的 browser/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 检查器浏览器插件可以帮助您查看最终的着色器代码。)创建着色器的功能尽可能最少是一个很好的经验法则,然后在内存允许的情况下添加。
就个人而言,我在内存更稀缺的移动平台上看到最多。
背景
我正在尝试制作一圈光,正如您在下面的函数中看到的那样
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, so check it out here
上线我的函数:
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;
}
其他的都在我的 repl.it 里,所以去看看吧!
答案在你的错误中。对于您正在使用的browser/platform,您的着色器中的制服太多了。
打开浏览器:https://webglreport.com/
在Vertex Shader
和Fragment Shader
下你会看到一个“Max _____ Uniform Vectors:
”。这是制服尺寸的硬性限制,根据您的 browser/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 检查器浏览器插件可以帮助您查看最终的着色器代码。)创建着色器的功能尽可能最少是一个很好的经验法则,然后在内存允许的情况下添加。
就个人而言,我在内存更稀缺的移动平台上看到最多。