Last active
April 15, 2021 23:13
-
-
Save lhog/69502d488969906a763f93d9cf9c96b3 to your computer and use it in GitHub Desktop.
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
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