Created
December 31, 2018 11:11
-
-
Save Gnimuc/80edb3d5348220a74d9cb792d7ce9a29 to your computer and use it in GitHub Desktop.
face_normal
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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