1

The problem

I'm trying to make a basic specular material shader in pyglet, but it does not work as intended. It does not render the part behind the transparent cube, and just gives this wierd output instead. I want it to render the red cube behind the transparent cube with the shaders.

The code

main.py

from pyshaders import from_files_names, ShaderCompilationError 
try:
    shader = from_files_names("main.vert", "main.frag")
except ShaderCompilationError as e:
    print(e.logs) 
    exit()

import pyglet, math
from pyglet.gl import *
from pyglet.window import key

window = pyglet.window.Window(caption = 'specular materials', resizable = True)
key_ = pyglet.window.key.KeyStateHandler()
window.push_handlers(key_)

rot = [0, 0, 0]
campos = [0, 0, 0]
camrot = [0, 0, 0]
glEnable(GL_DEPTH_TEST)
glClearColor(0.5, 1, 1, 1)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)

def drawScene():
    # ground
    glBegin(GL_QUADS)
    glColor4f(0.5, 0.5, 0.5, 1)
    glVertex3f(-100, -9.9, -100)
    glVertex3f(-100, -9.9, 100)
    glVertex3f(100, -9.9, 100)
    glVertex3f(100, -9.9, -100)
    glEnd()
    # cube
    glPushMatrix()
    glTranslatef(0, 0, -5)
    glRotatef(rot[0], 1, 0, 0)
    glRotatef(rot[1], 0, 1, 0)
    glRotatef(rot[2], 0, 0, 1)
    glBegin(GL_QUADS)
    glColor4f(1, 0, 0, 1)
    glVertex3f(-1, -1, -1)
    glVertex3f(-1, 1, -1)
    glVertex3f(1, 1, -1)
    glVertex3f(1, -1, -1)
    glVertex3f(-1, -1, 1)
    glVertex3f(-1, 1, 1)
    glVertex3f(1, 1, 1)
    glVertex3f(1, -1, 1)
    glVertex3f(-1, -1, -1)
    glVertex3f(-1, -1, 1)
    glVertex3f(1, -1, 1)
    glVertex3f(1, -1, -1)
    glVertex3f(-1, 1, -1)
    glVertex3f(-1, 1, 1)
    glVertex3f(1, 1, 1)
    glVertex3f(1, 1, -1)
    glVertex3f(-1, -1, -1)
    glVertex3f(-1, 1, -1)
    glVertex3f(-1, 1, 1)
    glVertex3f(-1, -1, 1)
    glVertex3f(1, -1, -1)
    glVertex3f(1, 1, -1)
    glVertex3f(1, 1, 1)
    glVertex3f(1, -1, 1)
    glEnd()
    glPopMatrix()

def drawTransparent():
    # ground
    glColor4f(0.5, 0.5, 0.5, 0.1)
    glBegin(GL_QUADS)
    glVertex3f(-100, -10, -100)
    glVertex3f(-100, -10, 100)
    glVertex3f(100, -10, 100)
    glVertex3f(100, -10, -100)
    glEnd()
    # cube
    glColor4f(0.5, 0.5, 0.5, 0.1)
    glPushMatrix()
    glRotatef(rot[0], 1, 0, 0)
    glRotatef(rot[1], 0, 1, 0)
    glRotatef(rot[2], 0, 0, 1)
    glBegin(GL_QUADS)
    glColor4f(0.5, 0.5, 0.5, 0.5)
    glVertex3f(-1.1, -1.1, -1.1)
    glVertex3f(-1.1, 1.1, -1.1)
    glVertex3f(1.1, 1.1, -1.1)
    glVertex3f(1.1, -1.1, -1.1)
    glColor4f(0.5, 0.5, 0.5, 0.5)
    glVertex3f(-1.1, -1.1, 1.1)
    glVertex3f(-1.1, 1.1, 1.1)
    glVertex3f(1.1, 1.1, 1.1)
    glVertex3f(1.1, -1.1, 1.1)
    glColor4f(0.5, 0.5, 0.5, 0.5)
    glVertex3f(-1.1, -1.1, -1.1)
    glVertex3f(-1.1, -1.1, 1.1)
    glVertex3f(1.1, -1.1, 1.1)
    glVertex3f(1.1, -1.1, -1.1)
    glColor4f(0.5, 0.5, 0.5, 0.5)
    glVertex3f(-1.1, 1.1, -1.1)
    glVertex3f(-1.1, 1.1, 1.1)
    glVertex3f(1.1, 1.1, 1.1)
    glVertex3f(1.1, 1.1, -1.1)
    glColor4f(0.5, 0.5, 0.5, 0.5)
    glVertex3f(-1.1, -1.1, -1.1)
    glVertex3f(-1.1, 1.1, -1.1)
    glVertex3f(-1.1, 1.1, 1.1)
    glVertex3f(-1.1, -1.1, 1.1)
    glColor4f(0.5, 0.5, 0.5, 0.5)
    glVertex3f(1.1, -1.1, -1.1)
    glVertex3f(1.1, 1.1, -1.1)
    glVertex3f(1.1, 1.1, 1.1)
    glVertex3f(1.1, -1.1, 1.1)
    glEnd()
    glPopMatrix()

def step(dt):
    rot[0] += math.pi / 8
    rot[1] += math.pi / 6
    rot[2] += math.pi / 7
pyglet.clock.schedule_interval(step, 1/60)

@window.event
def on_draw():
    window.clear()
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(70, window.width/window.height, 0.05, 1000)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    glTranslatef(-campos[0], -campos[1], -campos[2])
    glRotatef(camrot[0], 1, 0, 0)
    glRotatef(camrot[1], 0, 1, 0)
    glEnable(GL_POLYGON_OFFSET_FILL)
    glPolygonOffset(1.0, 1.0)
    glEnable(GL_LIGHTING)
    shader.use()
    glLightfv(GL_LIGHT0, GL_AMBIENT, (GLfloat * 4)(0.2, 0.2, 0.2, 1))
    glLightfv(GL_LIGHT0, GL_DIFFUSE, (GLfloat * 4)(0, 0.5, 0.1, 0))
    glLightfv(GL_LIGHT0, GL_SPECULAR, (GLfloat * 4)(0, 0.5, 0.1, 0))
    glLightfv(GL_LIGHT0, GL_POSITION, (GLfloat * 4)(0, 0, 1, 0))
    glEnable(GL_LIGHT0)
    glEnable(GL_COLOR_MATERIAL)
    glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE)
    glMaterialfv(GL_FRONT, GL_SPECULAR, (GLfloat * 4)(0.5, 0.5, 0.5, 1))
    glMaterialf(GL_FRONT, GL_SHININESS, 125)
    glPushMatrix()
    glTranslatef(0, 0, -5)
    drawTransparent()
    glPopMatrix()
    glDisable(GL_LIGHTING)
    glDisable(GL_POLYGON_OFFSET_FILL)
    glDisable(GL_COLOR_MATERIAL)
    glDisable(GL_LIGHT0)
    glDisable(GL_LIGHTING)
    glUseProgram(0)
    glEnable(GL_BLEND)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    drawScene()
    
    if key_[key.A]:
        campos[0] -= 0.1
    if key_[key.D]:
        campos[0] += 0.1
    if key_[key.W]:
        campos[2] -= 0.1
    if key_[key.S]:
        campos[2] += 0.1

@window.event
def on_mouse_drag(x, y, dx, dy, buttons, modifiers):
    global camrot
    camrot[1] -= dx / 4
    camrot[0] += dy / 4

pyglet.app.run()

main.vert

varying vec3 vN;
varying vec3 v;
varying vec4 color;
void main(void)  
{     
   v = vec3(gl_ModelViewMatrix * gl_Vertex);       
   vN = normalize(gl_NormalMatrix * gl_Normal);
   color = gl_Color;
   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;  
}

main.frag

varying vec3 vN;
varying vec3 v; 
varying vec4 color;
#define MAX_LIGHTS 1 
void main (void) 
{ 
   vec3 N = normalize(vN);
   vec4 finalColor = vec4(0.0, 0.0, 0.0, 0.0);
   vec4 transparent = vec4(0.0, 0.0, 0.0, 0.1);
   
   for (int i=0;i<MAX_LIGHTS;i++)
   {
      vec3 L = normalize(gl_LightSource[i].position.xyz - v); 
      vec3 E = normalize(-v); // we are in Eye Coordinates, so EyePos is (0,0,0) 
      vec3 R = normalize(-reflect(L,N)); 
   
      vec4 Iamb = gl_LightSource[i].ambient; 
      vec4 Idiff = gl_LightSource[i].diffuse * max(dot(N,L), 0.0);
      Idiff = clamp(Idiff, 0.0, 1.0); 
      vec4 Ispec = gl_LightSource[i].specular * pow(max(dot(R,E),0.0),0.3*gl_FrontMaterial.shininess);
      Ispec = clamp(Ispec, 0.0, 1.0); 
   
      finalColor += Iamb + Idiff + Ispec;
   }
    gl_FragColor = color * finalColor * transparent; 
}

Screenshots

Output

Expected output

Expected output

+ with specular lighting

UPDATE

I've disabled depth test, but now there's another problem.

Output:

UPDATED OUTPUT

But the specular lighting shades every face the same. The blending works perfectly now thanks to @rabbid76's answer.

N3RDIUM
  • 358
  • 5
  • 22

1 Answers1

2

Blending and the Depth Test do not work at the same time without additional effort. If the front faces are drawn first, the back faces will never be blended because they are discarded by the depth test. You need to do depth sorting. Sort all the faces of the meshes by their depth and draw them in reverse order, back to front. See also Transparency Sorting.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174