Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Module #12

Merged
merged 19 commits into from
Jan 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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