python-opengl
python-opengl copied to clipboard
code error in chapter 9 linestrip
It seems to draw nothing if points at [[10., 4.], [20., 4.], [15., 4.]]
The code is in below.
uniform vec2 resolution;
uniform float antialias, thickness, linelength;
attribute vec4 prev, curr, next;
varying vec2 v_uv;
void main() {
float w = thickness/2.0 + antialias;
vec2 p;
vec2 t0 = normalize(curr.xy - prev.xy);
vec2 t1 = normalize(next.xy - curr.xy);
vec2 n0 = vec2(-t0.y, t0.x);
vec2 n1 = vec2(-t1.y, t1.x);
// Cap at start
if (prev.xy == curr.xy) {
v_uv = vec2(-w, curr.z*w);
p = curr.xy - w*t1 + curr.z*w*n1;
// Cap at end
} else if (curr.xy == next.xy) {
v_uv = vec2(linelength+w, curr.z*w);
p = curr.xy + w*t0 + curr.z*w*n0;
// Body
} else {
vec2 miter = normalize(n0 + n1);
float dy = w / dot(miter, n1);
v_uv = vec2(curr.w, curr.z*w);
p = curr.xy + dy*curr.z*miter;
}
gl_Position = vec4(2.0*p/resolution-1.0, 0.0, 1.0);
}
I guess it happened when points previous, current, next are collinear and the next point's x or y less than current point.
Another case: The drawing of points [[453, 138], [647, 137], [453, 139]] is weird. And points [[453, 138], [647, 137], [453, 138]] draw nothing.
If you change the three 4. into 4.1 4.2 and 4.3 it works?
I figure out what happened. In the fragment shader, we are using v_uv.x to decide which points are cap.
It would be wrong if the end of point is 'before' it's previous point or 'before' the first point. But I still no idea how to fix it.
where is this test exactly?
The whole code is bellow:
import sys
import ctypes
import numpy as np
from glumpy import app, gloo, gl
vertex = """
uniform vec2 resolution;
uniform float antialias;
uniform float thickness;
uniform float linelength;
attribute vec4 prev, curr, next;
varying vec2 v_uv;
void main() {
float w = thickness/2.0 + antialias;
vec2 p;
if (prev.xy == curr.xy) {
vec2 t1 = normalize(next.xy - curr.xy);
vec2 n1 = vec2(-t1.y, t1.x);
v_uv = vec2(-w, curr.z*w);
p = curr.xy - w*t1 + curr.z*w*n1;
} else if (curr.xy == next.xy) {
vec2 t0 = normalize(curr.xy - prev.xy);
vec2 n0 = vec2(-t0.y, t0.x);
v_uv = vec2(linelength+w, curr.z*w);
p = curr.xy + w*t0 + curr.z*w*n0;
} else {
vec2 t0 = normalize(curr.xy - prev.xy);
vec2 t1 = normalize(next.xy - curr.xy);
vec2 n0 = vec2(-t0.y, t0.x);
vec2 n1 = vec2(-t1.y, t1.x);
vec2 miter = normalize(n0 + n1);
float dy = w / dot(miter, n1);
v_uv = vec2(curr.w, curr.z*w);
p = curr.xy + dy*curr.z*miter;
}
gl_Position = vec4(2.0*p/resolution-1.0, 0.0, 1.0);
} """
fragment = """
uniform float antialias;
uniform float thickness;
uniform float linelength;
varying vec2 v_uv;
void main() {
float d = 0;
float w = thickness/2.0 - antialias;
// Cap at start
if (v_uv.x < 0)
d = length(v_uv) - w;
// Cap at end
else if (v_uv.x >= linelength)
d = length(v_uv - vec2(linelength,0)) - w;
// Body
else
d = abs(v_uv.y) - w;
if( d < 0) {
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
} else {
d /= antialias;
gl_FragColor = vec4(0.0, 0.0, 0.0, exp(-d*d));
}
} """
window = app.Window(2*512, 512, color=(1,1,1,1))
@window.event
def on_resize(width, height):
#spiral["resolution"] = width, height
shape["resolution"] = width, height
@window.event
def on_draw(dt):
window.clear()
shape.draw(gl.GL_TRIANGLE_STRIP)
def bake(P, closed=False):
epsilon = 1e-10
n = len(P)
if closed and ((P[0]-P[-1])**2).sum() > epsilon:
P = np.append(P, P[0])
P = P.reshape(n+1,2)
n = n+1
#print("n=", n)
V = np.zeros(((1+n+1),2,4), dtype=np.float32)
V_prev, V_curr, V_next = V[:-2], V[1:-1], V[2:]
V_curr[...,0] = P[:,np.newaxis,0]
V_curr[...,1] = P[:,np.newaxis,1]
V_curr[...,2] = 1,-1
L = np.cumsum(np.sqrt(((P[1:]-P[:-1])**2).sum(axis=-1))).reshape(n-1,1)
V_curr[1:,:,3] = L
if closed:
V[0], V[-1] = V[-3], V[2]
else:
V[0], V[-1] = V[1], V[-2]
print(V_curr)
return V_prev, V_curr, V_next, L[-1]
P = np.array([[4, 1], [4, 12], [4, 24]]).astype(np.float32)
V_prev, V_curr, V_next, length = bake(P, False)
shape = gloo.Program(vertex, fragment)
shape["prev"], shape["curr"], shape["next"] = V_prev, V_curr, V_next
shape["thickness"] = 1.0
shape["antialias"] = 1.5
shape["linelength"] = length
app.run()
It works fine when the P is [[4, 1], [4, 12], [4, 24]], but shows nothing when P is [[4, 1], [4, 12], [4, 6]]
v_uv.x is supposed to be the curvilinear coordinate along the line. For the actual line, it goes from 0 to linelength. Negativr means starting cap end > linemenght means ending cap. If the calculation of this curvilnear coordnate is wrong, then it might be problelatic. If all the point are aligned, there might be a division by 0 somewhere but the shader will not raise any kind of exception and will simply silently fails. This might be the explanation.