[Solved] How to make an interpolated Triangle w/ vertex & pixel shaders?
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
-
- Prole
- Posts: 7
- Joined: Sun Jan 22, 2023 3:42 pm
Re: [Solved] How to make an interpolated Triangle w/ vertex & pixel shaders?
Exactly when you replied I also realized that I just had to change that value. Sorry but thanks for the solution!
Re: How to make an interpolated Triangle w/ vertex & pixel shaders?
Looking at that Shader Variables page you linked to, it mentions a "VaryingColor" variable predefined by the Löve base shader code. It's used in these lines:
- https://github.com/love2d/love/blob/02d ... r.lua#L227
- https://github.com/love2d/love/blob/02d ... r.lua#L233
Looking at how it's used in there, I think we can spare that vColor variable and use VaryingColor directly, something like this:
(Thanks for the template code by the way)
- https://github.com/love2d/love/blob/02d ... r.lua#L227
- https://github.com/love2d/love/blob/02d ... r.lua#L233
Looking at how it's used in there, I think we can spare that vColor variable and use VaryingColor directly, something like this:
(Thanks for the template code by the way)
Code: Select all
local lg = love.graphics
-- Create attributes of the triangle
local attributes = {
{"VertexPosition", "float", 2},
{"VertexColor", "float", 4},
}
-- Create the triangle vertices.
-- The attributes per-vertex are X, Y, R, G, B, A.
local vertices = {
{-0.5, -0.5, 1.0, 0.0, 0.0, 1.0},
{0.5, -0.5, 0.0, 1.0, 0.0, 1.0},
{0.0, 0.5, 0.0, 0.0, 1.0, 1.0}
}
-- Create a new mesh to hold the triangle
local triangle = lg.newMesh(attributes, vertices, "triangles", "static")
-- Set up the color interpolation pixel shader.
local shader = lg.newShader([[
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
return VaryingColor;
}
]])
function love.draw()
lg.setShader(shader)
lg.draw(triangle,lg.getWidth()/2,lg.getHeight()/2,0,200,200)
lg.setShader()
end
Re: [Solved] How to make an interpolated Triangle w/ vertex & pixel shaders?
Yes I specified it in my previous post, it was to illustrate how to pass a variable from vertex shader to the fragment shader.
Re: [Solved] How to make an interpolated Triangle w/ vertex & pixel shaders?
Ah, I missed that! Thanks.
-
- Prole
- Posts: 7
- Joined: Sun Jan 22, 2023 3:42 pm
Re: How to make an interpolated Triangle w/ vertex & pixel shaders?
After reading https://www.love2d.org/wiki/Shader_Variables I couldn't find "VaryingNormal" anywhere, and I need that for the lighting to be smooth. Is there any way to interpolate the normal when it gets passed from the VertexShader to the FragmentShader / PixelShader? I tried using "varying vec3 Normal;" and then in the position() function "Normal = VertexNormal;". But I don't know exactly why, but I had to include "attribute vec3 VertexNormal;" in order for it not to scream: "undeclared identifier", even though I included it in the vertex attributes of the mesh and also added the normal values at the mesh construction. Then inside the FragmentShader: "varying vec3 Normal;" and inside effect() I just use the value and do my light equations, but it doesn't seem to be interpolated which is a problem. Basically, I want the normal to interpolate in a way that its origin comes from the current pixel in the FragmentShader. Then I later do a dot product to see if the light is pointing directly at it or not. How would I interpolate a normal if I don't have a "VaryingNormal" variable? Or did I do something wrong with the normal?Bigfoot71 wrote: ↑Mon Jan 23, 2023 12:14 pm Note that I added the vertex shader as an example to show how to pass a variable from the vertex to the fragment, but the variable `VertexColor` to a correspondence directly offered by Löve accessible in the fragment shader which is `VaryingColor` so the last shader that I proposed can be simplified like this:
Hence the fact that I say that doing it directly in OpenGL allows you to learn more because Löve does a lot of work for us at this level. After once this kind of basic acquired Löve still allows you to progress faster on learning because this kind of tests are faster to perform in Lua but you must already have these basics. Hence once again the fact that I wonder about the usefulness of following an OpenGL tutorial with Löve2d, after again it's only my opinion, I may be wrong.Code: Select all
local shader = lg.newShader([[ vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) { return VaryingColor; } ]])
Edit: I'm thinking about it but if you really want to do all that in Löve2d I can only recommend this blog post on shaders in Löve2d which is very useful! https://blogs.love2d.org/content/beginn ... de-shaders
Code: Select all
local MeshAttributes = {
{"VertexPosition", "float", 3},
{"VertexTexCoord", "float", 2},
{"VertexNormal", "float", 3},
{"VertexColor", "byte", 4},
}
local shader = LG.newShader([[
// -- -- -- -- -- -- -- -- -- -- -- -- -- -- //
// Vertex Shader
// -- -- -- -- -- -- -- -- -- -- -- -- -- -- //
extern mat4 World;
varying vec3 Normal;
attribute vec3 VertexNormal;
varying vec3 LocalPos;
vec4 position(mat4 transform_projection, vec4 Position) {
Normal = VertexNormal;
vec4 Transformed = World * Position;
vec4 ScreenSpace = transform_projection * Transformed;
ScreenSpace.z = -ScreenSpace.z;
LocalPos = vec3(Position);
return ScreenSpace;
}
]], [[
// -- -- -- -- -- -- -- -- -- -- -- -- -- -- //
// Fragment Shader
// -- -- -- -- -- -- -- -- -- -- -- -- -- -- //
struct BaseLight {
vec3 Color;
float AmbientIntensity;
};
struct DirLight {
vec3 Color;
vec3 Direction;
float AmbientIntensity;
float DiffuseIntensity;
};
// Light Arrays
extern BaseLight BaseLights[1];
extern DirLight DirLights[1];
// Material
extern vec3 MaterialAmbientColor;
extern vec3 MaterialDiffuseColor;
extern vec3 MaterialSpecularColor;
extern vec3 CameraLocalPos;
varying vec3 Normal;
varying vec3 LocalPos;
vec4 effect(vec4 Color, Image image, vec2 uvs, vec2 screen_coords){
// Interpolation: return VaryingColor;
BaseLight gLight = BaseLights[0];
DirLight gLight2 = DirLights[0];
//vec4 LightColor = gLight.Color * gLight.AmbientIntensity;
vec3 LocalAmbientColor = gLight2.Color * gLight2.AmbientIntensity * MaterialAmbientColor;
float DiffuseFactor = dot(normalize(Normal), -gLight2.Direction);
vec3 LocalDiffuseColor = vec3(0, 0, 0);
vec3 LocalSpecularColor = vec3(0, 0, 0);
if (DiffuseFactor > 0){
LocalDiffuseColor = gLight2.Color * gLight2.DiffuseIntensity * MaterialDiffuseColor * DiffuseFactor;
vec3 PixelToCamera = normalize(CameraLocalPos - LocalPos);
vec3 LightReflect = normalize(reflect(gLight2.Direction, Normal));
float SpecularFactor = dot(PixelToCamera, LightReflect);
if (SpecularFactor > 0) {
// texture is grayscale
//float SpecularExponent = Texel(SpecularTexture, uvs).r * 255.0;
SpecularFactor = pow(SpecularFactor, 3.0);
LocalSpecularColor = gLight2.Color * MaterialSpecularColor * SpecularFactor;
}
}
return Texel(image, uvs) * clamp(vec4(LocalAmbientColor + LocalDiffuseColor + LocalSpecularColor, 1.0f), 0, 1);
}
]])
Re: How to make an interpolated Triangle w/ vertex & pixel shaders?
Not having all your code to try from what I understand you are unable to pass the `VertexNormal` attribute to the fragment shader, to do this you just need to do something like this:
Is that right?
Edit: By reviewing your code I think in fact that you have understood this, but not being able to test it I am not sure to tell you where the problem comes from.
If you don't want/can't share it in full you can always go see the library I quoted (g3d) to see how it handles all this, do your tests with then once you have understood start again from scratch with your knowledge. Here the link to are vertex shader.
If not, share your code with us so we can better understand the problem
Code: Select all
attribute vec3 VertexNormal; // Mesh attribute
varying vec3 VaryingNormal; // "Varying value" that will be used to pass VertexNormal to the fragment shader
vec4 position( mat4 transform_projection, vec4 vertex_position ) {
VaryingNormal = VertexNormal; // Set "varying value" with attribute
return transform_projection * vertex_position;
}
Code: Select all
varying vec3 VaryingNormal; // Redecalate the "varying value" here to be able to use it
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
// Make your calculations
}
Edit: By reviewing your code I think in fact that you have understood this, but not being able to test it I am not sure to tell you where the problem comes from.
If you don't want/can't share it in full you can always go see the library I quoted (g3d) to see how it handles all this, do your tests with then once you have understood start again from scratch with your knowledge. Here the link to are vertex shader.
If not, share your code with us so we can better understand the problem
-
- Prole
- Posts: 7
- Joined: Sun Jan 22, 2023 3:42 pm
Re: How to make an interpolated Triangle w/ vertex & pixel shaders?
Here's the "Render" script, btw I call all these functions from the main.lua file.Bigfoot71 wrote: ↑Thu Jan 26, 2023 12:00 pm Not having all your code to try from what I understand you are unable to pass the `VertexNormal` attribute to the fragment shader, to do this you just need to do something like this:
Code: Select all
attribute vec3 VertexNormal; // Mesh attribute varying vec3 VaryingNormal; // "Varying value" that will be used to pass VertexNormal to the fragment shader vec4 position( mat4 transform_projection, vec4 vertex_position ) { VaryingNormal = VertexNormal; // Set "varying value" with attribute return transform_projection * vertex_position; }
Is that right?Code: Select all
varying vec3 VaryingNormal; // Redecalate the "varying value" here to be able to use it vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) { // Make your calculations }
Edit: By reviewing your code I think in fact that you have understood this, but not being able to test it I am not sure to tell you where the problem comes from.
If you don't want/can't share it in full you can always go see the library I quoted (g3d) to see how it handles all this, do your tests with then once you have understood start again from scratch with your knowledge. Here the link to are vertex shader.
If not, share your code with us so we can better understand the problem
Code: Select all
local Render = {}
--// Requires
local mlib = require("mlib")
--// Read-Only Settings
local MeshAttributes = {
{"VertexPosition", "float", 3},
{"VertexTexCoord", "float", 2},
{"VertexNormal", "float", 3},
{"VertexColor", "byte", 4},
}
--// Get Shader Files
local VertexShader = love.filesystem.read("VertexShader.txt")
local FragmentShader = love.filesystem.read("FragmentShader.txt")
--// Löve
local LG = love.graphics
local LI = love.image
local LK = love.keyboard
local LW = love.window
--// Other optimisations
local sin = math.sin
local cos = math.cos
local tan = math.tan
local rad = math.rad
local abs = math.abs
local min = math.min
local max = math.max
local pi = math.pi
local sqrt = math.sqrt
local floor = math.floor
local ceil = math.ceil
local huge = math.huge
local random = math.random
local num = tonumber
--// Shaders
local MainShader = LG.newShader(VertexShader, FragmentShader)
--// Globals
local CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
local NUMBERS = "1234567890"
local SYMBOLS = "!@#$%^&*()'=-+_/.,<>"
local KEYS = CHARACTERS .. NUMBERS .. SYMBOLS
--// Variables
local Canvas = nil
local DepthCanvas = nil
local LightWorkspace = {}
--// Engine Variables
Render.Workspace = {}
Render.MainCamera = nil
Render.ObjectMaterials = {}
Render.ProjectionMatrix = nil
--// Config Settings
Render.ScreenWidth = 1920
Render.ScreenHeight = 1080
Render.FullScreen = true
Render.Resizable = false
Render.DepthType = "depth32f"
Render.zNear = 1
Render.zFar = 1000
Render.FOV = 30
Render.Spawn = mlib.Vector3(0, 0, 0)
Render.EscapeKey = "escape"
Render.RestartKey = "r"
Render.ObjectPath = "Objects"
Render.TexturePath = "Textures"
Render.AlwaysPanning = false
Render.MousePanButton = 2
Render.MouseSensivity = 0.7
Render.CameraPitch = 0
Render.CameraYaw = 0
Render.CameraRoll = 0
Render.TurnSpeed = -0.5
--// Utility
function Render.SplitString(x, Seperator)
--if Seperator == nil then Seperator = "%s" end
local t = {}
local i = 1
for str in string.gmatch(x, "([^".. Seperator .."]+)") do t[i] = str; i = i + 1 end
return t
end; local SplitString = Render.SplitString
function Render.ArrayToString(Array)
local Result = ""
local i = 0
for k, v in pairs(Array) do
i = i + 1
if type(v) == "table" then v = Render.ArrayToString(v) end
if type(v) ~= "userdata" then Result = Result .. "\n[" .. k .. "]: " .. v end
if i ~= #Array then Result = Result .. ", " end
end
if Result == "" and i == 0 then Result = "nil" end
return Result
end; local ArrayToString = Render.ArrayToString
function Render.RandomColor()
local R = random(0, 100) / 100
local G = random(0, 100) / 100
local B = random(0, 100) / 100
return R, G, B, 1
end; local RandomColor = Render.RandomColor
function Render.Lock(x, MinValue, MaxValue)
return max(min(x, MaxValue), MinValue)
end; local lock = Render.Lock
--// Engine Classes
local BaseLight = {Type = "BaseLight"}
BaseLight.__index = BaseLight
function Render.BaseLight()
local self = setmetatable({
Color = {1, 1, 1};
AmbientIntensity = 1;
}, BaseLight)
return self
end
local DirectionalLight = setmetatable({Type = "DirectionalLight"}, BaseLight)
DirectionalLight.__index = DirectionalLight
function Render.DirectionalLight()
local self = setmetatable({
Color = {1, 1, 1};
AmbientIntensity = 1;
DiffuseIntensity = 1;
WorldDirection = mlib.Vector3(0, 0, 0);
LocalDirection = mlib.Vector3(0, 0, 0);
}, DirectionalLight)
LightWorkspace[#LightWorkspace+1] = self
return self
end
function DirectionalLight:Calc(WM)
--// Get rid of translation in matrix, because not required
local World3 = mlib.Convert(WM, "Matrix3")
--[[
local World3 = {
WM[1], WM[5], WM[9],
WM[2], WM[6], WM[10],
WM[3], WM[7], WM[11]
}
]]
self.LocalDirection = (World3 * self.WorldDirection):Normalise()
end
local Mesh = {}
Mesh.__index = Mesh
local function GetObjectByID(ID)
for Alias, Object in pairs(Render.Workspace) do if Object.ID == ID then return Object end end
end
function Mesh:SetAlias(Alias)
if Render.Workspace[Alias] ~= nil then
local NewID = Alias
local Found = false
while true do
for i = 1, #KEYS, 1 do --// Go through every character and check if it works
local Attempt = NewID .. KEYS[i]
if not GetObjectByID(Attempt) then
NewID = Attempt
Found = true
break
end
end
if Found == true then break end
NewID = NewID .. "_" --// We can add any symbol technically
end
self.ID = NewID
else
self.ID = Alias
end
end
function Mesh:InsertWorkspace(Alias)
self:SetAlias(Alias)
Render.Workspace[self.ID] = self
end
function Mesh:SetPosition(X, Y, Z) self.Position[1] = X; self.Position[2] = Y; self.Position[3] = Z end
function Mesh:SetRotation(X, Y, Z) self.Rotation[1] = X; self.Rotation[2] = Y; self.Rotation[3] = Z end
function Mesh:SetSize(X, Y, Z) self.Size[1] = X; self.Size[2] = Y; self.Size[3] = Z end
function Mesh:Rotate(AngleX, AngleY, AngleZ)
self.Rotation[1] = self.Rotation[1] + (AngleX or 0)
self.Rotation[2] = self.Rotation[2] + (AngleY or 0)
self.Rotation[3] = self.Rotation[3] + (AngleZ or 0)
end
local Material = {}
Material.__index = Material
function Render.Material()
local self = setmetatable({
AmbientColor = {0, 0, 0};
DiffuseColor = {0, 0, 0};
SpecularColor = {0, 0, 0};
}, Material)
return self
end
function Render.ReadMaterial(FilePath)
--// This function will go through all the data in the .mtl file
--// it will create new materials and insert all of them inside an ObjectMaterials array
--// from there the MeshLoadObjectFile can use these materials with "usemtl"
local FileContent = nil
local Success, ErrorMessage = pcall(function() FileContent = love.filesystem.read(FilePath) end)
if not Success then return 0, "File not found or cant't read file!" end
local NewMaterial = nil
local MaterialName = ""
local Lines = SplitString(FileContent, "\n")
for _, Line in ipairs(Lines) do
local Tokens = SplitString(Line, " ")
local Prefix = Tokens[1]
if Prefix == "newmtl" then
--// Put Material inside ObjectMaterials array
MaterialName = Tokens[2]
if NewMaterial ~= nil then assert(Render.ObjectMaterials[MaterialName] ~= nil, "Material with name already exists!") end
NewMaterial = Render.Material()
Render.ObjectMaterials[MaterialName] = NewMaterial
elseif Prefix == "Ns" then
elseif Prefix == "Ka" then --// AmbientColor
NewMaterial.AmbientColor[1] = Tokens[2]
NewMaterial.AmbientColor[2] = Tokens[3]
NewMaterial.AmbientColor[3] = Tokens[4]
elseif Prefix == "Kd" then --// Diffuse
NewMaterial.DiffuseColor[1] = Tokens[2]
NewMaterial.DiffuseColor[2] = Tokens[3]
NewMaterial.DiffuseColor[3] = Tokens[4]
elseif Prefix == "Ks" then --// Specular
NewMaterial.SpecularColor[1] = Tokens[2]
NewMaterial.SpecularColor[2] = Tokens[3]
NewMaterial.SpecularColor[3] = Tokens[4]
elseif Prefix == "Ke" then
elseif Prefix == "Ni" then
elseif Prefix == "d" then --// Opaque
elseif Prefix == "illum" then
elseif Prefix == "map_Bump" then
elseif Prefix == "map_Kd" then
elseif Prefix == "map_Ns" then
elseif Prefix == "refl" then
elseif Prefix == "Material" then --// Material Color
end
end
end
function Render.FormatImageName(Name, Directory)
local Result = Directory .. "/" .. Name
local x = string.gsub(Result, "_diff", "") --// Append the TexturePath
--\\ Roblox appends _diff to all of their textures when exporting for some reason, so we get rid of it
--// There is no easy way to get a file without extension in love2d, so defualt is png
Result = Result .. ".png"
return Result
end
function Render.LoadObject(ObjectName, FixedTexture)
--// We get the folder that the .obj is located in, inside the Objects folder
--// Then we get the .obj file inside of that folder, Quite complicated lol
local Directory = Render.ObjectPath .. "/" .. ObjectName .. "/"
local TextureDirectory = Directory .. "Textures/"
local ObjectFile = Directory .. ObjectName .. ".obj"
local FileContent = love.filesystem.read(ObjectFile)
if FileContent == nil then return end
--assert(FileContent == nil, "File not found or can't read file!")
--// Find Material File, and use it if it's found
Render.ReadMaterial(Directory .. ObjectName .. ".mtl")
--// Create caches
local Vertices = {}
local Normals = {}
local Textures = {}
local ObjectMesh = Render.Mesh(ObjectName)
local Meshes = {}
--// If FixedTexture isn't included, this will result in being nil
local TextureData = FixedTexture
local MaterialName = ""
local Lines = SplitString(FileContent, "\n")
for _, Line in ipairs(Lines) do
local NewMesh = nil
local Tokens = SplitString(Line, " ")
local Prefix = Tokens[1]
if Prefix == "v" then --// Create Vertex
Vertices[#Vertices+1] = mlib.Vector3(num(Tokens[2]), num(Tokens[3]), num(Tokens[4]))
elseif Prefix == "f" then --// Create face of vertices
local Segments1 = SplitString(Tokens[2], "/")
local Segments2 = SplitString(Tokens[3], "/")
local Segments3 = SplitString(Tokens[4], "/")
ObjectMesh.Triangles[#ObjectMesh.Triangles+1] = {
--// Vertex Data
Vertices[num(Segments1[1])];
Vertices[num(Segments2[1])];
Vertices[num(Segments3[1])];
--// Texture Data
Textures[num(Segments1[2])];
Textures[num(Segments2[2])];
Textures[num(Segments3[2])];
TextureData;
--// Normal Data
Normals[num(Segments1[3])];
Normals[num(Segments2[3])];
Normals[num(Segments3[3])];
}
elseif Prefix == "vn" then --// Create Normal
Normals[#Normals+1] = mlib.Vector3(num(Tokens[2]), num(Tokens[3]), num(Tokens[4]))
elseif Prefix == "vt" then --// Create UV coordinates
Textures[#Textures+1] = mlib.Vector2(num(Tokens[2]), num(Tokens[3]))
elseif Prefix == "g" then --// Creates new object group for upcoming faces
--// If object is empty, don't create a new one just yet
if #Vertices ~= 0 then NewMesh = Tokens[2] end
ObjectMesh:SetAlias(Tokens[2]) --// Name the object accordingly
--\\ We handle objects like groups in this case
--// Search for texture if there is any
local Data = nil
local Success, ErrorMessage = pcall(function()
Data = LG.newImage(Render.FormatImageName(Tokens[2], TextureDirectory))
end)
--// If texture is found, set it
if Success and not FixedTexture then TextureData = Data end
elseif Prefix == "usemtl" or Prefix == "mtllib" then --// Set Material of upcoming triangles
--// Set the material of the object
--MaterialName = Tokens[2]
MaterialName = Tokens[2]
ObjectMesh.ObjectMaterial = Render.ObjectMaterials[MaterialName]
end
if NewMesh ~= nil then
--// If NewMesh isn't nil then create a new mesh
--// Note: Caches don't have to be reset, index just goes up even though new object is formed
Meshes[#Meshes+1] = ObjectMesh
ObjectMesh = Render.Mesh(NewMesh)
ObjectMesh.ObjectMaterial = ObjectMaterials[MaterialName] --// !: may break
Triangles = ObjectMesh.Triangles
end
end
--// Add Final Mesh
Meshes[#Meshes+1] = ObjectMesh
return Meshes
end
function Render.Mesh(Alias, PX, PY, PZ, RX, RY, RZ, SX, SY, SZ)
local self = setmetatable({
ID = 0; --// Reference of object in Workspace
Triangles = {};
Position = mlib.Vector4(PX or 0, PY or 0, PZ or 0);
Rotation = mlib.Vector4(RX or 0, RY or 0, RZ or 0);
Size = mlib.Vector4(SX or 1, SY or 1, SZ or 1);
MeshFormats = {};
ObjectMaterial = nil;
}, Mesh)
self:InsertWorkspace(Alias)
return self
end
--// Camera
local Camera = {}
Camera.__index = Camera
function Render.Camera(X, Y, Z)
local self = setmetatable({
pos = mlib.Vector3(X, Y, Z),
target = mlib.Vector3(0, 0, 1),
up = mlib.Vector3(0, 1, 0),
speed = 5
}, Camera)
return self
end
function Camera:SetPosition(X, Y, Z)
self.pos.x = X
self.pos.y = Y
self.pos.z = Z
return self
end
function Camera:RotationTransform()
local Pos, Target, Up = self.pos, self.target, self.up
local CameraTranslation = mlib.TranslationMatrix4(-Pos.x, -Pos.y, -Pos.z)
local CameraRotateTrans = mlib.CameraTransform(Target, Up)
return CameraRotateTrans * CameraTranslation
end
--// More Advanced Functions
--// Setters and Init
function Render.SetProjectionMatrix()
Render.ProjectionMatrix = mlib.ProjectionMatrix(Render.zNear, Render.zFar, Render.FOV)
end
function Render.Init(ScreenWidth, ScreenHeight)
Render.ScreenWidth = ScreenWidth or 1920
Render.ScreenHeight = ScreenHeight or 1080
LW.setMode(ScreenWidth, ScreenHeight, {fullscreen=Render.FullScreen,resizable=Render.FullScreen})
Canvas = LG.newCanvas()
DepthCanvas = LG.newCanvas(ScreenWidth, ScreenHeight, {type="2d",format="depth32f",readable=true})
LG.setMeshCullMode("back")
Render.MainCamera = Render.Camera(Render.Spawn.x, Render.Spawn.y, Render.Spawn.z)
--// Create Sun and Skybox
end
function Render.SetResolution(ScreenWidth, ScreenHeight)
Render.ScreenWidth = ScreenWidth or 1920
Render.ScreenHeight = ScreenHeight or 1080
end
--// Controls
local Panning = false
function Render.MousePressed(X, Y, Button) --// If mouse is down (not released yet)
if Button ~= Render.MousePanButton then return end
Panning = true
MouseX, MouseY = X, Y
StartPanX, StartPanY = X, Y
love.mouse.setGrabbed(true)
end
function Render.MouseReleased(X, Y, Button)
if Button ~= Render.MousePanButton then return end
Panning = false
love.mouse.setGrabbed(false)
end
function Render.UpdateMousePan(dt)
if Render.AlwaysPanning or Panning then
--love.mouse.setVisible(false)
NewMouseX, NewMouseY = love.mouse.getX(), love.mouse.getY()
local DifferenceX, DifferenceY
DifferenceX = NewMouseX - MouseX
DifferenceY = NewMouseY - MouseY
Render.CameraYaw = Render.CameraYaw - DifferenceX * dt * Render.MouseSensivity
Render.CameraPitch = lock(Render.CameraPitch - DifferenceY * dt * Render.MouseSensivity, -1.5, 1.5)
--// Reset Mouse Position
--local OriginX, OriginY = Allos.VisualWidth / 2, Allos.VisualHeight / 2
love.mouse.setPosition(Render.ScreenWidth / 2, Render.ScreenHeight / 2)
end
MouseX, MouseY = Render.ScreenWidth / 2, Render.ScreenHeight / 2
end
function Render.UpdateControls(dt)
local PlayerCamera = Render.MainCamera
local Target, Up, Speed = PlayerCamera.target, PlayerCamera.up, PlayerCamera.speed * dt
if LK.isDown('w') then PlayerCamera.pos = PlayerCamera.pos + (Target * Speed) end
if LK.isDown('s') then PlayerCamera.pos = PlayerCamera.pos - (Target * Speed) end
if LK.isDown("space") then PlayerCamera.pos = PlayerCamera.pos + Up * Speed end
if LK.isDown("lshift") or LK.isDown("rshift") then PlayerCamera.pos = PlayerCamera.pos - Up * Speed end
if LK.isDown('a') then
local Left = Up:Cross(Target) --// Flipped (Target, Up)
Left:Normalise()
PlayerCamera.pos = PlayerCamera.pos + Left * Speed
end
if LK.isDown('d') then
local Right = Target:Cross(Up) --// Flipped (Up, Target)
Right:Normalise()
PlayerCamera.pos = PlayerCamera.pos + Right * Speed
end
if LK.isDown("up") then Render.CameraPitch = lock(Render.CameraPitch - Render.TurnSpeed * dt, -1.5, 1.5) end
if LK.isDown("down") then Render.CameraPitch = lock(Render.CameraPitch + Render.TurnSpeed * dt, -1.5, 1.5) end
if LK.isDown("right") then Render.CameraYaw = Render.CameraYaw + Render.TurnSpeed * dt end
if LK.isDown("left") then Render.CameraYaw = Render.CameraYaw - Render.TurnSpeed * dt end
if LK.isDown(Render.EscapeKey) then love.event.quit(1) end
if LK.isDown(Render.RestartKey) then love.event.quit('restart') end
local CameraRotationX = mlib.XRotationMatrix4(Render.CameraPitch)
local CameraRotationY = mlib.YRotationMatrix4(Render.CameraYaw)
local CameraRotationZ = mlib.ZRotationMatrix4(Render.CameraRoll)
--// We transform our target direction normal by a rotation matrix so it's pointing in the correct direction
--// We can later add on to this with another rotation matrix to rotate up and down
local LookDirection = CameraRotationZ * (CameraRotationY * (CameraRotationX * mlib.Vector4(0, 0, 1, 1)))
--\\ We want yaw to go after pitch
PlayerCamera.target.x = LookDirection.x
PlayerCamera.target.y = LookDirection.y
PlayerCamera.target.z = LookDirection.z
end
--// Draw
function Render.RenderScene(IteratorList)
IteratorList = IteratorList or Render.Workspace
LG.setCanvas({Canvas, depthstencil=DepthCanvas, depth=true})
LG.clear()
LG.setDepthMode("lequal", true)
LG.setShader(MainShader)
local MainCamera = Render.MainCamera
for ID, Object in pairs(IteratorList) do
local WM = mlib.WorldMatrix(Object)
local WVP = Render.ProjectionMatrix * (MainCamera:RotationTransform() * WM)
MainShader:send("World", WVP)
--// Go through all lights and send data
local dir = 0
for _, Light in ipairs(LightWorkspace) do
if Light.Type == "DirectionalLight" then
Light:Calc(WM)
local T = "DirLights[" .. dir .. "]."
MainShader:send(T .. "AmbientIntensity", Light.AmbientIntensity)
MainShader:send(T .. "DiffuseIntensity", Light.DiffuseIntensity)
MainShader:send(T .. "Color", Light.Color)
MainShader:send(T .. "Direction", Light.LocalDirection:ToArray())
dir = dir + 1
end
end
local ObjectMaterial = Object.ObjectMaterial
MainShader:send("MaterialDiffuseColor", mlib.Color3ToArray4(ObjectMaterial.DiffuseColor))
MainShader:send("MaterialAmbientColor", mlib.Color3ToArray4(ObjectMaterial.AmbientColor))
MainShader:send("MaterialSpecularColor", mlib.Color3ToArray4(ObjectMaterial.SpecularColor))
MainShader:send("CameraPos", Render.MainCamera.pos:ToArray(1))
if #Object.MeshFormats == 0 and #Object.Triangles > 0 then
for i, Triangle in ipairs(Object.Triangles) do
local Vertices = {
{
Triangle[1].x, Triangle[1].y, Triangle[1].z,
Triangle[4].x, 1-Triangle[4].y,
Triangle[8].x, Triangle[8].y, Triangle[8].z,
1, 1, 1, 1
},
{
Triangle[2].x, Triangle[2].y, Triangle[2].z,
Triangle[5].x, 1-Triangle[5].y,
Triangle[9].x, Triangle[9].y, Triangle[9].z,
1, 1, 1, 1
},
{
Triangle[3].x, Triangle[3].y, Triangle[3].z,
Triangle[6].x, 1-Triangle[6].y,
Triangle[10].x, Triangle[10].y, Triangle[10].z,
1, 1, 1, 1
},
}
local MeshTriangle = LG.newMesh(MeshAttributes, Vertices, "triangles", "static")
MeshTriangle:setTexture(Triangle[7])
Object.MeshFormats[i] = MeshTriangle
end
end
for _, Triangle in ipairs(Object.MeshFormats) do
LG.draw(Triangle, Render.ScreenWidth / 2, Render.ScreenHeight / 2, 0, 100, 100)
end
end
LG.setShader()
LG.setCanvas()
end
function Render.OutputRender()
LG.setColor(1,1,1)
LG.setDepthMode()
LG.draw(Canvas, 0,0,0, 1,1)
LG.print(ArrayToString(Render.MainCamera.pos))
end
return Render
Re: How to make an interpolated Triangle w/ vertex & pixel shaders?
VertexColor is defined in the Löve base shader as a vec4. That's a 'float' data-type, not byte.
I don't know if that'll fix it, but I'd also try having the shader plug the vertex normals into the varying color, as a visual debug to see if the data is coming in right.
I don't know if that'll fix it, but I'd also try having the shader plug the vertex normals into the varying color, as a visual debug to see if the data is coming in right.
Re: How to make an interpolated Triangle w/ vertex & pixel shaders?
Good day!
Well... I took your shaders + your mesh format exactly how they were, symbol by symbol, plus made a simple example which draw only 2 triangles with them.
And it works! (aside from VertexColor, but looks like it is just not used in your shaders)
I animated light position, so it is moving circles.
And there is clearly a difference between these 2 triangles around top corner, and only around top corner, exactly where I made a difference between normals, so they do interpolate. Full code: Based on that looks like the problem is not in your shaders or mesh format.
Is it all correct with model files reading / normals calculation?:
Well... I took your shaders + your mesh format exactly how they were, symbol by symbol, plus made a simple example which draw only 2 triangles with them.
And it works! (aside from VertexColor, but looks like it is just not used in your shaders)
I animated light position, so it is moving circles.
And there is clearly a difference between these 2 triangles around top corner, and only around top corner, exactly where I made a difference between normals, so they do interpolate. Full code: Based on that looks like the problem is not in your shaders or mesh format.
Is it all correct with model files reading / normals calculation?:
- Maybe your normals look inside of the object so you have flat dark ambient color.
- Maybe your normals are not nearly perpendicular to the surface, as often assumed to be, but closer to parallel to it.
-
- Prole
- Posts: 7
- Joined: Sun Jan 22, 2023 3:42 pm
Re: How to make an interpolated Triangle w/ vertex & pixel shaders?
You're right! When I used a different .obj file, and added the movement of the light, it was getting interpolated correctly. So it's very likely that the vertex normal data isn't correct inside my other obj file. Thank you so much for the help! I will have to try to fix the obj file I guess.Sasha264 wrote: ↑Sat Jan 28, 2023 6:05 am Good day!
Well... I took your shaders + your mesh format exactly how they were, symbol by symbol, plus made a simple example which draw only 2 triangles with them.
And it works! (aside from VertexColor, but looks like it is just not used in your shaders)
I animated light position, so it is moving circles.
And there is clearly a difference between these 2 triangles around top corner, and only around top corner, exactly where I made a difference between normals, so they do interpolate.
result.png
Full code:
LoveNormals.love
Based on that looks like the problem is not in your shaders or mesh format.
Is it all correct with model files reading / normals calculation?:
- Maybe your normals look inside of the object so you have flat dark ambient color.
- Maybe your normals are not nearly perpendicular to the surface, as often assumed to be, but closer to parallel to it.
Who is online
Users browsing this forum: Ahrefs [Bot] and 3 guests