Я надеюсь, что кто-то может помочь мне с этим. Я нахожусь в конце своей веревки, пройдя все обсуждения и примеры, которые я нашел, и все еще не могу заставить работать 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.info(dt);
mesh.material.uniforms.time.value += dt;
mesh.material.uniforms.wavelength.value = wvl;
});
}
};
...
Вы сказали, что пробовали WebGL 2, это будет означать, что у вас есть поддержка WebGL 2, и в этом случае вы сможете просто удалить оператор #extension и просто использовать производные функции, установив версию шейдера с помощью оператора #version es 3.0.
@Nicol: всего несколько месяцев назад это работало нормально (это означает, что ошибка не появлялась). Я не знаю, что могло измениться (я использую Firefox, но также пробовал Chrome).
@LJ: Да, я пробовал. Он жалуется, что #version es 3.0 не является первой строкой в шейдере, хотя это так.
В WebGL2 с шейдерами версии 300 они поддерживаются по умолчанию, расширения не требуются.
<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
...
`;
Имеет #version 300 es во 2-й строке (ошибка)
С WebGL1 ваш код должен работать, но three.js автоматически выбирает WebGL2, если он существует. Чтобы протестировать WebGL1, мы могли бы заставить его использовать WebGL1, самостоятельно создав контекст WebGL,
const canvas = document.querySelector(selectorForCanvas);
const context = canvas.getContext('webgl');
const renderer = new THREE.WebGLRenderer({canvas, context});
Или мы можем использовать вспомогательный скрипт для эффективного отключения 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, и соответствующим образом настроить свои шейдеры.
Что касается того, почему ваш код работал и не работает сейчас, две идеи:
Спасибо. Похоже, что getContext возвращает ненулевое значение только для WebGL2. Я не знаю, как заставить webgl 1. Я не помню, чтобы менял версию three.js, но было обновление браузера и, возможно, было недавнее обновление аппаратного диска (насколько я помню). Могло ли это быть причиной? Мне пришлось внести одно дополнительное изменение, чтобы заставить его работать: ошибка, связанная с оператором #version, отсутствующим в первой строке, была связана с оператором определения lengthSegments: subdivisions.toFixed(1), в вызове RawShaderMaterial. Мне пришлось переместить это в сам код шейдера.
Я думаю, последний вопрос: что происходит, когда кто-то вызывает веб-сайт с шейдером, написанным для webgl 2, но машина этого человека поддерживает только webgl 1? Но я полагаю, это другая тема.
Это терпит неудачу. Как сказано внизу моего ответа, вы можете проверить флаг и настроить свои шейдеры. Вы можете получить некоторое представление о том, как three.js делает это для встроенных шейдеров здесь
@Marquizzo, это уже есть в ответе;)
Если расширение не поддерживается, вы не можете сделать так, чтобы оно поддерживалось.