Skip to content

Instantly share code, notes, and snippets.

@Gnimuc
Created December 31, 2018 11:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Gnimuc/80edb3d5348220a74d9cb792d7ce9a29 to your computer and use it in GitHub Desktop.
Save Gnimuc/80edb3d5348220a74d9cb792d7ce9a29 to your computer and use it in GitHub Desktop.
face_normal
#version 410
in vec3 geo_position_eye, normal_eye;
uniform mat4 view_mat;
// fixed point light properties
vec3 light_position_world = vec3(0.0, 0.0, 5.0);
vec3 Ls = vec3(1.0, 1.0, 1.0); // white specular colour
vec3 Ld = vec3(0.7, 0.7, 0.7); // dull white diffuse light colour
vec3 La = vec3(0.2, 0.2, 0.2); // grey ambient colour
// surface reflectance
vec3 Ks = vec3(1.0, 1.0, 1.0); // fully reflect specular light
vec3 Kd = vec3(1.0, 0.5, 0.0); // orange diffuse surface reflectance
vec3 Ka = vec3(1.0, 1.0, 1.0); // fully reflect ambient light
float specular_exponent = 100.0; // specular 'power'
out vec4 fragment_colour; // final colour of surface
void main () {
// ambient intensity
vec3 Ia = La * Ka;
// diffuse intensity
// raise light position to eye space
vec3 light_position_eye = vec3(view_mat * vec4(light_position_world, 1.0));
vec3 distance_to_light_eye = light_position_eye - geo_position_eye;
vec3 direction_to_light_eye = normalize(distance_to_light_eye);
float dot_prod = dot(direction_to_light_eye, normal_eye);
dot_prod = max(dot_prod, 0.0);
vec3 Id = Ld * Kd * dot_prod; // final diffuse intensity
// specular intensity
vec3 surface_to_viewer_eye = normalize(-geo_position_eye);
// blinn
vec3 half_way_eye = normalize(surface_to_viewer_eye + direction_to_light_eye);
float dot_prod_specular = max(dot(half_way_eye, normal_eye), 0.0);
float specular_factor = pow(dot_prod_specular, specular_exponent);
vec3 Is = Ls * Ks * specular_factor; // final specular intensity
// final colour
fragment_colour = vec4(Is + Id + Ia, 1.0);
}
#version 410
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
in vec3 vert_position_eye[];
out vec3 geo_position_eye;
out vec3 normal_eye;
void main () {
vec3 vert1 = vert_position_eye[0];
vec3 vert2 = vert_position_eye[1];
vec3 vert3 = vert_position_eye[2];
vec3 edge1 = vert2 - vert1;
vec3 edge2 = vert3 - vert1;
vec3 face_normal = normalize(cross(edge1,edge2));
for(int i = 0; i < gl_in.length(); i++) {
gl_Position = gl_in[i].gl_Position;
geo_position_eye = vert_position_eye[i];
normal_eye = face_normal;
EmitVertex();
}
}
#version 410
layout (location = 0) in vec3 vertex_position;
uniform mat4 projection_mat, view_mat, model_mat;
out vec3 vert_position_eye;
void main () {
vert_position_eye = vec3(view_mat * model_mat * vec4(vertex_position, 1.0));
gl_Position = projection_mat * vec4(vert_position_eye, 1.0);
}
using GLFW
using ModernGL
using Reactive
using Quaternions
using Printf, LinearAlgebra
# helper functions
function shader_info_log(shader::GLuint)
maxLengthRef = Ref{GLsizei}(0)
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, maxLengthRef)
actualLengthRef = Ref{GLsizei}(0)
log = Vector{GLchar}(undef, maxLengthRef[])
glGetShaderInfoLog(shader, maxLengthRef[], actualLengthRef, log)
@info "shader info log for GL index $shader: $(String(log))"
end
function programme_info_log(program::GLuint)
maxLengthRef = Ref{GLsizei}(0)
glGetProgramiv(program, GL_INFO_LOG_LENGTH, maxLengthRef)
actualLengthRef = Ref{GLsizei}(0)
log = Vector{GLchar}(undef, maxLengthRef[])
glGetProgramInfoLog(program, maxLengthRef[], actualLengthRef, log)
@info "program info log for GL index $program: $(String(log))"
end
# init key signals
const KEYS = (:A, :D, :Q, :E, :W, :S, :LEFT, :RIGHT, :UP, :DOWN, :Z, :C)
for key in KEYS
signame = Symbol("sig$key")
@eval $signame = Signal(false)
end
## GLFW initialization
# set up GLFW key callbacks :
# Esc -> escape
# A -> slide left
# D -> slide right
# W -> move forward
# S -> move backward
# Q -> move upward
# E -> move downward
# LEFT -> yaw left
# RIGHT -> yaw right
# UP -> pitch up
# DOWN -> pitch down
# Z -> roll left
# C -> roll right
function key_callback(window::GLFW.Window, key::GLFW.Key, scancode::Cint, action::GLFW.Action, mods::Cint)
key == GLFW.KEY_ESCAPE && action == GLFW.PRESS && GLFW.SetWindowShouldClose(window, true)
key == GLFW.KEY_A && action == GLFW.PRESS && push!(sigA, true)
key == GLFW.KEY_A && action == GLFW.RELEASE && push!(sigA, false)
key == GLFW.KEY_D && action == GLFW.PRESS && push!(sigD, true)
key == GLFW.KEY_D && action == GLFW.RELEASE && push!(sigD, false)
key == GLFW.KEY_W && action == GLFW.PRESS && push!(sigW, true)
key == GLFW.KEY_W && action == GLFW.RELEASE && push!(sigW, false)
key == GLFW.KEY_S && action == GLFW.PRESS && push!(sigS, true)
key == GLFW.KEY_S && action == GLFW.RELEASE && push!(sigS, false)
key == GLFW.KEY_Q && action == GLFW.PRESS && push!(sigQ, true)
key == GLFW.KEY_Q && action == GLFW.RELEASE && push!(sigQ, false)
key == GLFW.KEY_E && action == GLFW.PRESS && push!(sigE, true)
key == GLFW.KEY_E && action == GLFW.RELEASE && push!(sigE, false)
key == GLFW.KEY_LEFT && action == GLFW.PRESS && push!(sigLEFT, true)
key == GLFW.KEY_LEFT && action == GLFW.RELEASE && push!(sigLEFT, false)
key == GLFW.KEY_RIGHT && action == GLFW.PRESS && push!(sigRIGHT, true)
key == GLFW.KEY_RIGHT && action == GLFW.RELEASE && push!(sigRIGHT, false)
key == GLFW.KEY_UP && action == GLFW.PRESS && push!(sigUP, true)
key == GLFW.KEY_UP && action == GLFW.RELEASE && push!(sigUP, false)
key == GLFW.KEY_DOWN && action == GLFW.PRESS && push!(sigDOWN, true)
key == GLFW.KEY_DOWN && action == GLFW.RELEASE && push!(sigDOWN, false)
key == GLFW.KEY_Z && action == GLFW.PRESS && push!(sigZ, true)
key == GLFW.KEY_Z && action == GLFW.RELEASE && push!(sigZ, false)
key == GLFW.KEY_C && action == GLFW.PRESS && push!(sigC, true)
key == GLFW.KEY_C && action == GLFW.RELEASE && push!(sigC, false)
end
# : change window size
function window_size_callback(window::GLFW.Window, width::Cint, height::Cint)
global glfwWidth = width
global glfwHeight = height
println("width", width, "height", height)
# update any perspective matrices used here
return nothing
end
# error callback
function error_callback(error::Cint, description::Ptr{GLchar})
logger = getlogger(current_module())
s = @sprintf "GLFW ERROR: code %i msg: %s" error description
error(logger, s)
return nothing
end
# _update_fps_counter
let previousTime = time()
frameCount = 0
global function updatefps(window::GLFW.Window)
currentTime = time()
elapsedTime = currentTime - previousTime
if elapsedTime > 0.25
previousTime = currentTime
fps = frameCount / elapsedTime
GLFW.SetWindowTitle(window, @sprintf("opengl @ fps: %.2f", fps))
frameCount = 0
end
frameCount = frameCount + 1
end
end
# camera
let
cameraSpeed = GLfloat(1.0)
cameraHeadingSpeed = GLfloat(10.0)
cameraPosition = GLfloat[0.0, 0.0, 0.0]
rotationMatrix = Matrix{GLfloat}(I, 4, 4)
quat = qrotation([0.0, 1.0, 0.0], 0)
viewMatrix = Matrix{GLfloat}(I, 4, 4)
# pitch-yaw-roll x-y'-z'' intrinsic convension
fwd = GLfloat[0.0, 0.0, -1.0, 0.0] # roll
rgt = GLfloat[1.0, 0.0, 0.0, 0.0] # pitch
up = GLfloat[0.0, 1.0, 0.0, 0.0] # yaw
previousCameraTime = time()
global function updatecamera()
currentCameraTime = time()
elapsedCameraTime = currentCameraTime - previousCameraTime
previousCameraTime = currentCameraTime
moveFlag = false
singleFrameMove = GLfloat[0.0, 0.0, 0.0]
value(sigA) && (singleFrameMove[1] -= cameraSpeed * elapsedCameraTime; moveFlag=true)
value(sigD) && (singleFrameMove[1] += cameraSpeed * elapsedCameraTime; moveFlag=true)
value(sigQ) && (singleFrameMove[2] -= cameraSpeed * elapsedCameraTime; moveFlag=true)
value(sigE) && (singleFrameMove[2] += cameraSpeed * elapsedCameraTime; moveFlag=true)
value(sigW) && (singleFrameMove[3] -= cameraSpeed * elapsedCameraTime; moveFlag=true)
value(sigS) && (singleFrameMove[3] += cameraSpeed * elapsedCameraTime; moveFlag=true)
value(sigLEFT) && (rotate(up, cameraHeadingSpeed * elapsedCameraTime); moveFlag=true)
value(sigRIGHT) && (rotate(up, -cameraHeadingSpeed * elapsedCameraTime); moveFlag=true)
value(sigUP) && (rotate(rgt, cameraHeadingSpeed * elapsedCameraTime); moveFlag=true)
value(sigDOWN) && (rotate(rgt, -cameraHeadingSpeed * elapsedCameraTime); moveFlag=true)
value(sigZ) && (rotate(fwd, cameraHeadingSpeed * elapsedCameraTime); moveFlag=true)
value(sigC) && (rotate(fwd, -cameraHeadingSpeed * elapsedCameraTime); moveFlag=true)
moveFlag && return get_view_matrix(singleFrameMove)
return viewMatrix
end
global get_camera_position() = cameraPosition
global set_camera_position(p::Vector{GLfloat}) = cameraPosition = p
global function set_camera_rotation(axis::Vector{GLfloat}, angle)
quat = qrotation(axis, angle)
rotationMatrix[1:3,1:3] = rotationmatrix(quat)
fwd = rotationMatrix * GLfloat[0.0, 0.0, -1.0, 0.0]
rgt = rotationMatrix * GLfloat[1.0, 0.0, 0.0, 0.0]
up = rotationMatrix * GLfloat[0.0, 1.0, 0.0, 0.0]
end
global function resetcamera()
set_camera_position(GLfloat[0.0, 0.0, 0.0])
set_camera_rotation(GLfloat[0.0, 1.0, 0.0], 0.0)
end
global function get_view_matrix(move=GLfloat[0.0,0.0,0.0])
cameraPosition += fwd[1:3] * -move[3]
cameraPosition += up[1:3] * move[2]
cameraPosition += rgt[1:3] * move[1]
transMatrix = GLfloat[ 1.0 0.0 0.0 cameraPosition[1];
0.0 1.0 0.0 cameraPosition[2];
0.0 0.0 1.0 cameraPosition[3];
0.0 0.0 0.0 1.0]
rotationMatrix[1:3,1:3] = rotationmatrix(quat)
viewMatrix = inv(rotationMatrix) * inv(transMatrix)
end
function rotate(axis, angle)
quatYaw = qrotation(axis[1:3], deg2rad(angle))
quat = quatYaw * quat
rotationMatrix[1:3,1:3] = rotationmatrix(quat)
fwd = rotationMatrix * GLfloat[0.0, 0.0, -1.0, 0.0]
rgt = rotationMatrix * GLfloat[1.0, 0.0, 0.0, 0.0]
up = rotationMatrix * GLfloat[0.0, 1.0, 0.0, 0.0]
end
end
# projective matrix
let
near = 0.01 # clipping near plane
far = 1000.0 # clipping far plane
fov = deg2rad(67)
global function get_projective_matrix()
aspectRatio = glfwWidth / glfwHeight
range = tan(0.5*fov) * near
Sx = 2.0*near / (range * aspectRatio + range * aspectRatio)
Sy = near / range
Sz = -(far + near) / (far - near)
Pz = -(2.0*far*near) / (far - near)
return GLfloat[ Sx 0.0 0.0 0.0;
0.0 Sy 0.0 0.0;
0.0 0.0 Sz Pz;
0.0 0.0 -1.0 0.0]
end
end
# Renderer
@static if Sys.isapple()
const VERSION_MAJOR = 4
const VERSION_MINOR = 1
end
# window init global variables
glfwWidth = 640
glfwHeight = 480
@static if Sys.isapple()
GLFW.WindowHint(GLFW.CONTEXT_VERSION_MAJOR, VERSION_MAJOR)
GLFW.WindowHint(GLFW.CONTEXT_VERSION_MINOR, VERSION_MINOR)
GLFW.WindowHint(GLFW.OPENGL_PROFILE, GLFW.OPENGL_CORE_PROFILE)
GLFW.WindowHint(GLFW.OPENGL_FORWARD_COMPAT, GL_TRUE)
else
GLFW.DefaultWindowHints()
end
@info "starting GLFW ..."
@info GLFW.GetVersionString()
# create window
window = GLFW.CreateWindow(glfwWidth, glfwHeight, "Init...")
window == C_NULL && error("could not open window with GLFW3.")
# set callbacks
GLFW.SetErrorCallback(error_callback)
GLFW.SetKeyCallback(window, key_callback)
GLFW.SetWindowSizeCallback(window, window_size_callback)
GLFW.MakeContextCurrent(window)
GLFW.WindowHint(GLFW.SAMPLES, 4)
# set camera
resetcamera()
set_camera_position(GLfloat[0.0, 0.0, 5.0])
# vertex and normal
points = GLfloat[ -1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, 1.0, -1.0,
-1.0, 1.0, -1.0]
faces = GLushort[0, 1, 2,
2, 3, 0,
1, 5, 6,
6, 2, 1,
7, 6, 5,
5, 4, 7,
4, 0, 3,
3, 7, 4,
4, 5, 1,
1, 0, 4,
3, 2, 6,
6, 7, 3]
# create buffers located in the memory of graphic card
pointsVBO = Ref{GLuint}(0)
glGenBuffers(1, pointsVBO)
glBindBuffer(GL_ARRAY_BUFFER, pointsVBO[])
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW)
facesEBO = Ref{GLuint}(0)
glGenBuffers(1, facesEBO)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, facesEBO[])
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(faces), faces, GL_STATIC_DRAW)
# create VAO
vaoID = Ref{GLuint}(0)
glGenVertexArrays(1, vaoID)
glBindVertexArray(vaoID[])
glBindBuffer(GL_ARRAY_BUFFER, pointsVBO[])
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, C_NULL)
glEnableVertexAttribArray(0)
# create shader program
# load shaders from file
const vertexShaderSource = read(joinpath(@__DIR__, "phong.vert"), String)
const geometryShaderSource = read(joinpath(@__DIR__, "phong.geom"), String)
const fragmentShaderSource = read(joinpath(@__DIR__, "phong.frag"), String)
# compile shaders and check for shader compile errors
vertexShader = glCreateShader(GL_VERTEX_SHADER)
glShaderSource(vertexShader, 1, Ptr{GLchar}[pointer(vertexShaderSource)], C_NULL)
glCompileShader(vertexShader)
# get shader compile status
resultRef = Ref{GLint}(-1)
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, resultRef)
if resultRef[] != GL_TRUE
shader_info_log(vertexShader)
@error "GL vertex shader(index $vertexShader) did not compile."
end
geometryShader = glCreateShader(GL_GEOMETRY_SHADER)
glShaderSource(geometryShader, 1, Ptr{GLchar}[pointer(geometryShaderSource)], C_NULL)
glCompileShader(geometryShader)
# get shader compile status
resultRef = Ref{GLint}(-1)
glGetShaderiv(geometryShader, GL_COMPILE_STATUS, resultRef)
if resultRef[] != GL_TRUE
shader_info_log(geometryShader)
@error "GL geometry shader(index $geometryShader) did not compile."
end
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER)
glShaderSource(fragmentShader, 1, Ptr{GLchar}[pointer(fragmentShaderSource)], C_NULL)
glCompileShader(fragmentShader)
# checkout shader compile status
resultRef = Ref{GLint}(-1)
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, resultRef)
if resultRef[] != GL_TRUE
shaderlog(fragmentShader)
@error "GL fragment shader(index $fragmentShader) did not compile."
end
# create and link shader program
shaderProgramID = glCreateProgram()
glAttachShader(shaderProgramID, vertexShader)
glAttachShader(shaderProgramID, geometryShader)
glAttachShader(shaderProgramID, fragmentShader)
glLinkProgram(shaderProgramID)
# checkout programe linking status
resultRef = Ref{GLint}(-1)
glGetProgramiv(shaderProgramID, GL_LINK_STATUS, resultRef)
if resultRef[] != GL_TRUE
programme_info_log(shaderProgramID)
@error "Could not link shader programme GL index: $shaderProgramID"
end
paramsRef = Ref{GLint}(-1)
glValidateProgram(shaderProgramID)
glGetProgramiv(shaderProgramID, GL_VALIDATE_STATUS, paramsRef)
@info "program $shaderProgramID GL_VALIDATE_STATUS = $(paramsRef[])"
if paramsRef[] != GL_TRUE
programme_info_log(shaderProgramID)
end
modelMatrixLocation = glGetUniformLocation(shaderProgramID, "model_mat")
viewMatrixLocation = glGetUniformLocation(shaderProgramID, "view_mat")
projMatrixLocation = glGetUniformLocation(shaderProgramID, "projection_mat")
glUseProgram(shaderProgramID)
modelMatrix = Matrix{GLfloat}(I, 4, 4)
glUniformMatrix4fv(modelMatrixLocation, 1, GL_FALSE, modelMatrix)
glUniformMatrix4fv(viewMatrixLocation, 1, GL_FALSE, get_view_matrix())
glUniformMatrix4fv(projMatrixLocation, 1, GL_FALSE, get_projective_matrix())
# enable depth test
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LESS)
# enable cull face
glEnable(GL_CULL_FACE)
glCullFace(GL_BACK)
glFrontFace(GL_CCW)
# render
while !GLFW.WindowShouldClose(window)
updatefps(window)
# clear drawing surface
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glViewport(0, 0, glfwWidth, glfwHeight)
# drawing
glUseProgram(shaderProgramID)
glBindVertexArray(vaoID[])
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, facesEBO[])
modelMatrix[1,4] = sin(time())
glUniformMatrix4fv(modelMatrixLocation, 1, GL_FALSE, modelMatrix)
glDrawElements(GL_TRIANGLES, length(faces), GL_UNSIGNED_SHORT, Ptr{Cvoid}(0))
# check and call events
GLFW.PollEvents()
yield()
# move camera
viewMatrix = updatecamera()
glUniformMatrix4fv(viewMatrixLocation, 1, GL_FALSE, viewMatrix)
# swap the buffers
GLFW.SwapBuffers(window)
end
GLFW.DestroyWindow(window)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment