I want to use the draw edges method from How to render geometry edges? - Questions - three.js forum (threejs.org) but I also need to support AmbientLight
, DirectionalLight
, PointLight
and SpotLight
. How can I mix these shaders?
Hi!
What result do you want to achieve? Any explanatory or reference pic?
This cube has the StandardMaterial
because it needs to be flat shaded, the cube is white and the scene have a directional light.
This is the same cube with ambient light instead of directional.
I’d like both have the edges visible.
For some ideas, have a look at this post: Detecting objects which can camera see - #10 by prisoner849
MeshBasicMaterial + .onBeforeCompile
The shader of here doesn’t work because of some of my cubes are scaled.
The problem of MeshBasicMaterial + .onBeforeCompile
is that I use both MeshBasicMaterial and MeshStandardMaterial in other places that I don’t want to show the edges.
Do you use instancing?
You can use a uniform, for example, a boolean one, for enable/disable box’s edges
Do you use instancing?
Yes.
You can use a uniform, for example, a boolean one, for enable/disable box’s edges
I guess this would solve, I gonna check it now.
I tried the following, but it didn’t work:
new MeshStandardMaterial({
color: new Color().getHex(),
flatShading: true,
defines: { MY_EDGES: true },
onBeforeCompile: (shader) => {
shader.vertexShader = `
attribute vec3 instData;
${shader.vertexShader}
`.replace(
`#include <begin_vertex>`,
`
#include <begin_vertex>
#ifdef MY_EDGES
float aStep = instData.z;
float halfStep = aStep * 0.5;
float angle = mod(atan(instData.y, instData.x) + PI2, PI2);
float radius = length(instData.xy);
float currAngle = angle - halfStep + (aStep * position.x);
transformed.x = cos(currAngle) * (radius - position.z) - instData.x;
transformed.z = sin(currAngle) * (radius - position.z) - instData.y;
#endif
`
);
shader.fragmentShader = `
float edgeFactor(vec2 p) {
vec2 grid = abs(fract(p - 0.5) - 0.5) / fwidth(p);
return min(grid.x, grid.y);
}
${shader.fragmentShader}
`.replace(
`vec4 diffuseColor = vec4( diffuse, opacity );`,
`
#ifdef MY_EDGES
vec3 c = mix(vec3(0), diffuse, clamp(edgeFactor(vUv), 0., 1.));
vec4 diffuseColor = vec4(c, opacity);
#else
vec4 diffuseColor = vec4(diffuse, opacity);
#endif
`
);
}
})
I meant a uniform, not a define.
I meant a uniform, not a define.
Oh, my mistake.
With uniforms it is having a strange behavior.
new MeshStandardMaterial({
color: 0xffffff,
flatShading: true,
onBeforeCompile: (shader) => {
shader.uniforms.edges = { value: true };
shader.vertexShader = `
uniform bool edges;
attribute vec3 instData;
${shader.vertexShader}
`.replace(
`#include <begin_vertex>`,
`
#include <begin_vertex>
if (edges) {
float aStep = instData.z;
float halfStep = aStep * 0.5;
float angle = mod(atan(instData.y, instData.x) + PI2, PI2);
float radius = length(instData.xy);
float currAngle = angle - halfStep + (aStep * position.x);
transformed.x = cos(currAngle) * (radius - position.z) - instData.x;
transformed.z = sin(currAngle) * (radius - position.z) - instData.y;
}
`
);
shader.fragmentShader = `
uniform bool edges;
float edgeFactor(vec2 p) {
vec2 grid = abs(fract(p - 0.5) - 0.5) / fwidth(p);
return min(grid.x, grid.y);
}
${shader.fragmentShader}
`.replace(
`vec4 diffuseColor = vec4( diffuse, opacity );`,
`
vec4 diffuseColor;
if (edges) {
vec3 c = mix(vec3(0), diffuse, clamp(edgeFactor(gl_PointCoord), 0., 1.));
diffuseColor = vec4(c, opacity);
} else {
diffuseColor = vec4(diffuse, opacity);
}
`
);
}
})
I also tried to replace gl_PointCoord
by vUv
and by vUV
, but both didn’t compile.
(I’m using a instanced mesh of box geometries)
Oh, wait, I thought you want to implement that approach for edges: How to render geometry edges? - #7 by prisoner849