Skip to content

Commit

Permalink
Merge pull request #12 from groverburger/module
Browse files Browse the repository at this point in the history
Module
  • Loading branch information
groverburger authored Jan 20, 2021
2 parents 63b8d62 + a8d2519 commit 4f01b6d
Show file tree
Hide file tree
Showing 10 changed files with 283 additions and 219 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,27 +34,27 @@ For more information, check out the [g3d wiki](https://github.com/groverburger/g
The entire `main.lua` file for the Earth and Moon demo is under 30 lines, as shown here:
```lua
-- written by groverbuger for g3d
-- october 2020
-- january 2021
-- MIT license

require "g3d"
g3d = require "g3d"

function love.load()
Earth = Model:new("assets/sphere.obj", "assets/earth.png", {0,0,4}, nil, {-1,1,1})
Moon = Model:new("assets/sphere.obj", "assets/moon.png", {5,0,4}, nil, {-0.5,0.5,0.5})
Background = Model:new("assets/sphere.obj", "assets/starfield.png", {0,0,0}, nil, {500,500,500})
Earth = g3d.newModel("assets/sphere.obj", "assets/earth.png", {0,0,4}, nil, {-1,1,1})
Moon = g3d.newModel("assets/sphere.obj", "assets/moon.png", {5,0,4}, nil, {-0.5,0.5,0.5})
Background = g3d.newModel("assets/sphere.obj", "assets/starfield.png", {0,0,0}, nil, {500,500,500})
Timer = 0
end

function love.mousemoved(x,y, dx,dy)
FirstPersonCameraLook(dx,dy)
g3d.camera.firstPersonLook(dx,dy)
end

function love.update(dt)
Timer = Timer + dt
Moon:setTranslation(math.cos(Timer)*5, 0, math.sin(Timer)*5 +4)
Moon:setRotation(0,-1*Timer,0)
FirstPersonCameraMovement(dt)
g3d.camera.firstPersonMovement(dt)
end

function love.draw()
Expand Down
Binary file added Thumbs.db
Binary file not shown.
141 changes: 95 additions & 46 deletions g3d/camera.lua
Original file line number Diff line number Diff line change
@@ -1,97 +1,146 @@
-- written by groverbuger for g3d
-- august 2020
-- january 2021
-- MIT license

local shader = require(G3D_PATH .. "/shader")
local matrices = require(G3D_PATH .. "/matrices")

----------------------------------------------------------------------------------------------------
-- define the camera singleton
----------------------------------------------------------------------------------------------------

local camera = {
fov = math.pi/2,
nearClip = 0.01,
farClip = 1000,
aspectRatio = love.graphics.getWidth()/love.graphics.getHeight(),
position = {0,0,0},
target = {0,0,0},
down = {0,-1,0},
}

-- private variables used only for the first person camera functions
local fpsController = {
direction = 0,
pitch = 0
}

-- give the camera a point to look from and a point to look towards
function camera.lookAt(x,y,z, xAt,yAt,zAt)
camera.position[1] = x
camera.position[2] = y
camera.position[3] = z
camera.target[1] = xAt
camera.target[2] = yAt
camera.target[3] = zAt

-- TODO: update fpsController's direction and pitch here

-- update the camera in the shader
camera.updateViewMatrix()
end

-- move and rotate the camera, given a point and a direction and a pitch (vertical direction)
function SetCamera(x,y,z, direction,pitch)
Camera.position[1] = x
Camera.position[2] = y
Camera.position[3] = z
Camera.direction = direction or Camera.direction
Camera.pitch = pitch or Camera.pitch
function camera.lookInDirection(x,y,z, directionTowards,pitchTowards)
camera.position[1] = x
camera.position[2] = y
camera.position[3] = z

fpsController.direction = directionTowards or fpsController.direction
fpsController.pitch = pitchTowards or fpsController.pitch

-- convert the direction and pitch into a target point
local sign = math.cos(Camera.pitch)
local sign = math.cos(fpsController.pitch)
if sign > 0 then
sign = 1
elseif sign < 0 then
sign = -1
else
sign = 0
end
local cosPitch = sign*math.max(math.abs(math.cos(Camera.pitch)), 0.001)
Camera.target[1] = Camera.position[1]+math.sin(Camera.direction)*cosPitch
Camera.target[2] = Camera.position[2]-math.sin(Camera.pitch)
Camera.target[3] = Camera.position[3]+math.cos(Camera.direction)*cosPitch
local cosPitch = sign*math.max(math.abs(math.cos(fpsController.pitch)), 0.001)
camera.target[1] = camera.position[1]+math.sin(fpsController.direction)*cosPitch
camera.target[2] = camera.position[2]-math.sin(fpsController.pitch)
camera.target[3] = camera.position[3]+math.cos(fpsController.direction)*cosPitch

-- update the camera in the shader
G3DShader:send("viewMatrix", GetViewMatrix(Camera.position, Camera.target, Camera.down))
camera.updateViewMatrix()
end

-- give the camera a point to look from and a point to look towards
function SetCameraAndLookAt(x,y,z, xAt,yAt,zAt)
Camera.position[1] = x
Camera.position[2] = y
Camera.position[3] = z
Camera.target[1] = xAt
Camera.target[2] = yAt
Camera.target[3] = zAt
-- recreate the camera's view matrix from its current values
-- and send the matrix to the shader specified, or the default shader
function camera.updateViewMatrix(shaderGiven)
(shaderGiven or shader):send("viewMatrix", matrices.getViewMatrix(camera.position, camera.target, camera.down))
end

-- update the camera in the shader
G3DShader:send("viewMatrix", GetViewMatrix(Camera.position, Camera.target, Camera.down))
-- recreate the camera's projection matrix from its current values
-- and send the matrix to the shader specified, or the default shader
function camera.updateProjectionMatrix(shaderGiven)
(shaderGiven or shader):send("projectionMatrix", matrices.getProjectionMatrix(camera.fov, camera.nearClip, camera.farClip, camera.aspectRatio))
end

-- recreate the camera's orthographic projection matrix from its current values
-- and send the matrix to the shader specified, or the default shader
function camera.updateOrthographicMatrix(size, shaderGiven)
(shaderGiven or shader):send("projectionMatrix", matrices.getOrthographicMatrix(camera.fov, size or 5, camera.nearClip, camera.farClip, camera.aspectRatio))
end

-- simple first person camera movement with WASD
-- put this function in your love.update to use, passing in dt
function FirstPersonCameraMovement(dt)
-- put this local function in your love.update to use, passing in dt
function camera.firstPersonMovement(dt)
-- collect inputs
local mx,my = 0,0
local moveX,moveY = 0,0
local cameraMoved = false
if love.keyboard.isDown("w") then
my = my - 1
moveY = moveY - 1
end
if love.keyboard.isDown("a") then
mx = mx - 1
moveX = moveX - 1
end
if love.keyboard.isDown("s") then
my = my + 1
moveY = moveY + 1
end
if love.keyboard.isDown("d") then
mx = mx + 1
moveX = moveX + 1
end
if love.keyboard.isDown("space") then
Camera.position[2] = Camera.position[2] - 0.15*dt*60
camera.position[2] = camera.position[2] - 0.15*dt*60
cameraMoved = true
end
if love.keyboard.isDown("lshift") then
Camera.position[2] = Camera.position[2] + 0.15*dt*60
camera.position[2] = camera.position[2] + 0.15*dt*60
cameraMoved = true
end

-- add camera's direction and movement direction
-- then move in the resulting direction
if mx ~= 0 or my ~= 0 then
local angle = math.atan2(my,mx)
local speed = 0.15
local dx,dz = math.cos(Camera.direction + angle)*speed*dt*60, math.sin(Camera.direction + angle + math.pi)*speed*dt*60
-- do some trigonometry on the inputs to make movement relative to camera's direction
-- also to make the player not move faster in diagonal directions
if moveX ~= 0 or moveY ~= 0 then
local angle = math.atan2(moveY,moveX)
local speed = 9
local directionX,directionZ = math.cos(fpsController.direction + angle)*speed*dt, math.sin(fpsController.direction + angle + math.pi)*speed*dt

Camera.position[1] = Camera.position[1] + dx
Camera.position[3] = Camera.position[3] + dz
camera.position[1] = camera.position[1] + directionX
camera.position[3] = camera.position[3] + directionZ
cameraMoved = true
end

-- update the camera's in the shader
-- only if the camera moved, for a slight performance benefit
if cameraMoved then
SetCamera(Camera.position[1],Camera.position[2],Camera.position[3], Camera.direction,Camera.pitch)
camera.lookInDirection(camera.position[1],camera.position[2],camera.position[3], fpsController.direction,fpsController.pitch)
end
end

-- best served with FirstPersonCameraMovement()
-- use this in your love.mousemoved function, passing in the movements
function FirstPersonCameraLook(dx,dy)
function camera.firstPersonLook(dx,dy)
-- capture the mouse
love.mouse.setRelativeMode(true)

local sensitivity = 1/300
Camera.direction = Camera.direction + dx*sensitivity
Camera.pitch = math.max(math.min(Camera.pitch - dy*sensitivity, math.pi*0.5), math.pi*-0.5)
fpsController.direction = fpsController.direction + dx*sensitivity
fpsController.pitch = math.max(math.min(fpsController.pitch - dy*sensitivity, math.pi*0.5), math.pi*-0.5)

SetCamera(Camera.position[1],Camera.position[2],Camera.position[3], Camera.direction,Camera.pitch)
camera.lookInDirection(camera.position[1],camera.position[2],camera.position[3], fpsController.direction,fpsController.pitch)
end

return camera
70 changes: 14 additions & 56 deletions g3d/init.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
-- written by groverbuger for g3d
-- august 2020
-- january 2021
-- MIT license

--[[
Expand All @@ -14,63 +14,21 @@
\_/__/
--]]

----------------------------------------------------------------------------------------------------
-- set up the basic 3D shader
----------------------------------------------------------------------------------------------------
-- the shader that projects 3D meshes onto the screen
-- add the path to g3d to the global namespace
-- so submodules can know how to load their dependencies
G3D_PATH = ...

G3DShader = love.graphics.newShader [[
uniform mat4 projectionMatrix;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
local g3d = {}

varying vec4 vertexColor;
#ifdef VERTEX
vec4 position(mat4 transform_projection, vec4 vertex_position)
{
vertexColor = VertexColor;
return projectionMatrix * viewMatrix * modelMatrix * vertex_position;
}
#endif
#ifdef PIXEL
vec4 effect(vec4 color, Image tex, vec2 texcoord, vec2 pixcoord)
{
vec4 texcolor = Texel(tex, texcoord);
if (texcolor.a == 0.0) { discard; }
return vec4(texcolor)*color*vertexColor;
}
#endif
]]

----------------------------------------------------------------------------------------------------
-- load in all the required files
----------------------------------------------------------------------------------------------------

require(... .. "/matrices")
require(... .. "/objloader")
require(... .. "/model")
require(... .. "/camera")

----------------------------------------------------------------------------------------------------
-- set up the basic camera
----------------------------------------------------------------------------------------------------

Camera = {
fov = math.pi/2,
nearClip = 0.01,
farClip = 1000,
aspectRatio = love.graphics.getWidth()/love.graphics.getHeight(),
position = {0,0,0},
target = {0,0,1},
direction = 0,
pitch = 0,
down = {0,-1,0},
}

-- create the projection matrix from the camera and send it to the shader
G3DShader:send("projectionMatrix", GetProjectionMatrix(Camera.fov, Camera.nearClip, Camera.farClip, Camera.aspectRatio))
g3d.newModel = require(G3D_PATH .. "/model")
g3d.camera = require(G3D_PATH .. "/camera")
g3d.camera.updateProjectionMatrix()

-- so that far polygons don't overlap near polygons
love.graphics.setDepthMode("lequal", true)

-- get rid of G3D_PATH from the global namespace
-- so the end user doesn't have to worry about any globals
G3D_PATH = nil

return g3d
Loading

0 comments on commit 4f01b6d

Please sign in to comment.