Skip to content

Instantly share code, notes, and snippets.

@lhog
Last active April 15, 2021 23:13
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 lhog/69502d488969906a763f93d9cf9c96b3 to your computer and use it in GitHub Desktop.
Save lhog/69502d488969906a763f93d9cf9c96b3 to your computer and use it in GitHub Desktop.
function widget:GetInfo()
return {
name = "Map Grass GL4",
version = "v0.001",
desc = "Instanced rendering of garbagegrass",
author = "Beherith",
date = "2021.04.12",
license = "CC-BY-NC-ND 4.0",
layer = -1000000000000,
enabled = true,
}
end
--------------------------------------------------------------------------------
-- Todo:
-- a func that collects all map grass patches into VBO
-- a way to draw a textured quad
-- blade texture
-- normals texture?
-- a nice grass patch VBO
-- pos
-- uv
-- normal
-- bitangent
-- tangent
-- a vao drawing func preunit
-- sample $grass for color in VS
-- sample a noise texture in VS
-- sway grass with wind
--
--------------------------------------------------------------------------------
local patchresolution = 24
local patchsizemult = 1.0
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
local spGetGroundHeight = Spring.GetGroundHeight
local spGetGrass = Spring.GetGrass
local floor = math.floor
local mapSizeX, mapSizeZ = Game.mapSizeX, Game.mapSizeZ
---------------------------VAO VBO stuff:---------------------------------------
local grassPatchVBO = nil
local grassInstanceVBO = nil
local grassInstanceVBOSize = nil
local grassVAO = nil
local grassShader = nil
local grassPatchCount = 0
local luaShaderDir = "LuaUI/Widgets/Include/"
local LuaShader = VFS.Include(luaShaderDir.."LuaShader.lua")
local grassBladeColorTex = "LuaUI/Images/luagrass/grass_field_medit_flowering.dds.cached.dds" -- rgb + alpha transp
local grassBladeNormalTex = "LuaUI/Images/luagrass/grass_field_medit_flowering.dds.cached.dds" -- xyz + specular factor
local mapGrassColorModTex = "$grass"
local grassWindPerturbTex = "bitmaps/Lups/perlin_noise.jpg" -- rgba of various frequencies of perlin noise?
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
local function UpdateShader()
grassShader:ActivateWith(function()
grassShader:SetUniformAlways("shaderParams", gridSize, brightness, (curvature and 1.0) or 0.0, (fogEffect and 1.0) or 0.0)
end)
end
local function goodbye(reason)
Spring.Echo("Map Grass GL4 widget exiting with reason: "..reason)
if grassPatchVBO then grassPatchVBO = nil end
if grassInstanceVBO then grassInstanceVBO = nil end
if grassVAO then grassVAO = nil end
if grassShader then grassShader:Finalize() end
widgetHandler:RemoveWidget(self)
end
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- using: http://ogldev.atspace.co.uk/www/tutorial33/tutorial33.html
local function makeGrassPatchVBO() -- this needs to be much better
grassPatchVBO = gl.GetVBO(GL.ARRAY_BUFFER,true)
if grassPatchVBO == nil then goodbye("No LuaVAO support") end
local VBOLayout= { {id = 0, name = "position", size = 3},
{id = 1, name = "normal", size = 3},
{id = 2, name = "stangent", size = 3},
{id = 3, name = "ttangent", size = 3},
{id = 4, name = "texcoords0", size = 2},
{id = 5, name = "texcoords1", size = 2},
{id = 6, name = "pieceindex", size = 1},} --khm, this should be unsigned int
local VBOData = { 19.9253,-0.3833,-5.5756,0,1.0000,0,0,0,0,0,0,0,0.9984,0.0028,0,0,0,
-15.0340,-0.3833,14.6081,0,1.0000,0,0,0,0,0,0,0,0.0019,0.0028,0,0,0,
-11.7273,16.8366,20.3354,0,1.0000,0,0,0,0,0,0,0,0.0019,0.9976,0,0,0,
-11.7273,16.8366,20.3354,0,1.0000,0,0,0,0,0,0,0,0.0019,0.9976,0,0,0,
23.2319,16.8365,0.1517,0,1.0000,0,0,0,0,0,0,0,0.9984,0.9976,0,0,0,
19.9253,-0.3833,-5.5756,0,1.0000,0,0,0,0,0,0,0,0.9984,0.0028,0,0,0,
-14.8705,-0.3833,14.8913,0,1.0000,0,0,0,0,0,0,0,0.9984,0.0028,0,0,0,
20.0888,-0.3833,-5.2924,0,1.0000,0,0,0,0,0,0,0,0.0019,0.0028,0,0,0,
16.7821,16.8365,-11.0198,0,1.0000,0,0,0,0,0,0,0,0.0019,0.9976,0,0,0,
16.7821,16.8365,-11.0198,0,1.0000,0,0,0,0,0,0,0,0.0019,0.9976,0,0,0,
-18.1772,16.8365,9.1640,0,1.0000,0,0,0,0,0,0,0,0.9984,0.9976,0,0,0,
-14.8705,-0.3833,14.8913,0,1.0000,0,0,0,0,0,0,0,0.9984,0.0028,0,0,0,
19.8347,-0.3833,4.6970,0,1.0000,0,0,0,0,0,0,0,0.9984,0.0028,0,0,0,
-15.1245,-0.3833,-15.4867,0,1.0000,0,0,0,0,0,0,0,0.0019,0.0028,0,0,0,
-18.4312,16.8366,-9.7594,0,1.0000,0,0,0,0,0,0,0,0.0019,0.9976,0,0,0,
-18.4312,16.8366,-9.7594,0,1.0000,0,0,0,0,0,0,0,0.0019,0.9976,0,0,0,
16.5280,16.8365,10.4243,0,1.0000,0,0,0,0,0,0,0,0.9984,0.9976,0,0,0,
19.8347,-0.3833,4.6970,0,1.0000,0,0,0,0,0,0,0,0.9984,0.0028,0,0,0,
-15.2880,-0.3833,-15.2036,0,1.0000,0,0,0,0,0,0,0,0.9984,0.0028,0,0,0,
19.6712,-0.3833,4.9802,0,1.0000,0,0,0,0,0,0,0,0.0019,0.0028,0,0,0,
22.9779,16.8365,-0.7471,0,1.0000,0,0,0,0,0,0,0,0.0019,0.9976,0,0,0,
22.9779,16.8365,-0.7471,0,1.0000,0,0,0,0,0,0,0,0.0019,0.9976,0,0,0,
-11.9814,16.8365,-20.9309,0,1.0000,0,0,0,0,0,0,0,0.9984,0.9976,0,0,0,
-15.2880,-0.3833,-15.2036,0,1.0000,0,0,0,0,0,0,0,0.9984,0.0028,0,0,0,
-6.1704,-0.3833,20.5802,0,1.0000,0,0,0,0,0,0,0,0.9984,0.0028,0,0,0,
-6.1704,-0.3833,-19.7872,0,1.0000,0,0,0,0,0,0,0,0.0019,0.0028,0,0,0,
-12.7837,16.8366,-19.7872,0,1.0000,0,0,0,0,0,0,0,0.0019,0.9976,0,0,0,
-12.7837,16.8366,-19.7872,0,1.0000,0,0,0,0,0,0,0,0.0019,0.9976,0,0,0,
-12.7837,16.8365,20.5802,0,1.0000,0,0,0,0,0,0,0,0.9984,0.9976,0,0,0,
-6.1704,-0.3833,20.5802,0,1.0000,0,0,0,0,0,0,0,0.9984,0.0028,0,0,0,
-6.4974,-0.3833,-19.7872,0,1.0000,0,0,0,0,0,0,0,0.9984,0.0028,0,0,0,
-6.4974,-0.3833,20.5802,0,1.0000,0,0,0,0,0,0,0,0.0019,0.0028,0,0,0,
0.1159,16.8365,20.5802,0,1.0000,0,0,0,0,0,0,0,0.0019,0.9976,0,0,0,
0.1159,16.8365,20.5802,0,1.0000,0,0,0,0,0,0,0,0.0019,0.9976,0,0,0,
0.1159,16.8365,-19.7872,0,1.0000,0,0,0,0,0,0,0,0.9984,0.9976,0,0,0,
-6.4974,-0.3833,-19.7872,0,1.0000,0,0,0,0,0,0,0,0.9984,0.0028,0,0,0,
}
local numVerts = 36
grassPatchVBO:Define(
numVerts, -- 3 verts, just a triangle for now
VBOLayout -- 17 floats per vertex
)
grassPatchVBO:Upload(VBOData)
end
local function makeGrassInstanceVBO()
grassInstanceVBO = gl.GetVBO(GL.ARRAY_BUFFER,true)
if grassInstanceVBO == nil then goodbye("No LuaVAO support") end
grassInstanceData= {}
for x = patchresolution / 2, Game.mapSizeX, patchresolution do
for z = patchresolution / 2, Game.mapSizeZ, patchresolution do
if spGetGrass(x,z) == 1 or true then -- TESTING BY GRASS EVERYWHERE
local lx = x + (math.random() -0.5) * patchresolution/2
local lz = z + (math.random() -0.5) * patchresolution/2
local gx, gy, gz, gs = Spring.GetGroundNormal (lx,lz )
local gh = spGetGroundHeight(lx,lz)
if gh > 55 and gy > 0.98 then
grassPatchCount = grassPatchCount + 1
grassInstanceData[#grassInstanceData+1] = lx
grassInstanceData[#grassInstanceData+1] = gh
grassInstanceData[#grassInstanceData+1] = lz
grassInstanceData[#grassInstanceData+1] = (1.0 + math.random()) * patchsizemult -- size
--Spring.Echo(x,gh,z)
grassInstanceData[#grassInstanceData+1] = math.random()
grassInstanceData[#grassInstanceData+1] = math.random()*6
grassInstanceData[#grassInstanceData+1] = math.random()
grassInstanceData[#grassInstanceData+1] = math.random() --
end
end
end
end
Spring.Echo("Drawing ",#grassInstanceData/8,"grass patches")
grassInstanceVBO:Define(
#grassInstanceData/8,--?we dont know how big yet!
{
{id = 7, name = 'instancepos', size = 4}, -- a vec4 for pos + random rotation
{id = 8, name = 'instancerot', size = 4}, -- a vec4 for pos + random rotation
}
)
grassInstanceVBO:Upload(grassInstanceData)
end
local vsSrc = [[
#version 420
#line 10065
layout (location = 0) in vec3 vertexPos;
layout (location = 1) in vec3 vertexNormal;
layout (location = 2) in vec3 stangent;
layout (location = 3) in vec3 ttangent;
layout (location = 4) in vec2 texcoords0;
layout (location = 5) in vec2 texcoords1;
layout (location = 6) in float pieceindex;
layout (location = 7) in vec4 instancePos; //x, y, z, size
layout (location = 8) in vec4 instanceRot; //x, y, z, rot
uniform vec4 grassShaderParams; // grass X offset, grass wind Y offset, grass wind speed
uniform sampler2D grassBladeColorTex;
uniform sampler2D grassBladeNormalTex;
uniform sampler2D mapGrassColorModTex;
uniform sampler2D grassWindPerturbTex;
out DataVS {
vec3 worldPos;
vec3 Normal;
vec2 texCoord0;
vec3 Tangent;
vec3 Bitangent;
vec4 mapColor;
vec4 grassNoise;
vec4 instanceParamsVS;
};
layout(std140, binding = 0) uniform UniformMatrixBuffer {
mat4 screenView;
mat4 screenProj;
mat4 screenViewProj;
mat4 cameraView;
mat4 cameraProj;
mat4 cameraViewProj;
mat4 cameraBillboardProj;
mat4 cameraViewInv;
mat4 cameraProjInv;
mat4 cameraViewProjInv;
// the rest are not useful now
};
layout(std140, binding = 1) uniform UniformParamsBuffer {
vec3 rndVec3; //new every draw frame.
uint renderCaps; //various render booleans
vec4 timeInfo; //gameFrame, gameSeconds, drawFrame, frameTimeOffset
vec4 viewGeometry; //vsx, vsy, vpx, vpy
vec4 mapSize; //xz, xzPO2
vec4 fogColor; //fog color
vec4 fogParams; //fog {start, end, 0.0, scale}
vec4 pad[6];
vec4 windInfo;
};
// glsl rotate convencience funcs: https://github.com/dmnsgn/glsl-rotate
mat4 rotation3dY(float a) {
float s = sin(a);
float c = cos(a);
return mat4(
c, 0.0, -s, 0.0,
0.0, 1.0, 0.0, 0.0,
s, 0.0, c, 0.0,
0.0, 0.0, 0.0, 1.0
);
}
mat4 scaleMat(vec3 s) {
return mat4(
s.x, 0.0, 0.0, 0.0,
0.0, s.y, 0.0, 0.0,
0.0, 0.0, s.z, 0.0,
0.0, 0.0, 0.0, 1.0
);
}
mat4 translationMat(vec3 t) {
return mat4(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
t.x, t.y, t.z, 1.0
);
}
#line 10275
#define windSampleScale 0.001
void main() {
mat4 R = rotation3dY(instanceRot.y);
mat4 S = scaleMat(instancePos.www);
mat4 T = translationMat(instancePos.xyz);
mat4 worldMat = T * R * S;
mat4 invWorldMat = transpose(worldMat);
vec4 myVertexPos = vec4(vertexPos, 1.0);
myVertexPos.xyz += mat3(invWorldMat) * normalize(windInfo.xyz) * sqrt(max(vertexPos.y, 0.0)) * smoothstep(-3.0, 20.0, windInfo.w) * 3.0;
vec4 grassVertWorldPos = worldMat * myVertexPos;
//grassVertWorldPos.xyz += instancePos.xyz; // rotate Y and move to world pos
mapColor = texture(mapGrassColorModTex, vec2(grassVertWorldPos.x / mapSize.x, grassVertWorldPos.z / mapSize.z)); // sample minimap
grassNoise = texture(grassWindPerturbTex, vec2((grassVertWorldPos.xz + vec2(timeInfo.y*10)) * windSampleScale)); // sample windnoise
grassNoise = (grassNoise - 0.5 );
//vec4 worldpos = vec4(myVertexPos.xyz + instanceparams.xyz, 1.0); what is this?
grassVertWorldPos.xyz = grassVertWorldPos.xyz + grassNoise.rgb * myVertexPos.y * instancePos.w; // add temp ez-wind for now
// ------------ dump the stuff for FS --------------------
texCoord0 = texcoords0;
Normal = mat3(R) * vertexNormal;
Tangent = mat3(R) * ttangent;
mat4 mat = cameraView;
//mat[0].xyz = vec3(1, 0, 0);
//mat[1].xyz = vec3(0, 1, 0);
//mat[2].xyz = vec3(0, 0, 1);
gl_Position = cameraProj * mat * grassVertWorldPos;
}
]]
local fsSrc = [[
#version 330
#extension GL_ARB_uniform_buffer_object : require
#extension GL_ARB_shading_language_420pack: require
uniform vec4 grassShaderParams; // grass X offset, grass wind Y offset, grass wind speed
uniform sampler2D grassBladeColorTex;
uniform sampler2D grassBladeNormalTex;
uniform sampler2D mapGrassColorModTex;
uniform sampler2D grassWindPerturbTex;
in DataVS {
vec3 worldPos;
vec3 Normal;
vec2 texCoord0;
vec3 Tangent;
vec3 Bitangent;
vec4 mapColor;
vec4 grassNoise;
vec4 instanceParamsVS;
};
layout(std140, binding = 0) uniform UniformMatrixBuffer {
mat4 screenView;
mat4 screenProj;
mat4 screenViewProj;
mat4 cameraView;
mat4 cameraProj;
mat4 cameraViewProj;
mat4 cameraBillboardProj;
mat4 cameraViewInv;
mat4 cameraProjInv;
mat4 cameraViewProjInv;
// the rest are not useful now
};
layout(std140, binding = 1) uniform UniformParamsBuffer {
vec3 rndVec3; //new every draw frame.
uint renderCaps; //various render booleans
vec4 timeInfo; //gameFrame, gameSeconds, drawFrame, frameTimeOffset
vec4 viewGeometry; //vsx, vsy, vpx, vpy
vec4 mapSize; //xz, xzPO2
vec4 fogColor; //fog color
vec4 fogParams; //fog {start, end, 0.0, scale}
vec4 pad[6];
vec4 windInfo;
};
out vec4 fragColor;
void main() {
fragColor = texture(grassBladeColorTex, texCoord0);
fragColor.rgb = mix(fragColor.rgb,mapColor.rgb,1.0-texCoord0.y); //more mappy color at bottom of grass
fragColor.rgb = fragColor.rgb * clamp(texCoord0.y+0.5,0.5,1.0); // darken the bottom of it
fragColor.a = clamp((fragColor.a - 0.5) * 1.0 + 0.5,0.0,1.0); // harden alpha
//fragColor.rgb = mix(fogColor.rgb, fragColor.rgb, alphaFog.y);
//ragColor.a = alphaFog.x;
//fragColor = vec4(1.0, 1.0, 1.0, 1.0);
//fragColor = vec4(mapColor.rgb*texCoord0.x,1.0);
if (fragColor.a < 0.3)
discard;
}
]]
local function makeShaderVAO()
grassVAO = gl.GetVAO()
if grassVAO == nil then goodbye("Failed to create grassVAO") end
grassShader = LuaShader(
{
vertex = vsSrc,
fragment = fsSrc,
--geometry = gsSrc, no geom shader for now
uniformInt = {
grassBladeColorTex = 0,-- rgb + alpha transp
grassBladeNormalTex = 1,-- xyz + specular factor
mapGrassColorModTex = 2, -- minimap
grassWindPerturbTex = 3, -- perlin
},
uniformFloat = {
grassUniforms = {1,1,1,1},
},
},
"GrassShaderGL4"
)
shaderCompiled = grassShader:Initialize()
if not shaderCompiled then goodbye("Failed to compile grassShader GL4 ") end
grassVAO:AttachVertexBuffer(grassPatchVBO)
grassVAO:AttachInstanceBuffer(grassInstanceVBO)
end
function widget:Initialize()
WG['grassgl4'] = {}
WG['grassgl4'].getBrightness = function()
return brightness
end
WG['grassgl4'].setBrightness = function(value)
brightness = value
end
WG['grassgl4'].getCurvature = function()
return curvature
end
WG['grassgl4'].setCurvature = function(value)
curvature = value
end
makeGrassPatchVBO()
makeGrassInstanceVBO()
makeShaderVAO()
end
-- depth defaults:
--[[
false
false
GL_DEPTH_FUNC = GL_ALWAYS
]]--
-- blending defaults:
--[[
true
GL_SRC_ALPHA
GL_ONE_MINUS_SRC_ALPHA
]]--
-- culling defaults
--[[
false
GL_CULL_FACE_MODE = GL_BACK
]]--
function widget:DrawWorldPreUnit()
gl.DepthTest(GL.LEQUAL)
--gl.DepthTest(false)
--gl.AlphaToCoverage(true)
gl.DepthMask(true)
gl.Culling(GL.BACK) -- needs better front and back instead of using this
gl.Texture(0, grassBladeColorTex)
gl.Texture(1, "$grass")
gl.Texture(2, "$grass")
gl.Texture(3, grassWindPerturbTex)
grassShader:Activate()
--Spring.Echo(grassPatchCount)
grassVAO:DrawArrays(GL.TRIANGLES, 36, 0, grassPatchCount)
grassShader:Deactivate()
gl.Texture(0, false)
gl.Texture(1, false)
gl.Texture(2, false)
gl.Texture(3, false)
gl.DepthTest(GL.ALWAYS)
gl.DepthMask(false)
gl.AlphaToCoverage(false)
gl.Culling(GL.BACK)
end
function widget:GetConfigData(data)
return {
brightness = brightness,
curvature = curvature,
fogEffect = fogEffect
}
end
function widget:SetConfigData(data)
if data.brightness ~= nil then
brightness = data.brightness
end
if data.curvature ~= nil then
curvature = data.curvature
end
if data.fogEffect ~= nil then
fogEffect = data.fogEffect
end
end
-- ahahahah you cant stop me:
--[[
import sys
normals_up = True
if len(sys.argv) <2:
sys.argv.append("tovbo.obj")
objdata = {'vn' : [], 'vt' : [], 'v' : []}
numverts = 0
outfile = open(sys.argv[1]+'.lua','w')
outfile.write("""local VBOLayout= { {id = 0, name = "position", size = 3},
{id = 1, name = "normal", size = 3},
{id = 2, name = "stangent", size = 3},
{id = 3, name = "ttangent", size = 3},
{id = 4, name = "texcoords0", size = 2},
{id = 5, name = "texcoords1", size = 2},
{id = 6, name = "pieceindex", size = 1},} --khm, this should be unsigned int
local VBOData = { """)
def listoffloats_to_line(lof):
return '\t' + ','.join("0" if f == 0 else '%.4f'%f for f in lof) + ',\n'
for objline in open(sys.argv[1]).readlines():
objitems = objline.strip().split()
if objitems[0] in objdata:
objdata[objitems[0] ].append(list(map(float,objitems[1:])))
if objitems[0] == 'f':
for objitem in objitems[1:4]:
vi, vti, vni = tuple(map(int,objitem.split('/')))
if normals_up:
vn = [0,1,0]
else:
vn = objdata['vn'][vni-1]
outfile.write(listoffloats_to_line(objdata['v'][vi-1] + vn + [0,0,0] + [0,0,0] + objdata['vt'][vti-1][0:2] + [0,0] + [0]))
numverts += 1
outfile.write('\n}\nlocal numVerts = %d\n'%numverts)
outfile.close()
]]--
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment