我无法在使用 WebGL1 或 2 的着色器中使用导数 (dFdx)
I Can’t get derivatives (dFdx) working in my shader with WebGL1 or 2
我希望有人能帮我解决这个问题。我已经筋疲力尽了,已经完成了我发现的所有讨论和示例,但仍然无法让 dFdx 工作,无论是对于 WebGl1 还是 WebGL2。部分代码如下。
感谢您的帮助。
片段着色器使用:
#extension GL_OES_standard_derivatives : enable
precision highp float;
varying vec3 vNormal;
varying vec2 vUv;
varying vec3 vViewPosition;
uniform vec3 color;
uniform float animateRadius;
uniform float animateStrength;
vec3 faceNormal(vec3 pos) {
vec3 fdx = vec3(dFdx(pos.x), dFdx(pos.y), dFdx(pos.z));
vec3 fdy = vec3(dFdy(pos.x), dFdy(pos.y), dFdy(pos.z));
//vec3 fdx = dFdx(pos);
//vec3 fdy = dFdy(pos);
return normalize(cross(fdx, fdy));
}
控制台显示如下:
THREE.WebGLProgram: shader error: 0 35715 false gl.getProgramInfoLog Must have an compiled fragment shader attached. <empty string> THREE.WebGLShader: gl.getShaderInfoLog() fragment
WARNING: 0:2: 'GL_OES_standard_derivatives' : extension is not supported
ERROR: 0:14: 'GL_OES_standard_derivatives' : extension is not supported
ERROR: 0:14: 'GL_OES_standard_derivatives' : extension is not supported
ERROR: 0:14: 'GL_OES_standard_derivatives' : extension is not supported
ERROR: 0:15: 'GL_OES_standard_derivatives' : extension is not supported
ERROR: 0:15: 'GL_OES_standard_derivatives' : extension is not supported
ERROR: 0:15: 'GL_OES_standard_derivatives' : extension is not supported1: #define lengthSegments 300.0
2: #extension GL_OES_standard_derivatives : enable
3: precision highp float;
4:
5: varying vec3 vNormal;
6: varying vec2 vUv;
7: varying vec3 vViewPosition;
这里也是Javascript的一部分:
module.exports = function (app) {
const totalMeshes = isMobile ? 30 : 40;
const isSquare = false;
const subdivisions = isMobile ? 200 : 300;
const numSides = isSquare ? 4 : 8;
const openEnded = false;
const geometry = createTubeGeometry(numSides, subdivisions, openEnded);
// add to a parent container
const container = new THREE.Object3D();
const lines = [];
//lines.length = 0;
ShaderLoader("scripts/Grp3D/Phys4646A2/tube.vert", "scripts/Grp3D/Phys4646A2/tube.frag", function (vertex, fragment) {
const baseMaterial = new THREE.RawShaderMaterial({
vertexShader: vertex,
fragmentShader: fragment,
side: THREE.FrontSide,
extensions: {
derivatives: true
},
defines: {
lengthSegments: subdivisions.toFixed(1),
ROBUST: false,
ROBUST_NORMALS: false,
FLAT_SHADED: isSquare
},
uniforms: {
thickness: { type: 'f', value: 1 },
time: { type: 'f', value: 0 },
color: { type: 'c', value: new THREE.Color('#303030') },
animateRadius: { type: 'f', value: 0 },
animateStrength: { type: 'f', value: 0 },
index: { type: 'f', value: 0 },
totalMeshes: { type: 'f', value: totalMeshes },
radialSegments: { type: 'f', value: numSides },
wavelength: { type: 'f', value: 2.0 }
}
});
for( var i = 0; i < totalMeshes; i++){
var t = totalMeshes <= 1 ? 0 : i / (totalMeshes - 1);
var material = baseMaterial.clone();
material.uniforms = THREE.UniformsUtils.clone(material.uniforms);
material.uniforms.index.value = t;
material.uniforms.thickness.value = randomFloat(0.005, 0.0075);
material.uniforms.wavelength.value = 2.0;
var mesh = new THREE.Mesh(geometry, material);
mesh.frustumCulled = false;
lines.push(mesh);
container.add(mesh);
}
});
return {
object3d: container,
update,
setPalette
};
function update (dt,wvl) {
dt = dt / 1000;
lines.forEach(mesh => {
//console.log(dt);
mesh.material.uniforms.time.value += dt;
mesh.material.uniforms.wavelength.value = wvl;
});
}
};
...
在具有 300 版 es 着色器的 WebGL2 中,默认支持它们,无需扩展。
<canvas></canvas>
<script type="module">
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r122/build/three.module.js';
const canvas = document.querySelector('canvas');
const renderer = new THREE.WebGLRenderer({canvas});
const material = new THREE.RawShaderMaterial({
vertexShader: `#version 300 es
in vec4 position;
out vec4 vPosition;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
void main() {
gl_Position = projectionMatrix * modelViewMatrix * position;
vPosition = gl_Position;
}
`,
fragmentShader: `#version 300 es
precision mediump float;
in vec4 vPosition;
out vec4 outColor;
void main() {
outColor = vec4(normalize(vec3(dFdx(vPosition.x), dFdy(vPosition.y), 0)) * 0.5 + 0.5, 1);
}
`,
});
const geo = new THREE.BoxBufferGeometry();
const mesh = new THREE.Mesh(geo, material);
const scene = new THREE.Scene();
scene.add(mesh);
mesh.rotation.set(0.4, 0.4, 0);
const camera = new THREE.PerspectiveCamera(45, 2, 0.1, 10);
camera.position.z = 3;
renderer.render(scene, camera);
</script>
注:
const fs = `#version 300 es
...
`;
第一行有 #version 300 es
const fs = `
#version 300 es
...
`;
第 2 行有 #version 300 es
(错误)
对于 WebGL1,您的代码应该可以工作,但 three.js 如果 WebGL2 存在,则会自动选择它。为了测试 WebGL1,我们可以通过自己创建 WebGL 上下文来强制它使用 WebGL1,
const canvas = document.querySelector(selectorForCanvas);
const context = canvas.getContext('webgl');
const renderer = new THREE.WebGLRenderer({canvas, context});
或者,我们可以使用a helper script有效地禁用webgl2
<script src="https://greggman.github.io/webgl-helpers/webgl2-disable.js"></script>
<canvas></canvas>
<script type="module">
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r122/build/three.module.js';
const canvas = document.querySelector('canvas');
const renderer = new THREE.WebGLRenderer({canvas});
const material = new THREE.RawShaderMaterial({
vertexShader: `
attribute vec4 position;
varying vec4 vPosition;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
void main() {
gl_Position = projectionMatrix * modelViewMatrix * position;
vPosition = gl_Position;
}
`,
fragmentShader: `
#extension GL_OES_standard_derivatives : enable
precision mediump float;
varying vec4 vPosition;
void main() {
gl_FragColor = vec4(normalize(vec3(dFdx(vPosition.x), dFdy(vPosition.y), 0)) * 0.5 + 0.5, 1);
}
`,
});
const geo = new THREE.BoxBufferGeometry();
const mesh = new THREE.Mesh(geo, material);
const scene = new THREE.Scene();
scene.add(mesh);
mesh.rotation.set(0.4, 0.4, 0);
const camera = new THREE.PerspectiveCamera(45, 2, 0.1, 10);
camera.position.z = 3;
renderer.render(scene, camera);
</script>
否则您可以查看 renderer.capabilities.isWebGL2
以了解 three.js 是否选择 WebGL2 并适当调整着色器。
至于为什么你的代码以前能用,现在不能用,有两个想法:
- 你的机器以前不支持 WebGL2,现在支持了
- 您已将 three.js 升级到自动选择 WebGL2 的版本,而您使用的先前版本没有。
我希望有人能帮我解决这个问题。我已经筋疲力尽了,已经完成了我发现的所有讨论和示例,但仍然无法让 dFdx 工作,无论是对于 WebGl1 还是 WebGL2。部分代码如下。
感谢您的帮助。
片段着色器使用:
#extension GL_OES_standard_derivatives : enable
precision highp float;
varying vec3 vNormal;
varying vec2 vUv;
varying vec3 vViewPosition;
uniform vec3 color;
uniform float animateRadius;
uniform float animateStrength;
vec3 faceNormal(vec3 pos) {
vec3 fdx = vec3(dFdx(pos.x), dFdx(pos.y), dFdx(pos.z));
vec3 fdy = vec3(dFdy(pos.x), dFdy(pos.y), dFdy(pos.z));
//vec3 fdx = dFdx(pos);
//vec3 fdy = dFdy(pos);
return normalize(cross(fdx, fdy));
}
控制台显示如下:
THREE.WebGLProgram: shader error: 0 35715 false gl.getProgramInfoLog Must have an compiled fragment shader attached. <empty string> THREE.WebGLShader: gl.getShaderInfoLog() fragment
WARNING: 0:2: 'GL_OES_standard_derivatives' : extension is not supported
ERROR: 0:14: 'GL_OES_standard_derivatives' : extension is not supported
ERROR: 0:14: 'GL_OES_standard_derivatives' : extension is not supported
ERROR: 0:14: 'GL_OES_standard_derivatives' : extension is not supported
ERROR: 0:15: 'GL_OES_standard_derivatives' : extension is not supported
ERROR: 0:15: 'GL_OES_standard_derivatives' : extension is not supported
ERROR: 0:15: 'GL_OES_standard_derivatives' : extension is not supported1: #define lengthSegments 300.0
2: #extension GL_OES_standard_derivatives : enable
3: precision highp float;
4:
5: varying vec3 vNormal;
6: varying vec2 vUv;
7: varying vec3 vViewPosition;
这里也是Javascript的一部分:
module.exports = function (app) {
const totalMeshes = isMobile ? 30 : 40;
const isSquare = false;
const subdivisions = isMobile ? 200 : 300;
const numSides = isSquare ? 4 : 8;
const openEnded = false;
const geometry = createTubeGeometry(numSides, subdivisions, openEnded);
// add to a parent container
const container = new THREE.Object3D();
const lines = [];
//lines.length = 0;
ShaderLoader("scripts/Grp3D/Phys4646A2/tube.vert", "scripts/Grp3D/Phys4646A2/tube.frag", function (vertex, fragment) {
const baseMaterial = new THREE.RawShaderMaterial({
vertexShader: vertex,
fragmentShader: fragment,
side: THREE.FrontSide,
extensions: {
derivatives: true
},
defines: {
lengthSegments: subdivisions.toFixed(1),
ROBUST: false,
ROBUST_NORMALS: false,
FLAT_SHADED: isSquare
},
uniforms: {
thickness: { type: 'f', value: 1 },
time: { type: 'f', value: 0 },
color: { type: 'c', value: new THREE.Color('#303030') },
animateRadius: { type: 'f', value: 0 },
animateStrength: { type: 'f', value: 0 },
index: { type: 'f', value: 0 },
totalMeshes: { type: 'f', value: totalMeshes },
radialSegments: { type: 'f', value: numSides },
wavelength: { type: 'f', value: 2.0 }
}
});
for( var i = 0; i < totalMeshes; i++){
var t = totalMeshes <= 1 ? 0 : i / (totalMeshes - 1);
var material = baseMaterial.clone();
material.uniforms = THREE.UniformsUtils.clone(material.uniforms);
material.uniforms.index.value = t;
material.uniforms.thickness.value = randomFloat(0.005, 0.0075);
material.uniforms.wavelength.value = 2.0;
var mesh = new THREE.Mesh(geometry, material);
mesh.frustumCulled = false;
lines.push(mesh);
container.add(mesh);
}
});
return {
object3d: container,
update,
setPalette
};
function update (dt,wvl) {
dt = dt / 1000;
lines.forEach(mesh => {
//console.log(dt);
mesh.material.uniforms.time.value += dt;
mesh.material.uniforms.wavelength.value = wvl;
});
}
};
...
在具有 300 版 es 着色器的 WebGL2 中,默认支持它们,无需扩展。
<canvas></canvas>
<script type="module">
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r122/build/three.module.js';
const canvas = document.querySelector('canvas');
const renderer = new THREE.WebGLRenderer({canvas});
const material = new THREE.RawShaderMaterial({
vertexShader: `#version 300 es
in vec4 position;
out vec4 vPosition;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
void main() {
gl_Position = projectionMatrix * modelViewMatrix * position;
vPosition = gl_Position;
}
`,
fragmentShader: `#version 300 es
precision mediump float;
in vec4 vPosition;
out vec4 outColor;
void main() {
outColor = vec4(normalize(vec3(dFdx(vPosition.x), dFdy(vPosition.y), 0)) * 0.5 + 0.5, 1);
}
`,
});
const geo = new THREE.BoxBufferGeometry();
const mesh = new THREE.Mesh(geo, material);
const scene = new THREE.Scene();
scene.add(mesh);
mesh.rotation.set(0.4, 0.4, 0);
const camera = new THREE.PerspectiveCamera(45, 2, 0.1, 10);
camera.position.z = 3;
renderer.render(scene, camera);
</script>
注:
const fs = `#version 300 es
...
`;
第一行有 #version 300 es
const fs = `
#version 300 es
...
`;
第 2 行有 #version 300 es
(错误)
对于 WebGL1,您的代码应该可以工作,但 three.js 如果 WebGL2 存在,则会自动选择它。为了测试 WebGL1,我们可以通过自己创建 WebGL 上下文来强制它使用 WebGL1,
const canvas = document.querySelector(selectorForCanvas);
const context = canvas.getContext('webgl');
const renderer = new THREE.WebGLRenderer({canvas, context});
或者,我们可以使用a helper script有效地禁用webgl2
<script src="https://greggman.github.io/webgl-helpers/webgl2-disable.js"></script>
<canvas></canvas>
<script type="module">
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r122/build/three.module.js';
const canvas = document.querySelector('canvas');
const renderer = new THREE.WebGLRenderer({canvas});
const material = new THREE.RawShaderMaterial({
vertexShader: `
attribute vec4 position;
varying vec4 vPosition;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
void main() {
gl_Position = projectionMatrix * modelViewMatrix * position;
vPosition = gl_Position;
}
`,
fragmentShader: `
#extension GL_OES_standard_derivatives : enable
precision mediump float;
varying vec4 vPosition;
void main() {
gl_FragColor = vec4(normalize(vec3(dFdx(vPosition.x), dFdy(vPosition.y), 0)) * 0.5 + 0.5, 1);
}
`,
});
const geo = new THREE.BoxBufferGeometry();
const mesh = new THREE.Mesh(geo, material);
const scene = new THREE.Scene();
scene.add(mesh);
mesh.rotation.set(0.4, 0.4, 0);
const camera = new THREE.PerspectiveCamera(45, 2, 0.1, 10);
camera.position.z = 3;
renderer.render(scene, camera);
</script>
否则您可以查看 renderer.capabilities.isWebGL2
以了解 three.js 是否选择 WebGL2 并适当调整着色器。
至于为什么你的代码以前能用,现在不能用,有两个想法:
- 你的机器以前不支持 WebGL2,现在支持了
- 您已将 three.js 升级到自动选择 WebGL2 的版本,而您使用的先前版本没有。