Page 1 of 1
Help for wireframe in Android ES2/GL3
Posted: Sat Oct 11, 2025 5:29 pm
by Ats
Hello. I'm trying to write a shader to display the edges of a model, just like the basic Material Wireframe, but that should work on Android.
I'm getting to something, but the lines are in the middle of the faces, not on the edges. And I'm kind of lost
What is wrong with the way I'm doing this?
Code: Select all
<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" GLBase="1" FileVersion="2">
<OnLoaded>
<SpawnModel Model="Model_Box"/>
</OnLoaded>
<Content>
<Model Name="Model_Box">
<OnRender>
<UseMaterial Material="Material_Wire"/>
<RenderMesh Mesh="Mesh_Box"/>
</OnRender>
</Model>
<Mesh Name="Mesh_Box">
<Producers>
<MeshBox/>
<MeshExpression VertexColors="255">
<Expression>
<![CDATA[//V : current vertex
//N : current normal (turn off AutoNormals when modifying normals)
//C : current color (turn on VertexColors)
//TexCoord : current texture coordinate (turn on HasTexCoords)
C.R = V.X;
C.G = V.Y;
C.B = -V.X;]]>
</Expression>
</MeshExpression>
</Producers>
</Mesh>
<Material Name="Material_Wire" Shader="Shader_Wire"/>
<Shader Name="Shader_Wire">
<VertexShaderSource>
<![CDATA[
#ifdef GL_ES
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
#endif
attribute vec4 position;
attribute vec4 color;
uniform mat4 modelViewProjectionMatrix;
varying vec4 v_color;
varying vec3 v_pos;
void main()
{
v_color = color;
v_pos = position.xyz;
gl_Position = modelViewProjectionMatrix * position;
}
]]>
</VertexShaderSource>
<FragmentShaderSource>
<![CDATA[
#ifdef GL_ES
precision mediump float;
//#extension GL_OES_standard_derivatives : enable
#endif
varying vec4 v_color;
varying vec3 v_pos;
float edgeFactor(vec3 p)
{
vec3 d = fwidth(p);
vec3 a3 = smoothstep(vec3(0.0), d * 10.0, p);
return min(min(a3.x, a3.y), a3.z);
}
void main()
{
float edge = edgeFactor(abs(normalize(v_pos)));
vec3 fillColor = vec3(0.0);
vec3 lineColor = v_color.rgb;
float mixVal = smoothstep(0.0, 0.1, edge); // edge softness
vec3 finalColor = mix(lineColor, fillColor, mixVal);
gl_FragColor = vec4(finalColor, 1.0);
}]]>
</FragmentShaderSource>
</Shader>
</Content>
</ZApplication>
Re: Help for edge shader (wireframe)
Posted: Sat Oct 11, 2025 8:08 pm
by Kjell
Hi Ats,
Looks like you're trying to use barycentric coordinates to determine the pixel distance to edge? In that case .. you're accidentally using the vertex position as edge factor input, while you should be using your barycentric coordinates / vertex colors.
Below is a simple example ( for regular OpenGL ):
Code: Select all
<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" ClearColor="0.7529 0.7529 0.7529 1" FileVersion="2">
<OnLoaded>
<SpawnModel Model="Box"/>
</OnLoaded>
<Content>
<Model Name="Box" RotationVelocity="0.02 0.03 0">
<OnRender>
<UseMaterial Material="BoxMaterial"/>
<RenderMesh Mesh="BoxMesh"/>
</OnRender>
</Model>
<Variable Name="BoxIndex" Type="1"/>
<Material Name="BoxMaterial" Light="0" Shader="BoxShader"/>
<Mesh Name="BoxMesh">
<Producers>
<MeshBox/>
<ZExpression Expression="BoxIndex = 0;"/>
<MeshExpression AutoNormals="0" VertexColors="255">
<Expression>
<![CDATA[switch(BoxIndex++ & 3)
{
case 0:
case 3: C = vector4(1, 0, 0, 1); break;
case 1: C = vector4(0, 1, 0, 1); break;
case 2: C = vector4(0, 0, 1, 1); break;
}]]>
</Expression>
</MeshExpression>
</Producers>
</Mesh>
<Shader Name="BoxShader">
<VertexShaderSource>
<![CDATA[void main()
{
gl_FrontColor = gl_Color;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}]]>
</VertexShaderSource>
<FragmentShaderSource>
<![CDATA[void main()
{
vec3 d = step(fwidth(gl_Color.rgb), gl_Color.rgb);
gl_FragColor = gl_Color * min(min(d.x, d.y), d.z);
}]]>
</FragmentShaderSource>
</Shader>
</Content>
</ZApplication>
Personally i'm not a huge fan of this approach as it "draws" a line on the inside of a triangle .. resulting in a wireframe that appears thicker on edges that lie in between visible triangles compared to edges that don't.
K
Re: Help for edge shader (wireframe)
Posted: Mon Oct 13, 2025 10:05 am
by Ats
Oh, thanks. Coloring each triangle with 3 colors was that I was trying to do, but I didn't know I could put a ZExpression inside a Mesh Producers. So I was kind of stuck, wondering if I had to edit the mesh inside blender or something... Your example is really helpful.
I don't seem to find a simple way to draw wireframes in ES2/GL3. I've read about duplicating the 3DS models by suppressing the faces, while keeping the edges. Or using an OpenGL functions to manually draw GL_LINES in between vertices if there is a significative angle for each edge shared by two triangles, but I don't think ES2 has GL_LINES.
Edit:
After reading a bit more, I could simply use geometry shader... Now I'm getting to something
Code: Select all
<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="Smart wireframe demo" GLBase="1" ClearColor="0.8 0.8 0.8 1" FileVersion="2">
<OnLoaded>
<SpawnModel Model="Model_Box"/>
</OnLoaded>
<Content>
<Model Name="Model_Box" RotationVelocity="0.3 0.4 0">
<OnRender>
<UseMaterial Material="Mat_Wire"/>
<RenderMesh Mesh="Mesh_Box"/>
</OnRender>
</Model>
<Mesh Name="Mesh_Box">
<Producers>
<MeshBox/>
</Producers>
</Mesh>
<Material Name="Mat_Wire" Shader="Shader_Wire"/>
<Shader Name="Shader_Wire">
<VertexShaderSource>
<![CDATA[#ifdef GL_ES
precision mediump float;
#endif
attribute vec4 position;
attribute vec3 normal;
attribute vec4 color;
uniform mat4 modelViewProjectionMatrix;
uniform mat3 normalMatrix;
varying vec4 v_color;
void main() {
v_color = color; // pass color to fragment
gl_Position = modelViewProjectionMatrix * position;
}]]>
</VertexShaderSource>
<GeometryShaderSource>
<![CDATA[#version 330 core
layout(triangles) in;
layout(line_strip, max_vertices = 6) out;
varying vec4 v_color[];
void main() {
// For each triangle, emit 3 edges
for(int i = 0; i < 3; i++) {
gl_Position = gl_in[i].gl_Position;
EmitVertex();
gl_Position = gl_in[(i+1)%3].gl_Position;
EmitVertex();
EndPrimitive();
}
}]]>
</GeometryShaderSource>
<FragmentShaderSource>
<![CDATA[#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_color;
void main() {
gl_FragColor = v_color; // render edge color
}]]>
</FragmentShaderSource>
</Shader>
</Content>
</ZApplication>
Re: Help for edge shader (wireframe)
Posted: Mon Oct 13, 2025 10:20 am
by Kjell
Hi Ats,
Ats wrote: ↑Mon Oct 13, 2025 10:05 amColoring each triangle with 3 colors was that I was trying to do, but I didn't know I could put a ZExpression inside a Mesh Producers.
It feels like a bit of a hack. Would have been more convenient if there was a way to access mesh data ( vertices & faces ) directly, or if MeshExpression had a VertexIndex property.
Ats wrote: ↑Mon Oct 13, 2025 10:05 amOr using an OpenGL functions to manually draw GL_LINES in between vertices if there is a significative angle for each edge shared by two triangles, but I don't think ES2 has GL_LINES.
All versions of OpenGL ES support GL_LINES, GL_LINE_LOOP and GL_LINE_STRIP.
Ats wrote: ↑Mon Oct 13, 2025 10:05 amAfter reading a bit more, I could simply use geometry shader...
Do keep in mind that Geometry Shaders only work in OpenGL ES 3.2 .. and that they will always be significantly slower compared to using a static mesh.
K
Re: Help for edge shader (wireframe) in ES2/GL3
Posted: Mon Oct 13, 2025 11:20 am
by Ats
All versions of OpenGL ES support GL_LINES, GL_LINE_LOOP and GL_LINE_STRIP.
Oh, ok. Reddit is so full of crap
Anyway, I have something that is working a bit like I want. I'm going to try it on Android, to see if it is showing up. And I'll make it better, faster and stronger another day.
Code: Select all
<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="Smart wireframe demo" GLBase="1" ClearColor="0.8 0.8 0.8 1" FileVersion="2">
<OnLoaded>
<SpawnModel Model="Model_Box"/>
</OnLoaded>
<Content>
<Model Name="Model_Box" RotationVelocity="0.3 0.4 0">
<OnRender>
<UseMaterial Material="Mat_Wireframe"/>
<RenderMesh Mesh="Mesh_Box"/>
</OnRender>
</Model>
<Mesh Name="Mesh_Box">
<Producers>
<MeshBox/>
<MeshExpression AutoNormals="0" VertexColors="255">
<Expression>
<![CDATA[// Set all vertices to solid green
C.R = V.X;
C.G = -V.X;
C.B = V.Y;
C.A = 1.0;]]>
</Expression>
</MeshExpression>
</Producers>
</Mesh>
<Material Name="Mat_Wireframe" Shader="Shader_Wireframe"/>
<Shader Name="Shader_Wireframe">
<VertexShaderSource>
<![CDATA[#ifdef GL_ES
precision mediump float;
#endif
attribute vec4 position;
attribute vec3 normal;
attribute vec4 color;
uniform mat4 modelViewProjectionMatrix;
uniform mat3 normalMatrix;
varying vec4 v_color;
void main() {
v_color = color;
gl_Position = modelViewProjectionMatrix * position;
}]]>
</VertexShaderSource>
<GeometryShaderSource>
<![CDATA[#version 150 core
layout(triangles) in;
layout(line_strip, max_vertices = 6) out;
in vec4 v_color[];
out vec4 f_color;
void main() {
vec4 wireColor = v_color[0];
for(int i = 0; i < 3; i++) {
f_color = wireColor;
gl_Position = gl_in[i].gl_Position;
EmitVertex();
f_color = wireColor;
gl_Position = gl_in[(i+1)%3].gl_Position;
EmitVertex();
EndPrimitive();
}
}]]>
</GeometryShaderSource>
<FragmentShaderSource>
<![CDATA[#ifdef GL_ES
precision mediump float;
#endif
in vec4 f_color;
out vec4 fragColor;
void main() {
fragColor = f_color;
}]]>
</FragmentShaderSource>
</Shader>
</Content>
</ZApplication>
Edit:
And... It's super broken on Android
