whiterabbit Posted August 30, 2014 Share Posted August 30, 2014 I'm using the default grayscale posteffect shader to make everything black and white, but this doesn't affect anything drawn during Script:PostRender(context) (eg, red text is still red). Is it possible to make a shader apply after drawing takes place? Or any solution easier than manually changing the colour/textures of GUI elements - ideally more advanced shaders could also be used. This script shows my problem. You can put this script on any entity and link it to a camera, you will see everything is greyscale except the text 'Always red'. Script.Camera = nil --entity "Camera" Script.Enabled = true --bool "Enabled" function Script:Start() self.WasEnabled = -1 end function Script:_Enable() self.Camera:AddPostEffect("Shaders/PostEffects/grayscale.shader") end function Script:_Disable() self.Camera:ClearPostEffects() end function Script:UpdateWorld() if self.Enabled~=self.WasEnabled then if self.Enabled then self:_Enable() else self._Disable() end end self.WasEnabled = self.Enabled end function Script:PostRender(context) context:SetBlendMode(Blend.Solid) context:SetColor(1,0,0,1) context:DrawText("Always red", 5, 5) end EDIT: Right after posting this I found context:SetShader, it sounds like what I want. And the forum ruined my code indentation Quote Link to comment Share on other sites More sharing options...
whiterabbit Posted August 30, 2014 Author Share Posted August 30, 2014 I'm trying to use context:SetShader before drawing my GUI but it requires a different kind of shader I guess, if I use the same grayscale shader then the whole context becomes invisible (transparent?). I'm really inexperienced with shaders and have only really copy and paste-editted them up to this point. I've tried modifying some of the default 'Drawing' shaders but haven't been able to get anything that just modifies the colour of what I draw to the context - I always end up with either a solid block of color, an unrelated image over the top, or nothing. The default grayscale shader is easy to enough to understand, I just don't know why it won't work when used for context:SetShader Quote Link to comment Share on other sites More sharing options...
macklebee Posted August 31, 2014 Share Posted August 31, 2014 The easiest way to use the 'grayscale.shader' is to just apply it to the Root of your scene via the World' Post Effects. Then just make sure the camera is setup to allow post effects either via code (if its created via code) or by selecting the 'Use Post-Effects' option in the camera properties (if its an entity in the scene browser). Either way, a post effect only effects what is rendered, whereas 2D drawing commands are applied after the rendering. Like you showed you can set the color of the 2D draw commands via 'context:SetColor()'. EDIT--If you really have your heart set on applying a grayscale to your text and images via the 2D draw commands instead of just setting the color or using grayed images, then just modify the drawtext and drawimage shaders like this: drawtext.shader's fragment main loop: void main(void) { vec4 color = drawcolor; color.a *= texture(texture0,ex_texcoords0).a; float l = color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722; fragData0 = vec4(l, l, l, color.a); } drawimage.shader's fragment main loop: void main(void) { vec4 color = drawcolor * texture(texture0,vTexCoords0); float l = color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722; fragData0 = vec4(l, l, l, color.a); } Quote Win7 64bit / Intel i7-2600 CPU @ 3.9 GHz / 16 GB DDR3 / NVIDIA GeForce GTX 590 LE / 3DWS / BMX / Hexagon macklebee's channel Link to comment Share on other sites More sharing options...
whiterabbit Posted August 31, 2014 Author Share Posted August 31, 2014 Ok thanks, that's easy enough. But is it not possible to do it with just one shader applied with context:SetShader before drawing all my GUI? I'm hoping to have it be able to switch on and off. I could do it by editting both those shaders as you've said and adding a uniform value to toggle it on and off but from what I've read it's not a good idea to do boolean things like that in shader code? EDIT: For now I've gone ahead and done that - editted them and added a uniform value that will be 1 or 0 for whether greyscale is active, then used mix() to get the output. //in drawimage.shader //added a uniform uniform int GrayscaleActive; //changed main loop void main(void) { vec4 color = drawcolor * texture(texture0,vTexCoords0); float l = color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722; vec4 lumCol = vec4(l,l,l,color.a); fragData0 = mix(color,lumCol,GrayscaleActive); } Quote Link to comment Share on other sites More sharing options...
macklebee Posted August 31, 2014 Share Posted August 31, 2014 Ok thanks, that's easy enough. But is it not possible to do it with just one shader applied with context:SetShader before drawing all my GUI? Well yes that can be done by just rendering/drawing the scene/2D items to another buffer, apply the shader, and then draw the results to the default context buffer. Then to turn off/on you could set a toggle to not enable the shader in your code. Then you wouldn't have to edit shaders. It really depends on what you are comfortable with - shaders and buffer manipulation can be confusing for people just starting out. function App:Start() self.window = Window:Create() self.context = Context:Create(self.window) self.buffer = Buffer:GetCurrent() self.myworld = World:Create() self.mybuffer = Buffer:Create(self.context:GetWidth(), self.context:GetHeight(),1,1) self.myshader = Shader:Load("Shaders/PostEffects/grayscale.shader") Map:Load("Maps/start.map") self.toggle = 0 return true end function App:Loop() if self.window:Closed() or self.window:KeyHit(Key.Escape) then return false end Time:Update() self.myworld:Update() self.mybuffer:Enable() self.myworld:Render() self.context:SetBlendMode(Blend.Alpha) self.context:SetColor(1,0,0,1) self.context:DrawText("FPS: "..Time:UPS(), 0, 20) self.context:SetColor(1,1,1,1) self.context:SetBlendMode(Blend.Solid) self.buffer:Enable() if self.window:KeyHit(Key.Up) then self.toggle = 1 - self.toggle end if self.toggle==1 then self.myshader:Enable() else self.myshader:Disable() end self.mybuffer:GetColorTexture():Bind(1) self.context:DrawImage(self.mybuffer:GetColorTexture(),0,0,self.context:GetWidth(),self.context:GetHeight()) self.myshader:Disable() self.context:Sync() return true end Keep in mind this code assumes that your scene has a camera in it either as an scene entity or created via an entity script like in the fpsplayer script. Quote Win7 64bit / Intel i7-2600 CPU @ 3.9 GHz / 16 GB DDR3 / NVIDIA GeForce GTX 590 LE / 3DWS / BMX / Hexagon macklebee's channel Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.