I am working on a drawing application in OpenGL and would like to simulate a pencil brush similar to what applications like Krita and Procreate use. However, I'm facing challenges with getting the texture right. I'm currently drawing a square texture at each point using both a pencil texture and a noise texture. Both of these textures are grayscale.
Here is a snippet of my code:
// [Code snippet]
for (td in touchDataManager.get()) {
val startTime = System.nanoTime()
brush.color = color
brush.updateBrush(td)
val endTime = System.nanoTime()
val newTime = (endTime - startTime) / 1000000f
timeProfilerHelper.add(newTime)
square.draw(
brushMVPMatrix,
textureId,
noiseTextureId,
floatArrayOf(
brush.color[0],
brush.color[1],
brush.color[2],
min(brush.color[3] * td.normalizedSize, 1f).also {
})
)
index++
}
The square.draw function is responsible for rendering the brush stroke using the specified textures and parameters.
Here's the relevant part of the draw function:
// [Code snippet]
fun draw(mvpMatrix: FloatArray?, textureId: Int, noiseTextureId : Int , squareColor: FloatArray) {
// [Code to set up OpenGL program and uniforms]
// ...
GLES30.glDrawArrays(GLES30.GL_TRIANGLE_FAN, 0, 4)
GLES30.glDisableVertexAttribArray(positionHandle)
GLES30.glDisableVertexAttribArray(texCoordHandle)
}
Additionally, here is the fragment shader:
// [Fragment shader code]
precision mediump float;
uniform sampler2D uTexture;
uniform sampler2D uNoiseTexture;
varying vec2 vTexCoord;
uniform vec4 vColor;
uniform vec2 noiseTextureSize;
uniform float noiseScale;
uniform vec2 noiseOffset;
void main() {
// [Shader code]
// ...
}
I'm looking to implement a pencil brush effect similar to what you find in drawing applications. However, the results are not as expected, and I'm struggling with achieving a realistic pencil texture.
Possible Solution:
I have considered using stencil buffers but I'm not sure if that's the right approach. Another idea I've had is to draw a hidden noise texture and use the brush texture as a stencil or mask to reveal the noise texture behind it. However, I'm uncertain about how to proceed and would appreciate guidance on implementing the pencil brush effect in OpenGL.
I would like to know the drawing techniques and shader adjustments that can help me achieve a more realistic pencil texture similar to what's seen in professional drawing applications like Krita and Procreate. Any insights, code samples, or suggestions would be greatly appreciated. Thank you!
Yes you can use stencil buffer to get what you want. Here is simple implementation of stencil buffer. It is C++ but you will get the Idea.
#include <GL/glew.h>
#include <GLFW/glfw3.h>
void renderScene() {
// Enable the stencil test
glEnable(GL_STENCIL_TEST);
// Clear the stencil buffer to zero at the beginning of each frame
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
// Set the stencil test function to always pass and update the stencil buffer
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
// Render the areas where you want the pencil brush effect
// Bind your pencil brush texture and render a quad or other shapes here
// Disable writing to the stencil buffer and set the stencil test function to only render where the stencil buffer is not zero
glStencilFunc(GL_NOTEQUAL, 0, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
// Render the scene (background, objects, etc.) as you normally would
// Disable the stencil test
glDisable(GL_STENCIL_TEST);
// Swap buffers and update the screen
glfwSwapBuffers(window);
}
int main() {
// Initialize GLFW and create a window
if (!glfwInit()) {
return -1;
}
// Set up your OpenGL context and window here
// Load your pencil brush texture
while (!glfwWindowShouldClose(window)) {
// Process user input and update the scene
// Render the scene with the pencil brush effect
renderScene();
// Poll for and process events
glfwPollEvents();
}
// Cleanup and exit
glfwTerminate();
return 0;
}