Modularize flower generation

glasz

Active Member
Contributor
Art
Name: flower generator
Summary: a prototype experimenting with flower generation.
Scope: Mod (extra content)
Current Goal: Procedural creation of flowers, meant as a practical experimentation with the idea of procedural content.
Phase: Design
Curator: glasz
Related:
 

glasz

Active Member
Contributor
Art
Here's what i have in mind : i will try to lay out some ideas through a prototype. For this prototype i will demonstrate these ideas with the generation of a classic 16x16 flower sprite, but it should of course work with higher resolutions or even a uvmaped 3d model, and could work with other world elements beyond just flowers.

So, at world creation, a number of original flowers are to be created, then instanciated throughout the world.

Creation of a flower implies :
+Name generation. I will not cover this since it seems quite simple
+Flower properties : flower is associated with a number of effects or principles, at various levels. I will not cover this either.
+Flower appearance : thats what'll cover.

The flower appearance will be created by combining a patern with 3 different colors, that are picked at flower creation.

What i call a pattern is a 16x16 texture with alpha. alpha is to be used the usual way.

Beyond alpha, the pixels RVB values in the sprite should belong within four color range :
+Rcolor : a pixel whose V and B values are set to zero, and R value ranges from 1 to 255
+Vcolor : a pixel whose R and B values are set to zero, and V value ranges from 1 to 255
+Bcolor : a pixel whose V and R values are set to zero, and B value ranges from 1 to 255
+GREYcolor : RVB values are all the same, and range from 1 to 255

Those colors are not to be used as is, but are meant to be processed by a simple color swapping shader. GREYcolor should remain as is, while Rcolor, Vcolor, Bcolor are replaced, by the shader, with the three RVB colors that have been chosen for the flower at its creation. The original value of the relevant channel (the one that is not zero but range from 1 to 255) will be used to modulate that final RVB color, in a way that i have yet to define :D

Those colors can be completely random, but the result as a good chance to be esthetically unpleasing. Thats why i recommand the use of color palettes. A color palette could be chosen for everything in the world at world creation (at least everything vegetal), making everything esthetically consistent. Plus it offers the possibility for the player to chose the theme/color palette he prefers, and even create his/her own palette. A game like Proteus makes a great use of a nice color palette.

I hope this make sense. I will try to make some kind of prototype demonstrating these ideas, so as to make things a little clearer.
 

glasz

Active Member
Contributor
Art
I finally got some results (shaders are evil)

Here is the palette and the 3 flower sprites i made :



Here is the python code :

Code:
from pandac.PandaModules import loadPrcFileData
loadPrcFileData("", "win-size 1280 768")
 
 
import direct.directbase.DirectStart
from pandac.PandaModules import *
from direct.showbase.DirectObject import DirectObject
from direct.showbase.ShowBase import ShowBase
import sys, random, math
 
from panda3d.core import *
 
class FlowerData():
    def __init__(self):
        self.palette = PNMImage("tex/palette01.png")
        self.sprites = []
       
        model = loader.loadModel("spriteflower01")
        tex01 =  loader.loadTexture('tex/flower01.png')
        tex01.setMagfilter(Texture.FTNearest)
        tex01.setMinfilter(Texture.FTNearest)
        stagetex01 = TextureStage("tex01")
        model.setTexture(stagetex01, tex01)
        self.sprites.append(model)
 
 
        model = loader.loadModel("spriteflower01")
        tex02 =  loader.loadTexture('tex/flower02.png')
        tex02.setMagfilter(Texture.FTNearest)
        tex02.setMinfilter(Texture.FTNearest)
        stagetex02 = TextureStage("tex02")
        model.setTexture(stagetex02, tex02)
        self.sprites.append(model)
 
 
        model = loader.loadModel("spriteflower01")
        tex03 =  loader.loadTexture('tex/flower03.png')
        tex03.setMagfilter(Texture.FTNearest)
        tex03.setMinfilter(Texture.FTNearest)
        stagetex03 = TextureStage("tex0")
        model.setTexture(stagetex03, tex03)
        self.sprites.append(model)
       
       
 
    def pickSprite(self):
        random.seed()
        n = random.randint(0,2)
 
        print n
        return self.sprites[n]
       
    def pickColor(self):
       
        x = random.randint(0,7)
        y = random.randint(0,7)
 
        Rcol = self.palette.getXelA(x,y)
        Rcol =  Vec4(Rcol[0],Rcol[1], Rcol[2],Rcol[3])
       
        return Rcol
 
class FlowerType():
    def __init__(self,flowerdata):
        self.rcolor = flowerdata.pickColor()
        self.gcolor = flowerdata.pickColor()
        self.bcolor = flowerdata.pickColor()
        self.sprite = flowerdata.pickSprite().copyTo(render)
       
        self.sprite.setShaderInput("rcol", Vec4(self.rcolor))
        self.sprite.setShaderInput("gcol", Vec4(self.gcolor))
        self.sprite.setShaderInput("bcol", Vec4(self.bcolor))
       
        myshader = Shader.load("colorshader.sha", Shader.SLCg)
        self.sprite.setShader(myshader)
       
 
 
 
fd = FlowerData()
 
 
ft = []
for i in range(8):
    for j in range(8):
        f = FlowerType(fd)
        f.sprite.setX(i*4)
        f.sprite.setY(j*4)
        ft.append(f)
       
 
ambientLight = AmbientLight("ambientLight")
ambientLight.setColor(Vec4(1, 1, 1, 1))
render.setLight(render.attachNewNode(ambientLight))
 
run()
Here is the shader :

Code:
//Cg
/* lesson2.sha */
 
void vshader(
    uniform float4x4 mat_modelproj,
    in float4 vtx_position : POSITION,
    out float4 l_position : POSITION,
    float2 vtx_texcoord0 : TEXCOORD0,
    out float2 l_textcoord : TEXCOORD0)
{
    l_position = mul(mat_modelproj, vtx_position);
    l_textcoord = vtx_texcoord0;
};
 
void fshader( float2 l_texcoord0 : TEXCOORD0,
                uniform sampler2D tex_0,
                uniform float4 rcol,
                uniform float4 gcol,
                uniform float4 bcol,
                out float4 o_color : COLOR)
{
    float4 color = tex2D(tex_0, l_texcoord0);
    if (color.a == 0)
              // alpha value less than user-specified threshold?
            {
              discard; // yes: discard this fragment
            }
    else
    {if (color.g ==0 & color.b ==0 & color.r >0){
      float r = rcol.r*color.r;
        float g = rcol.g*color.r;
        float b = rcol.b*color.r;
        o_color = float4(r,g,b,1);
            }
                    else if (color.r ==0 & color.b ==0 & color.g >0){
      float r = gcol.r*color.g;
        float g = gcol.g*color.g;
        float b = gcol.b*color.g;
        o_color = float4(r,g,b,1);
            }
        else if (color.g ==0 & color.r ==0 & color.b >0){
      float r = bcol.r*color.b;
        float g = bcol.g*color.b;
        float b = bcol.b*color.b;
        o_color = float4(r,g,b,1);
            }
    else{
    o_color = color;}
    }
}
and the result :

 

eleazzaar

Member
Contributor
Art
If you want a real variety in appearance, you need to assemble the base sprite from components.
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
If you want a real variety in appearance, you need to assemble the base sprite from components.
Hey eleazzaar ! Been ages, glad to see you again :)

I can't wait to see this in-game :D

Seems like pretty good variety as is, although you can spot some "types" (which could probably be put to actual use). I'm figuring the 16x16 limits us a bit too. Unless we can expand into either multi-block plants or higher res? Either way this has great potential
 

Immortius

Lead Software Architect
Contributor
Architecture
GUI
I would suggest that it may look better if the colors were a bit more directed - particularly more pastels for the flowers, and less shades of green.
 

eleazzaar

Member
Contributor
Art
A bit of explanation on that abrupt comment...

I whipped up some examples that, if i understand correctly, follow your color scheme. The idea is each type of flower would be assembled from several graphic -- no more than one from each row. To make a non-flowering plant skip the top row. Using all three rows there are 64 different combinations-- and that's before you start the pallet swapping. If your different layers are skillfully made it would create a huge amount of apparent variety.




Hey eleazzaar ! Been ages, glad to see you again :)
Howdy!

I don't seem to have the energy to work on these group projects much anymore, but i'm still keeping an eye on you guys via twitter. Pure art is more relaxing, and i've got a pretty good minecraft texture pack going here. But this thing caught my attention, so i put in my 2 cents.
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
I get it with the plant sprites, good example :)

Nice MC texture pack! You know, we've got hires support for Terasology now if you feel like doing some 2D art ... :3

Heck, we need to replace the base GMC! textures sometime, since we couldn't make consistent contact with the fellow. Oh if only we could run into some other fellow with a nice texture pack who was already active here ... :scootangel:
 

glasz

Active Member
Contributor
Art
Immortius : yup, this prototype was just meant to demonstrate the tech, i made this palette quickly and without much care. The important thing is the possibility to use many different palettes. If anyone wants to provide their carefully composed palette i'll use it :)

eleazzaar : thanks for the sprites and suggestion, i'll try to make a new prototype using your textures.
 

glasz

Active Member
Contributor
Art
So, here is a prototype using eleazzaar sprites combination. The palette is certainly a bit to psychedelic :D and the sprites probably need to be done differently so as to make the different flowers more distinct, but on the principle it works.



The python code :
Code:
from pandac.PandaModules import loadPrcFileData
loadPrcFileData("", "win-size 1280 768")


import direct.directbase.DirectStart
from pandac.PandaModules import *
from direct.showbase.DirectObject import DirectObject
from direct.showbase.ShowBase import ShowBase
import sys, random, math

from panda3d.core import *

class FlowerData():
    def __init__(self):
        self.palette = PNMImage("tex/palette01.png")
        self.sprites = []      
        self.model = loader.loadModel("spriteflower01")
      
#        tex01 =  loader.loadTexture('tex/flower01.png')
#        self.sprites.append(tex01)
#        tex02 =  loader.loadTexture('tex/flower02.png')
#        self.sprites.append(tex02)
#        tex03 =  loader.loadTexture('tex/flower03.png')
#        self.sprites.append(tex03)
        self.sprites.append(loader.loadTexture("tex/flbase01.png"))
        self.sprites.append(loader.loadTexture("tex/flbase02.png"))
        self.sprites.append(loader.loadTexture("tex/flbase03.png"))
        self.sprites.append(loader.loadTexture("tex/flbase04.png"))
        self.sprites.append(loader.loadTexture("tex/flmid01.png"))
        self.sprites.append(loader.loadTexture("tex/flmid02.png"))
        self.sprites.append(loader.loadTexture("tex/flmid03.png"))
        self.sprites.append(loader.loadTexture("tex/flmid04.png"))
        self.sprites.append(loader.loadTexture("tex/fltop01.png"))
        self.sprites.append(loader.loadTexture("tex/fltop02.png"))
        self.sprites.append(loader.loadTexture("tex/fltop03.png"))
        self.sprites.append(loader.loadTexture("tex/fltop04.png"))



      
      

    def pickSprite(self):
        random.seed()
        np = NodePath()
        model = self.model.copyTo(np)

        n = random.randint(0,3)
        tex = self.sprites[n]
        tex.setMagfilter(Texture.FTNearest)
        tex.setMinfilter(Texture.FTNearest)
        stagetex = TextureStage("tex")
        stagetex.setSort(0)
        stagetex.setMode(TextureStage.MDecal)

        model.setTexture(stagetex, tex)
      
        n = random.randint(4,7)
        tex2 = self.sprites[n]
        tex2.setMagfilter(Texture.FTNearest)
        tex2.setMinfilter(Texture.FTNearest)
        stagetex2 = TextureStage("tex2")
        stagetex2.setSort(1)
        stagetex2.setMode(TextureStage.MDecal)

        model.setTexture(stagetex2, tex2)
      
        n = random.randint(8,11)
        tex3 = self.sprites[n]
        tex3.setMagfilter(Texture.FTNearest)
        tex3.setMinfilter(Texture.FTNearest)
        stagetex3 = TextureStage("tex3")
        stagetex3.setSort(2)
        stagetex3.setMode(TextureStage.MDecal)

        model.setTexture(stagetex3, tex3)


        return model
      
    def pickColor(self):
      
        x = random.randint(0,7)
        y = random.randint(0,7)

        Rcol = self.palette.getXelA(x,y)
        Rcol =  Vec4(Rcol[0],Rcol[1], Rcol[2],Rcol[3])
      
        return Rcol

class FlowerType():
    def __init__(self,flowerdata):
        self.rcolor = flowerdata.pickColor()
        self.gcolor = flowerdata.pickColor()
        self.bcolor = flowerdata.pickColor()
#        self.sprite = flowerdata.pickSprite().copyTo(render)
        self.sprite = flowerdata.pickSprite()
        self.sprite.reparentTo(render)

      
        self.sprite.setShaderInput("rcol", Vec4(self.rcolor))
        self.sprite.setShaderInput("gcol", Vec4(self.gcolor))
        self.sprite.setShaderInput("bcol", Vec4(self.bcolor))
      
        myshader = Shader.load("colorshader.sha", Shader.SLCg)
        self.sprite.setShader(myshader)
      



fd = FlowerData()


ft = []
for i in range(8):
    for j in range(8):
        f = FlowerType(fd)
        f.sprite.setX(i*4)
        f.sprite.setY(j*4)
        ft.append(f)
      
base.setBackgroundColor(0, 0, 0, 1)

ambientLight = AmbientLight("ambientLight")
ambientLight.setColor(Vec4(1, 1, 1, 1))
render.setLight(render.attachNewNode(ambientLight))

run()
The shader :

Code:
//Cg
/* lesson2.sha */

void vshader(
    uniform float4x4 mat_modelproj,
    in float4 vtx_position : POSITION,
    out float4 l_position : POSITION,
    float2 vtx_texcoord0 : TEXCOORD0,
    out float2 l_textcoord : TEXCOORD0)
{
    l_position = mul(mat_modelproj, vtx_position);
    l_textcoord = vtx_texcoord0;
};

void fshader( float2 l_texcoord0 : TEXCOORD0,
                uniform sampler2D tex_0,
                uniform sampler2D tex_3,
                uniform sampler2D tex_2,
                uniform float4 rcol,
                uniform float4 gcol,
                uniform float4 bcol,
                out float4 o_color : COLOR)
{
    float4 color1= tex2D(tex_0, l_texcoord0);
    float4 color2 = tex2D(tex_2, l_texcoord0);
    float4 color3 = tex2D(tex_3, l_texcoord0);
    float4 color ;
    if (color1.a == 0 & color2.a==0 & color3.a ==0)
              // alpha value less than user-specified threshold?
            {
              discard; // yes: discard this fragment
            }
    else
    {
    if(color1.a >0){color=color1;};
    if (color2.a >0){color=color2;};
      if (color3.a >0){color=color3;};
//color = color3;
  
    if (color.g ==0 & color.b ==0 & color.r >0){
      float r = rcol.r*color.r;
        float g = rcol.g*color.r;
        float b = rcol.b*color.r;
        o_color = float4(r,g,b,1);
            }
                    else if (color.r ==0 & color.b ==0 & color.g >0){
      float r = gcol.r*color.g;
        float g = gcol.g*color.g;
        float b = gcol.b*color.g;
        o_color = float4(r,g,b,1);
            }
        else if (color.g ==0 & color.r ==0 & color.b >0){
      float r = bcol.r*color.b;
        float g = bcol.g*color.b;
        float b = bcol.b*color.b;
        o_color = float4(r,g,b,1);
            }
    else{
    o_color = color;}
    }
}
 
Last edited:

eleazzaar

Member
Contributor
Art
So, here is a prototype using eleazzaar sprites combination. The palette is certainly a bit to psychedelic :D and the sprites probably need to be done differently so as to make the different flowers more distinct, but on the principle it works.
Cool, i think i'll give the making of some decent graphics for this a shot.

One thing i noticed is some of the flowers picked the same color all three times. It would be good if at least the color for the "green" parts was chosen from a different pallet than the other parts.
 

glasz

Active Member
Contributor
Art
eleazzaar
Yup, i used the same 3 colors for the 3 sprites, but this can be tweaked of course. And yes there is the possibility to use a different palette for each base color, that would make sense.

[edit]
and also next iteration i will add the generation of plants with only one or two of the levels.
 

eleazzaar

Member
Contributor
Art
Did you end up using Grey? That could be useful for woody parts of plants. The palettes would mostly translate it to browns, tans, and grays.
 

glasz

Active Member
Contributor
Art
No i didnt use grey. My original idea was to not change the grey color at all, so as to have "pure" black and white at least (allways usefull). Buut yeah there is the possibility to use it as a fourth color, as you suggest.
 

Immortius

Lead Software Architect
Contributor
Architecture
GUI
I guess if you wanted to be organized, you could use the R channel as the greyscale mask for vibrant flower color, the G channel as the greyscale mask for stem/leaves and the B channel as a greyscale mask for a pastel flower color. Leaves the A channel for alpha masking. Decent image editors let you work with each channel individually, or at least break up and recombine them.
 

glasz

Active Member
Contributor
Art
Immortius : yes we could organize things like that. In any case a little more thinking into the color use is required :) I'll try to make other palettes when i have some time, but if somebody else is willing to do it, they're welcome.

Note : we'll also have to figure out a sprite system that encompasses the different stages of the plant growth.
 

eleazzaar

Member
Contributor
Art
No i didnt use grey. My original idea was to not change the grey color at all, so as to have "pure" black and white at least (allways usefull). Buut yeah there is the possibility to use it as a fourth color, as you suggest.
I don't think i would want to use pure B&W on a plant, but you could always make an exception for pure B&W, and use the rest of the greyscale for a fourth color.
 

glasz

Active Member
Contributor
Art
I don't think i would want to use pure B&W on a plant, but you could always make an exception for pure B&W, and use the rest of the greyscale for a fourth color.​
I agree, but my idea was to test that system on plants, and then to extend it possibly to a whole world, this way we could have sort of "themed" worlds. Next thing on my list is to try some kind of animal generator, wich will use the same kind of palette system, and for animals B&W will be usefull. As for the number of colors, we could of course have four color and more, but the more color we use the more chances we end up with something ugly i think. My idea is : enough colors to offer a wide range of possible combination, but no too many, so as to avoid as much as possible obvious color discordances.​
 

eleazzaar

Member
Contributor
Art
Here's some non-junky pieces to test with. Obviously i don't have blossoms yet. The lower row (base layer) is designed to go in front of the mid layer.

Can i talk you into adding a 4th layer that's linked to the blossom layer?

In the first graphics i gave you some of the blossoms were "floating" and some had stems drawn that connect them to the ground. I don't especially like either solution-- blossoms that levitate, or stems that get drawn on top of everything.

The use of the 4th layer would be to drawn the stems for the blossoms-- and that layer would be put behind all the others so that the blossoms would be connected to the ground, but the blossom's stems wouldn't obscure the interesting details of the base and mid layers.
 

Attachments

Top