0
$\begingroup$

I am creating a cylinder, and there is fog around it. I can't handle two things:

  1. the inner surface of the cylinder, realized as a smaller diameter cylinder, actually gives me just a second cylinder inserted into a wider cylinder. How to achieve a monolithic figure?

  2. fog: now it turns out as shown in the screenshot. I need a full-fledged fog with a cloud texture. What's wrong with the code?

enter image description here

I used any file with a cloud (fog) in the format.jpg. By the way, the .png format gave about the same error

Code:

import pygame
from pygame.locals import *
import math
from OpenGL.GL import *
from OpenGL.GLU import *

# creating a window
pygame.init()
display = (800, 600)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)

# animation
glMatrixMode(GL_PROJECTION)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)

glMatrixMode(GL_MODELVIEW)
gluLookAt(0, -10, 10, 0, 0, 0, 0, 1, 0)

# setting the properties of the cylinders
gluQuadric = gluNewQuadric()
gluQuadricTexture(gluQuadric, GL_TRUE)

def draw_cylinder(color):

    glColor3fv(color)

    gluCylinder(gluQuadric, cylinder_rad, cylinder_rad, cylinder_height, 32, 1)

    # inner surface
    glColor3f(color[0]*0.3, color[1]*0.3, color[2]*0.3)
    gluCylinder(gluQuadric, cylinder_rad-cylinder_thickness, cylinder_rad-cylinder_thickness, cylinder_height, 32, 1)

# objects
cylinder_color = (0., 0.5, 0.5)
cylinder_rad = 2.5
cylinder_thickness = 1.8
cylinder_height = 4

# the radius of the circle along which the icosahedron and torus will rotate
circle_radius = cylinder_rad * 2

# creating a cloud texture
cloud_texture = pygame.image.load('cloud_texture.jpg')
cloud_texture_surface = pygame.image.tostring(cloud_texture, "RGB", 1)
cloud_texture_width = cloud_texture.get_width()
cloud_texture_height = cloud_texture.get_height()

# setting the position and size of the fog
fog_size = 0.25
fog_pos_x = - circle_radius - cylinder_rad/2
fog_pos_y = cylinder_rad/2
fog_pos_z = 1

# the main rendering cycle
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            quit()

    glClearColor(0, 0.1, 0.1, 1)
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
    
    glEnable(GL_DEPTH_TEST)

    # setting up the matrix
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(45.0, float(display[0])/float(display[1]), 0.1, 50.0)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()

    gluLookAt(0, -10, 10, 0, 0, 0, 0, 1, 0)
    
    # draw a cylinder
    draw_cylinder(cylinder_color)
    
    # setting up the fog
    glEnable(GL_BLEND)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

    glEnable(GL_TEXTURE_2D)
    glBindTexture(GL_TEXTURE_2D, glGenTextures(1))
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, cloud_texture_width, cloud_texture_height, 0, GL_RGB, GL_UNSIGNED_BYTE, cloud_texture_surface)

    glEnable(GL_FOG)
    glFogi(GL_FOG_MODE, GL_EXP2)
    
    glFogfv(GL_FOG_COLOR, [1, 1, 1, 1])
    glFogf(GL_FOG_DENSITY, 0.5)
    glFogf(GL_FOG_START, 0.0)
    glFogf(GL_FOG_END, 10.0)

    # drawing the fog
    glBegin(GL_QUADS)
    glTexCoord2f(0.0, 0.0); glVertex3f(fog_pos_x-fog_size, fog_pos_y-fog_size, fog_pos_z)
    glTexCoord2f(1.0, 0.0); glVertex3f(fog_pos_x+fog_size, fog_pos_y-fog_size, fog_pos_z)
    glTexCoord2f(1.0, 1.0); glVertex3f(fog_pos_x+fog_size, fog_pos_y+fog_size, fog_pos_z)
    glTexCoord2f(0.0, 1.0); glVertex3f(fog_pos_x-fog_size, fog_pos_y+fog_size, fog_pos_z)
    glEnd()

    glDisable(GL_FOG)
    glDisable(GL_TEXTURE_2D)
    glDisable(GL_BLEND)

    pygame.display.flip()
    pygame.time.wait(10)
$\endgroup$

1 Answer 1

1
$\begingroup$

the inner surface of the cylinder, realized as a smaller diameter cylinder, actually gives me just a second cylinder inserted into a wider cylinder. How to achieve a monolithic figure?

gluCylinder does not draw ends — only the sides of a cylinder. You will need to also use gluDisk to draw flat ends too.

If you want to have lighting, or back-face culling, you will also need to set gluQuadricOrientation to INSIDE while drawing the inner surface cylinder.

Note that this entire style of drawing is obsolete — the modern way is to pre-compute the entire mesh (all surfaces of the cylinder together), put it in a vertex buffer (memory on the GPU), and command the GPU to draw that, rather than computing and sending all the vertices every frame. (This doesn't matter for a scene this simple, but if you wish to draw much more complex scenes, it is important to use buffers for better performance.)

fog: now it turns out as shown in the screenshot. I need a full-fledged fog with a cloud texture. What's wrong with the code?

The fog feature built into the GL fixed-function rendering pipeline does not use a texture, and also doesn't work the way you've set it up. What it does is, when other objects are being drawn, blend their color to the fog color based on distance. In order to use it you would have to enable fog while drawing your cylinder, not while drawing the cloud texture.

But that won't get you textured fog. In order to use a texture, you will need to use a fragment shader which computes the fog blending itself and uses the texture instead of just a color. That's a much bigger topic and I'm not able to tell you all the steps to set up a shader in your particular environment, but I hope the pointer will be useful.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.